1 /****************************************************************************
2 Copyright (C) 1987-2015 by Jeffery P. Hansen
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 Last edit by hansen on Sun Feb 12 17:01:30 2006
19 ****************************************************************************/
20 /*
21 Functions in this module are used to make joints. Joints are created
22 when a wire end is dropped near the middle of another wire.
23 */
24 #include <stdio.h>
25 #include "tkgate.h"
26
27 #define parallel(_n1,_n2) ((((_n1)->x == (_n1)->out->x) && ((_n2)->x == (_n2)->out->x)) \
28 || (((_n1)->y == (_n1)->out->y) && ((_n2)->y == (_n2)->out->y)))
29
join_wirenodereverse(GWireNode * n)30 void join_wirenodereverse(GWireNode *n)
31 {
32 GWireNode *t;
33
34 if (n) {
35 ob_touch(n);
36 t = n->out;
37 n->out = n->in;
38 n->in = t;
39 join_wirenodereverse(n->in);
40 }
41 }
42
43 /*
44 Reverse the link direction of a single wire.
45 */
join_wirereverse(GWire * w)46 void join_wirereverse(GWire *w)
47 {
48 struct wire *wd;
49
50 wd = wire_driver(w);
51 join_wirenodereverse(wd->nodes);
52
53 wd = wire_driver(w);
54 ob_touch(wd);
55 wd->driver = wd;
56
57 w = wire_drivee(w);
58 ob_touch(w);
59 w->driver = wd;
60 }
61
join_treereverse_aux(GWire * w)62 void join_treereverse_aux(GWire *w)
63 {
64 GWire *ow = wire_other(w); /* Get other end */
65 GCElement *g;
66 int i;
67
68 join_wirereverse(w);
69
70 if (!(g = ow->gate)) return; /* Other end was endpoint, we are all done */
71
72 switch (g->typeinfo->code) {
73 case GC_JOINT :
74 if (ow->driver == ow) { /* ow used to be drivee, need to choose new drivee */
75 for (i = 0;i < 4;i++)
76 if (g->wires[i] && g->wires[i] != ow) {
77 join_treereverse_aux(g->wires[i]);
78 break;
79 }
80 } else { /* ow now a drivee, need to undo other drivee */
81 for (i = 0;i < 4;i++)
82 if (g->wires[i] && g->wires[i] != ow && g->wires[i]->driver != g->wires[i]) {
83 join_treereverse_aux(g->wires[i]);
84 break;
85 }
86 }
87 /*
88 * This is just here as a consistancy check
89 */
90 {
91 int nd = 0,ne = 0;
92
93
94 for (i = 0;i < 4;i++) {
95 GWire *w = g->wires[i];
96
97 if (!w) continue;
98 if (w->driver == w) nd++; else ne++;
99 }
100 if (ne != 1)
101 logError(ERL_ERROR,"Expecting only a single drivee on joint.");
102 }
103 break;
104 case GC_TAP :
105 if (g->wires[TAP_IN] == ow)
106 join_treereverse_aux(g->wires[TAP_OUT]);
107 else if (g->wires[TAP_OUT] == ow)
108 join_treereverse_aux(g->wires[TAP_IN]);
109 break;
110 }
111 }
112
113 /*
114 Reverse the link direction of a tree of wires. The top-level
115 w should be a free end.
116 */
join_treereverse(GWire * w)117 void join_treereverse(GWire *w)
118 {
119 if (w->gate)
120 logError(ERL_ERROR,"Expecting free end in join_treereverse");
121 else
122 join_treereverse_aux(w);
123 }
124
125 /*
126 Splices a corner. After splice, w1 is a driver, and w2 is a drivee.
127 */
join_splice_corner(GWireNode * n,GWire * w1[],GWire * w2[],int dwidth,EditState * es)128 void join_splice_corner(GWireNode *n,GWire *w1[],GWire *w2[],int dwidth,EditState *es)
129 {
130 GWire *wd;
131 GWire *pw = wirenode_driver(n);
132
133 w1[0] = wire_newend(es->env,pw->net,0);
134 w2[0] = wire_newend(es->env,pw->net,0);
135
136 ob_touch(n);
137 ob_touch(w1[0]);
138 ob_touch(w2[0]);
139 ob_touch(w1[0]->nodes);
140
141 w1[0]->nodes = n;
142 w2[0]->nodes = new_GWireNode();
143
144 ob_touch(w2[0]->nodes);
145 w2[0]->nodes->x = n->x;
146 w2[0]->nodes->y = n->y;
147 w2[0]->nodes->in = n->in;
148
149 ob_touch(w2[0]->nodes->in);
150 w2[0]->nodes->in->out = w2[0]->nodes;
151
152 ob_touch(n);
153 n->in = NULL;
154
155 w1[0]->nodes->end = w1[0];
156 w2[0]->nodes->end = w2[0];
157
158 w1[0]->driver = wire_driver(w1[0]);
159 wd = wire_drivee(w1[0]);
160 ob_touch(wd);
161 wd->driver = w1[0]->driver;
162
163 w2[0]->driver = wire_driver(w2[0]);
164 wd = wire_drivee(w2[0]);
165 ob_touch(wd);
166 wd->driver = w2[0]->driver;
167 net_setSize(w1[0]->net,dwidth);
168 net_setSize(w2[0]->net,dwidth);
169 }
170
join_splice_middle(GWireNode * n,GWire * w1[],GWire * w2[],int x,int y,int dwidth,EditState * es)171 void join_splice_middle(GWireNode *n,GWire *w1[],GWire *w2[],int x,int y,int dwidth,EditState *es)
172 {
173 GWire *pw = wirenode_driver(n);
174
175 w1[0] = wire_newend(es->env,pw->net,1);
176 w2[0] = wire_newend(es->env,pw->net,1);
177
178 ob_touch(w1[0]);
179 ob_touch(w2[0]);
180 ob_touch(w1[0]->nodes);
181 ob_touch(w2[0]->nodes);
182
183 if ((n->x == n->out->x) && (n->y != n->out->y)) {
184 w2[0]->nodes->x = w1[0]->nodes->x = n->x;
185 w2[0]->nodes->y = w1[0]->nodes->y = y;
186 } else
187 if ((n->y == n->out->y) && (n->x != n->out->x)){
188 w2[0]->nodes->x = w1[0]->nodes->x = x;
189 w2[0]->nodes->y = w1[0]->nodes->y = n->y;
190 } else {
191 w2[0]->nodes->x = w1[0]->nodes->x = x;
192 w2[0]->nodes->y = w1[0]->nodes->y = y;
193 logError(ERL_WARN,"Bizarre attachment in join_splice_middle.");
194 }
195
196 ob_touch(n);
197 ob_touch(n->out);
198
199 w1[0]->nodes->out = n->out;
200 n->out->in = w1[0]->nodes;
201
202 w2[0]->nodes->in = n;
203 n->out = w2[0]->nodes;
204
205 w1[0]->driver = w1[0];
206 wirenode_drivee(w1[0]->nodes)->driver = w1[0];
207
208 w2[0]->driver = wirenode_driver(w2[0]->nodes);
209 net_setSize(w1[0]->net,dwidth);
210 net_setSize(w2[0]->net,dwidth);
211 }
212
213
214
join_middle_out(GWire * w,GWireNode * n,EditState * es,int size)215 void join_middle_out(GWire *w,GWireNode *n,EditState *es,int size)
216 {
217 struct wire *nw1,*nw2;
218
219 join_splice_middle(n,&nw1,&nw2,w->nodes->x,w->nodes->y,size,es);
220 join_treereverse(nw2);
221 joint_make(nw1->nodes->x,nw1->nodes->y,nw1,nw2,w,NULL,es);
222 joint_fixwires(w->gate,w,0);
223 wire_snapgate(w->gate,0);
224 #ifdef JOIN_DRAW
225 gate_draw(w->gate,0);
226 #endif
227 }
228
join_middle_in(GWire * w,GWireNode * n,EditState * es,int size)229 void join_middle_in(GWire *w,GWireNode *n,EditState *es,int size)
230 {
231 GWire *nw1,*nw2;
232
233 join_splice_middle(n,&nw1,&nw2,w->nodes->x,w->nodes->y,size,es);
234 joint_make(nw1->nodes->x,nw1->nodes->y,nw1,nw2,w,NULL,es);
235 joint_fixwires(w->gate,w,0);
236 wire_snapgate(w->gate,0);
237 #ifdef JOIN_DRAW
238 gate_draw(w->gate,0);
239 #endif
240 }
241
join_corner_out(GWire * w,GWireNode * n,EditState * es,int size)242 void join_corner_out(GWire *w,GWireNode *n,EditState *es,int size)
243 {
244 GWire *nw1,*nw2;
245
246 join_splice_corner(n,&nw1,&nw2,size,es);
247 join_treereverse(nw2);
248 joint_make(nw1->nodes->x,nw1->nodes->y,nw1,nw2,w,NULL,es);
249 joint_fixwires(w->gate,w,0);
250 wire_snapgate(w->gate,0);
251 #ifdef JOIN_DRAW
252 gate_draw(w->gate,0);
253 #endif
254 }
255
join_corner_in(GWire * w,GWireNode * n,EditState * es,int size)256 void join_corner_in(GWire *w,GWireNode *n,EditState *es,int size)
257 {
258 GWire *nw1,*nw2;
259
260 join_splice_corner(n,&nw1,&nw2,size,es);
261 joint_make(nw1->nodes->x,nw1->nodes->y,nw1,nw2,w,NULL,es);
262 joint_fixwires(w->gate,w,0);
263 wire_snapgate(w->gate,0);
264 #ifdef JOIN_DRAW
265 gate_draw(w->gate,0);
266 #endif
267 }
268
269 /*
270 * Joins a wire endpoint w (selected by soldering iron), to a point
271 * n on another wire. If the join results in a bit selector being
272 * created, the GCElement for it is returned.
273 */
join_wires(GWire * w,GWireNode * n,EditState * es)274 GCElement *join_wires(GWire *w,GWireNode *n,EditState *es)
275 {
276 GWire *splicewire;
277 GCElement *g = 0;
278
279 splicewire = wirenode_driver(n);
280 if (splicewire->net->n_nbits < w->net->n_nbits) return g;
281
282 if ((n->stype == VERTICAL)||(n->stype == HORIZONTAL)) {
283 if (!w->nodes->out) {
284 join_middle_out(w,n,es,splicewire->net->n_nbits);
285 if (splicewire->net->n_nbits != w->net->n_nbits) {
286 tap_transmute(w,es);
287 g = w->gate;
288 wire_finalizeNet(splicewire);
289 }
290 return g;
291 } else {
292 join_middle_in(w,n,es,splicewire->net->n_nbits);
293 if (splicewire->net->n_nbits != w->net->n_nbits) {
294 tap_transmute(w,es);
295 g = w->gate;
296 wire_finalizeNet(splicewire);
297 }
298 return g;
299 }
300 } else {
301 if (!n->end) {
302 if (!w->nodes->out) {
303 if (splicewire->net->n_nbits == w->net->n_nbits) {
304 join_corner_out(w,n,es,splicewire->net->n_nbits);
305 return g;
306 }
307 } else {
308 if (splicewire->net->n_nbits == w->net->n_nbits) {
309 join_corner_in(w,n,es,splicewire->net->n_nbits);
310 return g;
311 }
312 }
313 }
314 }
315 GWire_snap(w->driver);
316 return g;
317 }
318