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