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 
19 /*****************************************************************************
20  *    Functions that change the structure of a wire are defined here.  This
21  *    include routines for cutting and attaching wires.
22  *
23  *   wireorient(n,d)		Get orientation of a wire
24  *   wire_root_ok(w)		Test if this wire can be a root.
25  *   wire_choose_root(w,rw)     Choose best of two wires as root
26  *   wire_sigroot(w)		Choose best wire for root from connected tree.
27  *   setIoNet(net,g)		Mark a net as an I/O for element g
28  *   wire_findIdx(w,d)		Find the the wire with index d
29  *   wire_chooseUniqueNet(dw)	Choose a unique net for a newly merged wire.
30  *   wire_replaceNet(w,n)	Replace the net of a wire.
31  *   GWire_sizeisdisplayed(w)	Returns true if w has any segments displaying the size
32  *   wire_finalizeNet(w)	Do all finalization of a wire after it has been modified
33  *   wire_findClosest(w,x,y)	Find other wire end closest to w at (x,y)
34  *   wire_solder(n1,n2)		Connect two nodes together
35  *   wire_connect(M,w1,w2)	Connect two wires together
36  *   wire_changedriver(n,w)	Change the driver of a node to w
37  *   GWireNode_setends(n)	Set the ends of a wire.
38  *   wirenode_cutcorner(n,M)    Cut a wire at a corner.
39  *   wirenode_cutsegment(n,M)	Cut a wire in the middle of a segment.
40  *   wire_cut(x,y,n,M)		Cut the wire at node n at position (x,y)
41  *   wire_shorten(w,M,dp)	Shorten a wire after a cut
42  *   wire_nuke(w,dp,M)		Try to get rid of a wire if it is not attached to anything
43  *   wire_trash(n,M,dp)		Trash a wire
44  *   ...more...
45  *
46  *   Helping functions for primary functions above:
47  *
48  *   wire_sigroot_aux(w,rw)
49  *   wire_replaceNetAux(w,net)
50  *   wire_trashin(n,M,dp)	Trash a wire in the "in" direction.
51  *   wire_trashout(n,M,dp)	Trash a wire in the "out" direction.
52  *
53  *****************************************************************************/
54 
55 #include <stdlib.h>
56 #include <assert.h>
57 
58 #include "tkgate.h"
59 
60 #define DEBUG_CUT 0
61 
62 /** Wire snap cases */
63 typedef enum {
64   OSC_HH = 0x3,
65   OSC_VV = 0xC,
66   OSC_HV = 0x6,
67   OSC_VH = 0x9,
68   OSC_HZ = 0x1,
69   OSC_ZH = 0x2,
70   OSC_VZ = 0x4,
71   OSC_ZV = 0x8
72 } ObjectSnapCases_t;
73 
74 /*
75   Return the orientation of the segment 'd' in from end 'n'.
76   */
wireorient(GWireNode * n,int d)77 int wireorient(GWireNode *n,int d)
78 {
79   int r;		/* Direction of wire (in/out) */
80   GWireNode *on;	/* Other end of segment */
81 
82   r = (n->in != NULL);
83 
84   for (;d;d--)
85     if (r)
86       n = (n->in ? n->in : n);
87     else
88       n = (n->out ? n->out : n);
89 
90   on = (r ? (n->in ? n->in : n) : (n->out ? n->out : n));
91 
92   if (n->x == on->x) {
93     if (n->y < on->y)
94       return 3;
95     else
96       if (n->y > on->y)
97 	return 1;
98       else
99 	return -1;
100   } else
101     if (n->x < on->x)
102       return 0;
103     else
104       return 2;
105 }
106 
107 /*
108  * return non-zero if this wire is a valid root wire.
109  */
wire_root_ok(GWire * w)110 static int wire_root_ok(GWire *w)
111 {
112   if (!w->gate) return 1;
113   if (w->gate->typeinfo->code != GC_JOINT && w->gate->typeinfo->code != GC_TAP) return 1;
114   if (w->gate->typeinfo->code == GC_TAP && w == w->gate->wires[TAP_TAP]) return 1;
115 
116   return 0;
117 }
118 
119 /*
120  * Compare w and *root_w to determine which is the better
121  * root representative.  If w is better than *root_w, then
122  * *root_w is set to w.
123  */
wire_choose_root(GWire * w,GWire ** root_w)124 static void wire_choose_root(GWire *w,GWire **root_w)
125 {
126   if (!wire_root_ok(w)) return;		/* w must at least be a valid root */
127 
128   if (!*root_w) {			/* If no current root, then make w the root */
129     *root_w = w;
130     return;
131   }
132 
133   /*
134    * Ideally, the root should be a driver of a segment.  If both w and
135    * *root_w have the same driver status, then use the address to determine
136    * the representative.
137    */
138   if ((w->driver == w && (*root_w)->driver == *root_w)
139       || (w->driver != w && (*root_w)->driver != *root_w)) {
140     if (w < *root_w) *root_w = w;
141   } else if (w->driver == w && (*root_w)->driver != *root_w) {
142     *root_w = w;
143   }
144 }
145 
146 /*
147  * Recursively scan all wires in the tree starting at w and choose
148  * a representative wire. The representative wire choosen for any
149  * wire on a net is the same for all wires on the net.
150  */
wire_sigroot_aux(GWire * w,GWire ** root_w)151 static void wire_sigroot_aux(GWire *w,GWire **root_w)
152 {
153   int i;
154 
155   wire_choose_root(w,root_w);
156   if (!w->gate) return;
157 
158   switch (w->gate->typeinfo->code) {
159   case GC_JOINT :
160     for (i=0;i<4;i++)
161       if (w->gate->wires[i] && w->gate->wires[i] != w) {
162 	GWire *xw = w->gate->wires[i];
163 	wire_choose_root(xw,root_w);
164 	wire_sigroot_aux(wire_other(xw),root_w);
165       }
166     break;
167   case GC_TAP :
168     if (w->gate->wires[TAP_OUT] == w) {
169       GWire *xw = w->gate->wires[TAP_IN];
170       wire_choose_root(xw,root_w);
171       wire_sigroot_aux(wire_other(xw),root_w);
172     }
173     if (w->gate->wires[TAP_IN] == w) {
174       GWire *xw = w->gate->wires[TAP_OUT];
175       wire_choose_root(xw,root_w);
176       wire_sigroot_aux(wire_other(xw),root_w);
177     }
178     break;
179   }
180 }
181 
182 /*
183    Return the representative wire end with the signal name for w.
184    The represent wire end must not be connected to a joint or
185    the IN/OUT ports of a tap.
186 */
wire_sigroot(GWire * w)187 GWire *wire_sigroot(GWire *w)
188 {
189   GWire *root_w = 0;
190 
191   wire_sigroot_aux(w,&root_w);
192   wire_sigroot_aux(wire_other(w),&root_w);
193 
194   if (!root_w) {
195     logError(ERL_ERROR,"failed to find valid wire root.");
196     return w;
197   }
198 
199   return root_w;
200 }
201 
202 
203 /*****************************************************************************
204  *
205  * Helping function to search a net through its wire for an I/O net
206  *
207  *****************************************************************************/
GWire_findIoGate_aux(GWire * w)208 GCElement *GWire_findIoGate_aux(GWire *w)
209 {
210   int i;
211   GCElement *g = 0;
212 
213   if (!w->gate) return 0;
214 
215   /*
216    * Found an I/O gate.
217    */
218   if (w->gate->typeinfo->Flags.IsIOnet)
219     return w->gate;
220 
221   switch (w->gate->typeinfo->code) {
222   case GC_JOINT :
223     for (i=0;i<4;i++)
224       if (w->gate->wires[i] && w->gate->wires[i] != w) {
225 	GWire *xw = w->gate->wires[i];
226 	g = GWire_findIoGate_aux(wire_other(xw));
227 	if (g) return g;
228       }
229     break;
230   case GC_TAP :
231     if (w->gate->wires[TAP_OUT] == w) {
232       GWire *xw = w->gate->wires[TAP_IN];
233 
234       g = GWire_findIoGate_aux(wire_other(xw));
235       if (g) return g;
236     }
237     if (w->gate->wires[TAP_IN] == w) {
238       GWire *xw = w->gate->wires[TAP_OUT];
239 
240       g = GWire_findIoGate_aux(wire_other(xw));
241       if (g) return g;
242     }
243     break;
244   }
245 
246   return 0;
247 }
248 
249 /*****************************************************************************
250  *
251  * Search a net through its wire for an I/O net
252  *
253  *****************************************************************************/
GWire_findIoGate(GWire * w)254 GCElement *GWire_findIoGate(GWire *w)
255 {
256   GCElement *g;
257 
258   g = GWire_findIoGate_aux(w);
259   if (g) return g;
260 
261   return GWire_findIoGate_aux(wire_other(w));
262 }
263 
264 /*****************************************************************************
265  *
266  * Attempt to set the I/O gate of net.  If g is not an I/O net, then it does
267  * nothing.
268  *
269  *****************************************************************************/
setIoNet(GNet * net,GCElement * g)270 static void setIoNet(GNet *net,GCElement *g)
271 {
272   if (!g) return;
273   if (g->typeinfo->Flags.IsIOnet) {
274     ob_touch(net);
275     net->n_ionet = g;
276   }
277 }
278 
279 /*****************************************************************************
280  *
281  * Helping function to replace the net of a wire.
282  *
283  *****************************************************************************/
wire_replaceNetAux(GWire * w,GNet * net)284 static void wire_replaceNetAux(GWire *w,GNet *net)
285 {
286   GWire *sw;
287   int i;
288 
289   sw = w;
290   w = wire_drivee(w);
291   if (w == sw) {
292     join_wirereverse(w);
293     sw = wire_driver(w);
294     w  = wire_drivee(w);
295   }
296 
297   wire_setNet(sw,net);
298   if (net) setIoNet(net,sw->gate);
299   wire_setNet(w,net);
300   if (net) {
301     ob_touch(sw);
302     ob_touch(w);
303     ob_touch(net);
304     setIoNet(net,w->gate);
305     sw->nidx = net->n_wnum++;
306     w->nidx = net->n_wnum++;
307   }
308 
309 #if 0
310   if (net)
311     printf("   wire_replaceNetAux(%s) [0x%x]=%d [0x%x]=%d\n",
312 	   net->n_signame,sw,sw->nidx,w,w->nidx);
313 #endif
314 
315   if (w->gate)
316     switch (w->gate->typeinfo->code) {
317     case GC_JOINT :
318       if (net) {
319 	ob_touch(net);
320 	ob_touch(w->gate);
321 	w->gate->u.joint.gidx = net->n_gnum++;
322       }
323       for (i=0;i<4;i++)
324 	if (w->gate->wires[i] && w->gate->wires[i] != w)
325 	  wire_replaceNetAux(w->gate->wires[i],net);
326       break;
327     case GC_TAP :
328       if (w->gate->wires[TAP_TAP] == w) break;
329       if (net) {
330 	ob_touch(net);
331 	ob_touch(w->gate);
332 	w->gate->u.tap.gidx = net->n_gnum++;
333       }
334       if (w->gate->wires[TAP_IN] == w)
335 	wire_replaceNetAux(w->gate->wires[TAP_OUT],net);
336       if (w->gate->wires[TAP_OUT] == w)
337 	wire_replaceNetAux(w->gate->wires[TAP_IN],net);
338       break;
339     }
340 }
341 
wire_findIdx(GWire * w,int d)342 GWire *wire_findIdx(GWire *w,int d)
343 {
344   GWire *xw = 0;
345   int i;
346 
347   if (w->nidx == d) return w;
348   w = wire_drivee(w);
349   if (w->nidx == d) return w;
350 
351   if (w->gate)
352     switch (w->gate->typeinfo->code) {
353     case GC_JOINT :
354       for (i=0;i<4;i++)
355 	if (w->gate->wires[i] && w->gate->wires[i]->net && w->gate->wires[i] != w) {
356 	  xw = wire_findIdx(w,d);
357 	  if (xw) break;
358 	}
359       break;
360     case GC_TAP :
361       if (w->gate->wires[TAP_OUT] == w)
362 	xw = wire_findIdx(w->gate->wires[TAP_IN],d);
363       if (w->gate->wires[TAP_IN] == w)
364 	xw = wire_findIdx(w->gate->wires[TAP_OUT],d);
365       break;
366     }
367 
368   return xw;
369 }
370 
371 /*
372    Chooses a unique net for a collection of connected wires,
373    clears the 'net' field for all wires in the collection,
374    deletes all but one of the 'net's, and returns a unique
375    net.  A named net will take precidence over unnamed nets
376    in selecting a net to return.
377 */
wire_chooseUniqueNet(GWire * dw)378 GNet *wire_chooseUniqueNet(GWire *dw)
379 {
380   GNet *net = 0;
381   GWire *w;
382   int i;
383 
384   w = wire_drivee(dw);
385 
386   net = net_pickOne(dw->net,w->net,0);
387   net_incref(net);
388   wire_setNet(dw,0);
389   wire_setNet(w,0);
390 
391   if (w->gate)
392     switch (w->gate->typeinfo->code) {
393     case GC_JOINT :
394       for (i=0;i<4;i++)
395 	if (w->gate->wires[i] && w->gate->wires[i]->net)
396 	  net = net_pickOne(net,wire_chooseUniqueNet(w->gate->wires[i]),1);
397       break;
398     case GC_TAP :
399       if (w != w->gate->wires[TAP_TAP]) {
400 	if (w->gate->wires[TAP_OUT]->net)
401 	  net = net_pickOne(net,wire_chooseUniqueNet(w->gate->wires[TAP_OUT]),1);
402 	if (w->gate->wires[TAP_IN]->net)
403 	  net = net_pickOne(net,wire_chooseUniqueNet(w->gate->wires[TAP_IN]),1);
404       }
405       break;
406     }
407   return net;
408 }
409 
410 /*
411    Replace the net on all connected components of w.  The old
412    net is *not* deleted.
413 */
wire_replaceNet(GWire * w,GNet * net)414 void wire_replaceNet(GWire *w,GNet *net)
415 {
416   w = wire_sigroot(w);
417   wire_replaceNetAux(w,net);
418 }
419 
GWire_sizeisdisplayedonnode(GWire * w)420 static int GWire_sizeisdisplayedonnode(GWire *w)
421 {
422   GWireNode *n;
423 
424   w = wire_driver(w);
425 
426   for (n = w->nodes;n;n = n->out)
427     if (n->showSize)
428       return 1;
429 
430   return 0;
431 }
432 
GWire_sizeisdisplayed_aux(GWire * w,int isFirst)433 static int GWire_sizeisdisplayed_aux(GWire *w,int isFirst)
434 {
435   int i;
436 
437   w = wire_other(w);
438 
439   if (!isFirst) {
440     if (GWire_sizeisdisplayedonnode(w))
441       return 1;
442   }
443 
444   if (w->gate) {
445     switch (w->gate->typeinfo->code) {
446     case GC_JOINT :
447       for (i=0;i<4;i++)
448 	if (w->gate->wires[i] && (w->gate->wires[i] != w))
449 	  GWire_sizeisdisplayed_aux(w->gate->wires[i],0);
450       break;
451     case GC_TAP :
452       if (w == w->gate->wires[TAP_OUT])
453 	GWire_sizeisdisplayed_aux(w->gate->wires[TAP_IN],0);
454       else if (w == w->gate->wires[TAP_IN])
455 	GWire_sizeisdisplayed_aux(w->gate->wires[TAP_OUT],0);
456       break;
457     }
458   }
459   return 0;
460 }
461 
GWire_sizeisdisplayed(GWire * w)462 int GWire_sizeisdisplayed(GWire *w)
463 {
464   GWire *o_w = wire_other(w);
465 
466   if (GWire_sizeisdisplayed_aux(w,0))
467     return 1;
468   if (GWire_sizeisdisplayed_aux(o_w,1))
469     return 1;
470 
471   return 0;
472 }
473 
474 /*****************************************************************************
475  *
476  * Do final processing on a wire after it has been touched by editing functions.
477  *
478  * Parameters:
479  *      w		A wire on the net to be finalized.
480  *
481  * Choose a final net for a wire.  If there is more than one net on
482  * a collection of wires choose one and delete the others.
483  *
484  *****************************************************************************/
wire_finalizeNet(GWire * w)485 void wire_finalizeNet(GWire *w)
486 {
487   GNet *net;
488 
489 #if 0
490   printf("wire_finalizeNet(0x%x (%s))\n",w,w->net->n_signame);
491 #endif
492 
493   w = wire_sigroot(w);
494   net = wire_chooseUniqueNet(w);
495 
496   ob_touch(net);
497   net->n_finalized = 0;
498   net->n_wnum = 0;
499   net->n_gnum = 0;
500   net->n_ionet = 0;
501   wire_replaceNetAux(w,net);
502   net->n_driver = w;
503 
504   net->n_finalized = 1;
505   net_decref(net);
506 
507   /*
508    * Make sure at least one wire segment is marked to display the bit size.
509    */
510   if (!GWire_sizeisdisplayed(net->n_driver))
511     net->n_driver->nodes->showSize = 1;
512 
513   /*
514    * Make sure name is visible if necessary.
515    */
516   GNet_checkNameVisibility(net,0);
517 }
518 
519 /*****************************************************************************
520  *
521  * Find wire end closest to (x,y) on net rooted at w.
522  *
523  * Parameters:
524  *      w		Wire on which to search
525  *      x,y		Target coordinate pair
526  *
527  *****************************************************************************/
wire_findClosest(GWire * w,int x,int y)528 GWire *wire_findClosest(GWire *w,int x,int y)
529 {
530   GWire *ow = 0;
531   GWire *xw = 0;
532   GWire *bw;
533   int i;
534 
535   if (!w) return 0;
536 
537   ow = wire_other(w);
538   bw = w;
539   if (wdist(ow,x,y) < wdist(bw,x,y))
540     bw = ow;
541 
542   if (ow->gate) {
543     GCElement *g = ow->gate;
544     switch (g->typeinfo->code) {
545     case GC_JOINT :
546       for (i = 0;i < 4;i++)
547 	if (g->wires[i] != ow) {
548 	  xw = wire_findClosest(g->wires[i],x,y);
549 	  if (xw && wdist(xw,x,y) < wdist(bw,x,y))
550 	    bw = xw;
551 	}
552       break;
553     case GC_TAP :
554       if (g->wires[TAP_IN] == ow) {
555 	xw = wire_findClosest(g->wires[TAP_OUT],x,y);
556       } else if (g->wires[TAP_OUT] == ow) {
557 	xw = wire_findClosest(g->wires[TAP_IN],x,y);
558       } else
559 	xw = 0;
560       if (xw && wdist(xw,x,y) < wdist(bw,x,y))
561 	bw = xw;
562       break;
563     }
564   }
565 
566   return bw;
567 }
568 
569 
570 /*
571    Low-level routine for connecting two wire nodes n1 and n2
572 */
wire_solder(GWireNode * n1,GWireNode * n2)573 void wire_solder(GWireNode *n1,GWireNode *n2)
574 {
575   ObjectSnapCases_t t;
576 
577   ob_touch(n1);
578   ob_touch(n2);
579 
580   if (n1->out || n2->in) printf("Ack!\n");
581   t = horizontal(n1,n1->in) | (horizontal(n2,n2->out) <<1) |
582     (vertical(n1,n1->in)<<2) | (vertical(n2,n2->out)<<3);
583 
584   switch (t) {
585   case OSC_HH :
586   case OSC_VV :
587     if ((n1->x != n2->x) || (n1->y != n2->y)) { /* Couldn't move a node */
588       n1->out = n2;				  /* Don't remove bend */
589       n2->in = n1;
590       debugprint("*click* (case 1)\n");
591     } else {					  /* General case */
592       ob_touch(n1->in);
593       ob_touch(n2->out);
594 
595       n1->in->out = n2->out;
596       n2->out->in = n1->in;
597       delete_GWireNode(n1);
598       delete_GWireNode(n2);
599       debugprint("*click* (case 2)\n");
600     }
601     break;
602   case OSC_HV :
603   case OSC_VH :
604     ob_touch(n2->out);
605 
606     n1->out = n2->out;
607     n2->out->in = n1;
608     delete_GWireNode(n2);
609     debugprint("*click* (case 3)\n");
610     break;
611   case OSC_ZH :
612   case OSC_ZV :
613     if (n1->in->in) {
614       ob_touch(n1->in);
615 
616       n1->in->out = NULL;
617       debugprint("*subclick* (case 4)\n");
618       wire_solder(n1->in,n2);
619       delete_GWireNode(n1);
620     } else {
621       ob_touch(n2->out);
622 
623       n1->out = n2->out;
624       n2->out->in = n1;
625       delete_GWireNode(n2);
626       logError(ERL_ERROR,"Out of wire case 4 in wire_solder.");
627     }
628     break;
629   case OSC_HZ :
630   case OSC_VZ :
631     if (n2->out->out) {
632       ob_touch(n2->out);
633 
634       n2->out->in = NULL;
635       debugprint("*subclick* (case 5)\n");
636       wire_solder(n1,n2->out);
637       delete_GWireNode(n2);
638     } else {
639       ob_touch(n2->out);
640 
641       n1->out = n2->out;
642       n2->out->in = n1;
643       logError(ERL_ERROR,"Out of wire case 5 in wire_solder.");
644     }
645     break;
646   default :
647     n1->out = n2;
648     n2->in = n1;
649     logError(ERL_FATAL,"Weird connection in wire_solder.");
650   }
651 }
652 
653 /*
654    Connects two wires into a single wire.
655 */
wire_connect(GModuleDef * M,GWire * w1,GWire * w2)656 GWire *wire_connect(GModuleDef *M,GWire *w1,GWire *w2)
657 {
658   GWire *nw;
659   /** @TODO to remove */
660   GWireNode *n1/*,*n2*/;
661 
662   if (w1->net->n_nbits != w2->net->n_nbits) return 0;
663 
664   if (w1->nodes->out)
665     join_treereverse(w1);
666   if (w2->nodes->in)
667     join_treereverse(w2);
668 
669   n1 = w1->nodes;
670   /** @TODO to remove */
671   /*n2 = w2->nodes;*/
672 
673   ob_touch(w1->nodes);
674   ob_touch(w2->nodes);
675 
676   w1->nodes->stype = FULL;
677   w2->nodes->stype = FULL;
678 
679   if (!anchoredp(n1->in)) {
680     wire_move(w1->nodes,w2->nodes->x - w1->nodes->x,
681 	      w2->nodes->y - w1->nodes->y,w1->nodes->stype);
682   } else {
683       wire_move(w2->nodes,w1->nodes->x - w2->nodes->x,
684 		w1->nodes->y - w2->nodes->y,w2->nodes->stype);
685   }
686   w1->nodes->end = NULL;
687   w2->nodes->end = NULL;
688 
689   nw = wire_drivee(w2);
690   ob_touch(nw);
691   nw->driver = wire_driver(w1);
692   nw = nw->driver;
693 
694   wire_solder(w1->nodes,w2->nodes);
695 
696   wire_finalizeNet(nw);
697 
698   ob_touch(M);
699   M->m_wires = wire_unlink(M->m_wires,w1);
700   M->m_wires = wire_unlink(M->m_wires,w2);
701 
702   wire_free(w1);
703   wire_free(w2);
704 
705   return nw->driver;
706 }
707 
708 
709 /*****************************************************************************
710  *
711  * Changes the driver of a node
712  *
713  * Parameters:
714  *      n		Node of wire on which to make change
715  *      w		New driving wire
716  *
717  *****************************************************************************/
wire_changedriver(GWireNode * n,GWire * w)718 void wire_changedriver(GWireNode *n,GWire *w)
719 {
720   if (n == NULL) return;
721 
722   if (n->end) {
723     ob_touch(n->end);
724     n->end->driver = w;
725   } else
726     wire_changedriver(n->out,w);
727 }
728 
GWireNode_freeOut(GWireNode * n)729 void GWireNode_freeOut(GWireNode *n)
730 {
731   if (!n) return;
732   GWireNode_freeOut(n->out);
733   delete_GWireNode(n);
734 }
735 
GWireNode_setends(GWireNode * n)736 void GWireNode_setends(GWireNode *n)
737 {
738   GWire *w;
739 
740   w = wirenode_drivee(n);
741   ob_touch(w);
742   w->driver = wirenode_driver(n);
743   ob_touch(w->driver);
744   w->driver->driver = w->driver;
745 
746   w->wtype = DRIVEE;
747   w->driver->wtype = DRIVER;
748 }
749 
GWire_pickRenameWire(GWire * w1,GWire * w2,GModuleDef * M)750 void GWire_pickRenameWire(GWire *w1,GWire *w2,GModuleDef *M)
751 {
752   GNet *net = new_GNet_compatable(0,w1->net,M);
753   GCElement *g1 = GWire_findIoGate(w1);
754   GCElement *g2 = GWire_findIoGate(w2);
755 
756   if (g1 && !g2)
757     wire_replaceNet(w2,net);
758   else
759     wire_replaceNet(w1,net);
760 }
761 
762 
763 /*
764    Called when the wire clippers are used to cut a wire on a corner.
765 */
wirenode_cutcorner(GWireNode * n,GModuleDef * M)766 GWireNode *wirenode_cutcorner(GWireNode *n,GModuleDef *M)
767 {
768   GWireNode *cn;
769   GWire *w = wirenode_driver(n);
770 
771   cn = new_GWireNode();
772   ob_touch(cn);
773   cn->in = n->in;
774   ob_touch(cn->in);
775   cn->in->out = cn;
776   cn->out = NULL;
777   ob_touch(n);
778   n->in = NULL;
779 
780   cn->end = wire_newend(M,w->net,0);
781   ob_touch(cn->end);
782   cn->end->nodes = cn;
783 
784   n->end = wire_newend(M,w->net,0);
785   ob_touch(n->end);
786   n->end->nodes = n;
787 
788   cn->x = n->x;
789   cn->y = n->y;
790 
791   GWireNode_setends(n);
792   GWireNode_setends(cn);
793 
794   /*
795    * Decide which net to rename.
796    */
797   GWire_pickRenameWire(n->end,cn->end,M);
798 
799   return cn;
800 }
801 
802 
wirenode_cutsegment(int x,int y,GWireNode * n,GModuleDef * M)803 GWireNode *wirenode_cutsegment(int x,int y,GWireNode *n,GModuleDef *M)
804 {
805   GWireNode *cn1,*cn2;
806   GWire *w = wirenode_driver(n);
807 
808   cn1 = new_GWireNode();
809   cn2 = new_GWireNode();
810 
811   ob_touch(cn1);
812   ob_touch(cn2);
813   if (n->x == n->out->x) {
814     cn1->x = cn2->x = n->x;
815     cn1->y = cn2->y = y;
816   } else {
817     cn1->x = cn2->x = x;
818     cn1->y = cn2->y = n->y;
819   }
820 
821   cn1->in = n;
822   cn2->out = n->out;
823   n->out = cn1;
824   ob_touch(cn2->out);
825   cn2->out->in = cn2;
826 
827   cn1->end = wire_newend(M,w->net,0);
828   cn2->end = wire_newend(M,w->net,0);
829 
830   ob_touch(cn1->end);
831   ob_touch(cn2->end);
832 
833   cn1->end->nodes = cn1;
834   cn2->end->nodes = cn2;
835   GWireNode_setends(cn1);
836   GWireNode_setends(cn2);
837 
838   /*
839    * Decide which side to rename.
840    */
841 
842   GWire_pickRenameWire(cn1->end,cn2->end,M);
843 
844   return cn2;
845 }
846 
847 /** @TODO check */
848 /*
849 static int verify_addr(void *p)
850 {
851   return (p) != (void*)0xa7a7a7a7;
852 }
853 
854 static void verify_nodes(const char *place,GWireNode *n)
855 {
856   if (!verify_addr(n->in)) {
857     printf("%s: bad wire node in\n",place);
858     return;
859   }
860   if (!verify_addr(n->out)) {
861     printf("%s: bad wire node in\n",place);
862     return;
863   }
864   if (n->out)
865     verify_nodes(place,n->out);
866 }
867 
868 static void verify_wires(const char *place,GWire *w)
869 {
870   if (!verify_addr(w->net)) {
871     printf("%s: bad wire net\n",place);
872     return;
873   }
874   verify_nodes(place,w->nodes);
875   if (w->next)
876     verify_wires(place,w->next);
877 }
878 
879 static void verify_net(const char *place,GNet *n)
880 {
881   if (!verify_addr(n->n_signame)) {
882     printf("%s: bad net\n",place);
883     return;
884   }
885   verify_wires(place, n->n_driver);
886 }
887 */
888 /*****************************************************************************
889  *
890  * Cut wire near node an at (x,y).
891  *
892  * Parameters:
893  *      x,y          Position at which cut is requested
894  *      n            Wire node at which to cut
895  *      M            Module that wire is in.
896  *
897  * NOTE: Assumes that the node has been marked with the type of cut that is
898  * to take place using wire_hit, wire_iohit, etc.  The type of cut is stored
899  * in the "stype" field of the node and can be  FULL (for a cut at a corner),
900  * HORIZONTAL for a cut on a horizontal segment, or VERTICAL for a cut on a
901  * vertical segment.
902  *
903  *****************************************************************************/
wire_cut(int x,int y,GWireNode * n,GModuleDef * M)904 void wire_cut(int x,int y,GWireNode *n,GModuleDef *M)
905 {
906   GWireNode *cn;
907   GWire *w,*nw;
908   int nbits;
909   GNet *na = 0, *nb = 0;
910 
911   w = wirenode_driver(n);
912   nbits = w->net->n_nbits;
913 
914   switch (n->stype) {
915   case FULL :
916     if (n->in && n->out) {
917       GNet_draw(w->net);
918 
919       cn = wirenode_cutcorner(n,M);
920 
921       na = wirenode_driver(n)->net;
922       nb = wirenode_driver(cn)->net;
923       net_incref(na);
924       net_incref(nb);
925 
926       if (!wire_shorten(n->end,M,0)) {
927 	nw = wirenode_drivee(n);
928 	net_setSize(nw->net,nbits);
929 	nw = wirenode_driver(n);
930 	net_setSize(nw->net,nbits);
931 	wire_finalizeNet(nw);
932       }
933 
934       if (!wire_shorten(cn->end,M,0)) {
935 	nw = wirenode_driver(cn);
936 	net_setSize(nw->net,nbits);
937 	wire_finalizeNet(nw);
938       }
939     } else
940       if (n->end->gate && (n->end->gate->typeinfo->code == GC_BLOCK)) {
941 	GCElement *g = n->end->gate;
942 	if (block_isIntfProtected(g)) {
943 	  message(0,msgLookup("err.protintf"),g->u.block.moduleName);
944 	  return;
945 	}
946 
947 	SetModified(MF_INTERFACE);
948 
949 	GNet_draw(w->net);
950 	na = w->net;
951 	net_incref(na);
952 	w = n->end;
953 	block_deletewire(w);
954 	wire_nuke(w,0,M);
955       }
956     break;
957   case VERTICAL :
958   case HORIZONTAL :
959     {
960       GWire *w1,*w2;
961 
962       GNet_draw(w->net);
963 
964       cn = wirenode_cutsegment(x,y,n,M);
965 
966       na = wirenode_driver(n)->net;
967       nb = wirenode_driver(cn)->net;
968       net_incref(na);
969       net_incref(nb);
970       //    printf("(3) na-sig=%p\n",na->n_signame);
971 
972 
973 #if DEBUG_CUT
974       printf("@5(n=%s): %d\n",n->out->end->net->n_signame,n->out->end->net->n_refs);
975       printf("@5(cn=%s): %d\n",cn->end->net->n_signame,cn->end->net->n_refs);
976 #endif
977       w1 = n->out->end;
978       if (!wire_shorten(w1,M,0)) {
979 #if 0
980 	nw = wirenode_drivee(n);
981 	net_setSize(nw->net,nbits);
982 	nw = wirenode_driver(n);
983 	net_setSize(nw->net,nbits);
984 	wire_finalizeNet(nw);
985 #else
986 	net_setSize(w1->net,nbits);
987 	wire_finalizeNet(w1);
988 #endif
989       } else {
990 #if DEBUG_CUT
991 	printf("ACK 1\n");
992 #endif
993       }
994 
995       w2 = cn->end;
996       if (!wire_shorten(w2,M,0)) {
997 	cn = w2->nodes;
998 	nw = wirenode_driver(cn);
999 	net_setSize(nw->net,nbits);
1000 	wire_finalizeNet(nw);
1001       } else {
1002 #if DEBUG_CUT
1003 	printf("ACK 2\n");
1004 #endif
1005       }
1006     }
1007     break;
1008   default :
1009     fprintf(stderr, "Unallowed cut type %d", (int)n->stype);
1010   }
1011 
1012   /*
1013    * We create temp. references to these nets so we don't delete them until
1014    * we have a chance to check the reference count.  If there is only 1
1015    * reference, then that is just the temp. reference and the net will be
1016    * deleted as soon as we decrement the ref. count
1017    */
1018   if (na && na->n_refs > 1) GNet_draw(na);
1019   if (nb && nb->n_refs > 1) GNet_draw(nb);
1020   if (na) net_decref(na);
1021   if (nb) net_decref(nb);
1022 }
1023 
1024 /*
1025  * Shortens a newly cut wire, totally deletes the wire if it is no longer
1026  * connected to anything other than a joint. Returns '1' if the wire was
1027  * deleted, '0' if the wire was retained.
1028  */
wire_shorten(GWire * w,GModuleDef * M,int drawp)1029 int wire_shorten(GWire *w,GModuleDef *M,int drawp)
1030 {
1031   GWireNode *n,*on;	/* node and "other" node on segment in question */
1032 
1033   if (drawp) GWire_draw(w->driver);
1034   if (wire_nuke(w,drawp,M)) {
1035     //    printf("ws: nuke1\n");
1036     return 1;
1037   }
1038 
1039   n = w->nodes;
1040   on = (n->in ? n->in : n->out);
1041 
1042   if ((abs(n->y - on->y) < 10) && (abs(n->x - on->x) < 10)) {
1043     if (on->in && on->out) {
1044       ob_touch(on);
1045       on->end = n->end;
1046       ob_touch(on->end);
1047       on->end->nodes = on;
1048       if (on->out == n)
1049 	on->out = NULL;
1050       else
1051 	on->in = NULL;
1052       //      printf("ws: del\n");
1053       delete_GWireNode(n);
1054     }
1055   } else {
1056     ob_touch(n);
1057     if (n->x == on->x) {
1058       n->y += 5*(n->y < on->y) - 5*(n->y > on->y);	/* Zero if n->y == on->y */
1059     }
1060     else {
1061       n->x += 5*(n->x < on->x) - 5*(n->x > on->x);
1062     }
1063   }
1064   //  printf("ws: ok\n");
1065   return 0;
1066 }
1067 
wire_trashin(GWireNode * n,GModuleDef * M,int drawp)1068 static int wire_trashin(GWireNode *n,GModuleDef *M,int drawp)
1069 {
1070   int trashp;
1071 
1072   if (!n) return 0;
1073 
1074   if (!n->in) {
1075     if (n->end && n->end->gate) {
1076       switch (n->end->gate->typeinfo->code) {
1077       case GC_JOINT :
1078 	return joint_dejoint(n,M,drawp);
1079       default :
1080 	return 0;
1081       }
1082     } else {
1083       if (M) {
1084 	ob_touch(M);
1085 	M->m_wires = wire_unlink(M->m_wires,n->end);
1086       }
1087       wire_free(n->end);
1088       delete_GWireNode(n);
1089       return 1;
1090     }
1091   } else {
1092     if ((trashp = wire_trashin(n->in,M,drawp)))
1093       delete_GWireNode(n);
1094     return trashp;
1095   };
1096 }
1097 
wire_trashout(GWireNode * n,GModuleDef * M,int drawp)1098 static int wire_trashout(GWireNode *n,GModuleDef *M,int drawp)
1099 {
1100   int trashp;
1101 
1102   if (!n) return 0;
1103 
1104   if (!n->out) {
1105     if (n->end && n->end->gate) {
1106       switch (n->end->gate->typeinfo->code) {
1107       case GC_JOINT :
1108 	return joint_dejoint(n,M,drawp);
1109       default :
1110 	return 0;
1111       }
1112     } else {
1113       if (M) {
1114 	ob_touch(M);
1115 	M->m_wires = wire_unlink(M->m_wires,n->end);
1116       }
1117       wire_free(n->end);
1118       delete_GWireNode(n);
1119       return 1;
1120     }
1121   } else {
1122     if ((trashp = wire_trashout(n->out,M,drawp)))
1123       delete_GWireNode(n);
1124     return trashp;
1125   }
1126 }
1127 
wire_trash(GWireNode * n,GModuleDef * M,int draw)1128 static int wire_trash(GWireNode *n,GModuleDef *M,int draw)
1129 {
1130   if (n->in)
1131     return wire_trashin(n,M,draw);
1132   else
1133     return wire_trashout(n,M,draw);
1134 }
1135 
1136 /*
1137  * Nukes a wire if it is not attached to anything.  Returns 1 if the wire
1138  * was nuked, 0 otherwise.
1139  */
wire_nuke(GWire * w,int draw,GModuleDef * M)1140 int wire_nuke(GWire *w,int draw,GModuleDef *M)
1141 {
1142   /** @TODO to remove */
1143   /*
1144   GWire *ow;
1145   GWireNode *freeNodes = 0;
1146   */
1147 
1148   if (wire_trash(w->nodes,M,draw)) {
1149     ob_touch(M);
1150     M->m_wires = wire_unlink(M->m_wires,w);
1151     wire_free(w);
1152     return 1;
1153   }
1154   return 0;
1155 }
1156 
wire_makecorner(GWireNode * n,int tx,int ty)1157 GWireNode *wire_makecorner(GWireNode *n,int tx,int ty)
1158 {
1159   GWireNode *nn;
1160   GWire *dn;
1161 
1162   if (!n->out)
1163     return NULL;
1164 
1165   if ((n->stype != HORIZONTAL) && (n->stype != VERTICAL))
1166     return NULL;
1167 
1168   dn = wirenode_driver(n);
1169   GWire_draw(dn);
1170   nn = new_GWireNode();
1171   ob_touch(nn);
1172   nn->out = new_GWireNode();
1173   ob_touch(nn->out);
1174   nn->out->in = nn;
1175 
1176   if (n->x == n->out->x) {
1177     nn->x = nn->out->x = n->x;
1178     nn->y = nn->out->y = ty;
1179   } else {
1180     nn->y = nn->out->y = n->y;
1181     nn->x = nn->out->x = tx;
1182   }
1183 
1184   nn->out->out = n->out;
1185   ob_touch(n->out);
1186   n->out->in = nn->out;
1187   nn->in = n;
1188   n->out = nn;
1189 
1190   nn->stype = nn->out->stype = HORIZONTAL | VERTICAL;
1191 
1192   GWire_draw(dn);
1193 
1194   return n->in ? nn : nn->out;
1195 }
1196 
wire_unattach(GWire * w,GWire * wl)1197 GWire *wire_unattach(GWire *w,GWire *wl)
1198 {
1199   if (wl) {
1200     if (w == wl)
1201       return w->next;
1202     else {
1203       ob_touch(wl);
1204       wl->next = wire_unattach(w,wl->next);
1205       return wl;
1206     }
1207   } else
1208     return NULL;
1209 }
1210 
wire_deletenode(GWireNode * n)1211 void wire_deletenode(GWireNode *n)
1212 {
1213   if (n->out && !n->in) {
1214     ob_touch(n->end);
1215     ob_touch(n->out);
1216     n->end->nodes = n->out;
1217     n->out->end = n->end;
1218     n->out->in = NULL;
1219     n->out->stype = n->stype;
1220   } else
1221     if (n->in && !n->out) {
1222       ob_touch(n->end);
1223       ob_touch(n->in);
1224       n->end->nodes = n->in;
1225       n->in->end = n->end;
1226       n->in->out = NULL;
1227       n->in->stype = n->stype;
1228     } else {
1229       ob_touch(n->out);
1230       ob_touch(n->in);
1231       n->out->in = n->in;
1232       n->in->out = n->out;
1233       n->out->stype = n->stype;
1234     }
1235   delete_GWireNode(n);
1236 }
1237 
wire_deletezeronodes(GWireNode * n)1238 void wire_deletezeronodes(GWireNode *n)
1239 {
1240   if (n && n->out) {
1241     if (n->x == n->out->x && n->y == n->out->y) {
1242       GWireNode *nn;
1243 
1244       nn = n->out;
1245       wire_deletenode(n);
1246       wire_deletezeronodes(nn);
1247     } else
1248       wire_deletezeronodes(n->out);
1249   }
1250 }
1251 
GWireNode_freenodelist(GWireNode * n)1252 void GWireNode_freenodelist(GWireNode *n)
1253 {
1254   if (n) {
1255     GWireNode_freenodelist(n->out);
1256     delete_GWireNode(n);
1257   }
1258 }
1259 
1260 /*
1261   Evaluate quality of cutting segment between n1 and n2 at point (x,y).
1262   Lower values are better
1263  */
cutscore(GWireNode * n1,GWireNode * n2,int x,int y)1264 int cutscore(GWireNode *n1,GWireNode *n2,int x,int y)
1265 {
1266   if (!n1 || !n2) return 1000;
1267 
1268   if (n1->x == n2->x) {
1269     if (n1->y < n2-> y) {
1270       if (y < n1->y || y > n2->y) return 1000;
1271     } else {
1272       if (y < n2->y || y > n1->y) return 1000;
1273     }
1274     return abs(x-n1->x);
1275   } else {
1276     if (n1->x < n2->x) {
1277       if (x < n1->x || x > n2->x) return 1000;
1278     } else {
1279       if (x < n2->x || x > n1->x) return 1000;
1280     }
1281     return abs(y-n1->y);
1282   }
1283 }
1284 
wire_dump(EditState * es)1285 void wire_dump(EditState *es)
1286 {
1287   GWireList *l;
1288   GWire *lw;
1289   GWireNode *ln;
1290 
1291   printf("WIRES:\n");
1292   for (l = es->env->m_wires;l;l = l->wl_next) {
1293     lw = l->wl_wire;
1294     if (!lw->nodes->out) continue;
1295     printf("  **  %s: ",lw->net->n_signame);
1296     for (ln = lw->nodes;ln;ln = ln->out)
1297       printf(" @%p:(%d %d)",ln,ln->x,ln->y);
1298     printf("\n");
1299   }
1300 }
1301 
1302 
1303 /*
1304  * Adds a new wire stub at position (x,y).
1305  */
wire_addstub(EditState * es,int x,int y)1306 void wire_addstub(EditState *es,int x,int y)
1307 {
1308   GWire *new_w1,*new_w2,*cut_w1,*cut_w2;
1309   GWireNode *n1 = 0;
1310   GWireNode *n2 = 0;
1311   int cs1,cs2;
1312   GWire *w;
1313   GWire *jw[4];					/* Attachment points for joint (0=right, 1=up, 2=left, 3=down) */
1314 
1315   jw[0] = jw[1] = jw[2] = jw[3] = 0;
1316 
1317   n1 = wire_hitall(x,y,es->env->m_wires);
1318   if (!n1) { return; }
1319   w = wirenode_driver(n1);
1320 
1321   if (distance(x,y,n1->x,n1->y) < MAXWIRERANGE) {	/* Attach to corner */
1322     if (!n1->in || !n1->out) {
1323       return;
1324     }
1325 
1326     x = n1->x;
1327     y = n1->y;
1328 
1329     GNet_draw(w->net);
1330 
1331     cut_w1 = wire_newend(es->env,w->net,1);
1332     cut_w2 = wire_newend(es->env,w->net,1);
1333     wire_newNetSegment(es->env,w->net,&new_w1,&new_w2);		/* The new wire to attach */
1334 
1335     ob_touch(cut_w1->nodes);
1336     cut_w1->nodes->in = n1->in;
1337 
1338     ob_touch(n1->in);
1339     n1->in->out = cut_w1->nodes;
1340 
1341     ob_touch(cut_w2->nodes);
1342     cut_w2->nodes->out = n1->out;
1343 
1344     ob_touch(n1->out);
1345     n1->out->in = cut_w2->nodes;
1346 
1347     ob_touch(new_w1->nodes);
1348     new_w1->nodes->x = x;
1349     new_w1->nodes->y = y;
1350 
1351     ob_touch(new_w2->nodes);
1352     new_w2->nodes->x = x;
1353     new_w2->nodes->y = y;
1354 
1355     cut_w1->nodes->x = x;
1356     cut_w1->nodes->y = y;
1357     cut_w2->nodes->x = x;
1358     cut_w2->nodes->y = y;
1359 
1360     if (n1->x > n1->in->x)
1361       jw[2] = cut_w1;
1362     else if (n1->x < n1->in->x)
1363       jw[0] = cut_w1;
1364     else if (n1->y > n1->in->y)
1365       jw[1] = cut_w1;
1366     else if (n1->y < n1->in->y)
1367       jw[3] = cut_w1;
1368     else {
1369       jw[0] = cut_w1;				/* Should never happen */
1370       logError(ERL_ERROR,"bogus w1 cut: (%d,%d) (%d,%d)\n",n1->x,n1->y,n1->in->x,n1->in->y);
1371     }
1372 
1373     if (n1->x > n1->out->x && !jw[2])
1374       jw[2] = cut_w2;
1375     else if (n1->x < n1->out->x && !jw[0])
1376       jw[0] = cut_w2;
1377     else if (n1->y > n1->out->y && !jw[1])
1378       jw[1] = cut_w2;
1379     else if (n1->y < n1->out->y && !jw[3])
1380       jw[3] = cut_w2;
1381     else {					/* Should never happen */
1382       logError(ERL_ERROR,"bogus w2 cut: (%d,%d) (%d,%d)\n",n1->x,n1->y,n1->out->x,n1->out->y);
1383       if (!jw[0])
1384 	jw[0] = cut_w2;
1385       else
1386 	jw[2] = cut_w2;
1387     }
1388 
1389     if (!jw[0]) {
1390       jw[0] = new_w1;
1391       new_w2->nodes->x += 12;
1392     } else if (!jw[1]) {
1393       jw[1] = new_w1;
1394       new_w2->nodes->y -= 12;
1395     } else if (!jw[2]) {
1396       jw[2] = new_w1;
1397       new_w2->nodes->x -= 12;
1398     } else if (!jw[3]) {
1399       jw[3] = new_w1;
1400       new_w2->nodes->y += 12;
1401     }
1402 
1403     delete_GWireNode(n1);
1404   } else {						/* Attach to segment */
1405     cs1 = cutscore(n1,n1->out,x,y);
1406     cs2 = cutscore(n1,n1->in,x,y);
1407 
1408     if (cs1 < cs2) {
1409       n2 = n1->out;
1410     } else {
1411       n1 = n1->in;
1412       n2 = n1->out;
1413     }
1414     if (!n2) return;
1415 
1416     GNet_draw(w->net);
1417 
1418     cut_w1 = wire_newend(es->env,w->net,1);
1419     cut_w2 = wire_newend(es->env,w->net,1);
1420     wire_newNetSegment(es->env,w->net,&new_w1,&new_w2);		/* The new wire to attach */
1421 
1422     ob_touch(n1);
1423     n1->out = cut_w1->nodes;
1424 
1425     ob_touch(cut_w1->nodes);
1426     cut_w1->nodes->in = n1;
1427 
1428     ob_touch(n2);
1429     n2->in = cut_w2->nodes;
1430 
1431     ob_touch(cut_w2->nodes);
1432     cut_w2->nodes->out = n2;
1433 
1434     ob_touch(new_w2->nodes);
1435 
1436     if (n1->x == n2->x) {
1437       x = n1->x;
1438 
1439       jw[0] = new_w1;
1440 
1441       new_w2->nodes->x = x + 12;
1442       new_w2->nodes->y = y;
1443 
1444       if (n1->y < n2->y) {
1445 	jw[1] = cut_w1;
1446 	jw[3] = cut_w2;
1447       } else {
1448 	jw[1] = cut_w2;
1449 	jw[3] = cut_w1;
1450       }
1451     } else if (n1->y == n2->y) {
1452       y = n1->y;
1453 
1454       jw[1] = new_w1;
1455 
1456       new_w2->nodes->x = x;
1457       new_w2->nodes->y = y - 12;
1458 
1459       if (n1->x < n2->x) {
1460 	jw[2] = cut_w1;
1461 	jw[0] = cut_w2;
1462       } else {
1463 	jw[2] = cut_w2;
1464 	jw[0] = cut_w1;
1465       }
1466     }
1467 
1468     ob_touch(new_w1->nodes);
1469     ob_touch(cut_w1->nodes);
1470     ob_touch(cut_w2->nodes);
1471     new_w1->nodes->x = x;
1472     new_w1->nodes->y = y;
1473     cut_w1->nodes->x = x;
1474     cut_w1->nodes->y = y;
1475     cut_w2->nodes->x = x;
1476     cut_w2->nodes->y = y;
1477 
1478   }
1479 
1480   if (jw[0]) { jw[0]->nodes->x += 2; jw[0]->orient = 0; }
1481   if (jw[1]) { jw[1]->nodes->y -= 2; jw[1]->orient = 1; }
1482   if (jw[2]) { jw[2]->nodes->x -= 2; jw[2]->orient = 2; }
1483   if (jw[3]) { jw[3]->nodes->y += 2; jw[3]->orient = 3; }
1484   joint_make(x,y,jw[0],jw[1],jw[2],jw[3],es);
1485 
1486   ob_touch(new_w2);
1487   new_w2->orient = (new_w1->orient + 2) % 4;
1488 
1489   GWireNode_setends(cut_w1->nodes);
1490   GWireNode_setends(cut_w2->nodes);
1491   GWireNode_setends(new_w1->nodes);
1492 
1493   wire_finalizeNet(new_w1);
1494   GNet_draw(w->net);
1495 }
1496 
wire_numOnPad(GWire * w)1497 int wire_numOnPad(GWire *w)
1498 {
1499   if (!w)
1500     return 0;
1501   else
1502     return 1 + wire_numOnPad(w->next);
1503 }
1504 
wire_root(GWireNode * n)1505 GWire *wire_root(GWireNode *n)
1506 {
1507   GWire *w;
1508   int i;
1509 
1510   w = wirenode_driver(n);
1511   if (w->gate)
1512     switch (w->gate->typeinfo->code) {
1513     case GC_JOINT :
1514       for (i=0;i<4;i++)
1515 	if (w->gate->wires[i] &&
1516 	    (w->gate->wires[i]->nodes->in))
1517 	  return wire_root(w->gate->wires[i]->nodes);
1518       break;
1519     case GC_TAP :
1520       if (w->gate->wires[TAP_TAP] != w)
1521 	return wire_root(w->gate->wires[TAP_IN]->nodes);
1522       break;
1523     }
1524   return w;
1525 }
1526 
1527 /*
1528  * Set the size of the selected wire to the current wire size
1529  */
setwiresize(EditState * es)1530 void setwiresize(EditState *es)
1531 {
1532   GWire *r;
1533   int size;
1534 
1535   ob_touch(TkGate.circuit);
1536 
1537   if (!(TkGate.circuit->wnsel = wire_hit(TkGate.ed->tx,TkGate.ed->ty,es->env->m_wires)))
1538     TkGate.circuit->wnsel = wire_iohit(TkGate.ed->tx,TkGate.ed->ty,es->env->m_wires);
1539 
1540   if (TkGate.circuit->wnsel) {
1541     const char *str_size = Tcl_GetVar(TkGate.tcl,"tkg_bitWidth",TCL_GLOBAL_ONLY);
1542 
1543     size = 1;
1544     assert(str_size);
1545     sscanf(str_size,"%d",&size);
1546 
1547     TkGate.circuit->wsel = wirenode_driver(TkGate.circuit->wnsel);
1548     r = wire_root(TkGate.circuit->wnsel);
1549     GNet_draw(r->net);
1550     net_setSize(r->net,size);
1551     GNet_draw(r->net);
1552     SetModified(MF_NET);
1553   }
1554 }
1555 
1556 
GWire_getNetWires_aux(GWire * w,GWire ** wlist,unsigned which,int isFirst)1557 static int GWire_getNetWires_aux(GWire *w,GWire **wlist,unsigned which,int isFirst)
1558 {
1559   int count = 0;
1560   int i;
1561 
1562   w = wire_other(w);
1563 
1564   if (!isFirst) {
1565     if ((which & GW_DRIVER))
1566       wlist[count++] = wire_driver(w);
1567     if ((which & GW_DRIVEE))
1568       wlist[count++] = wire_drivee(w);
1569   }
1570 
1571   if (w->gate) {
1572     switch (w->gate->typeinfo->code) {
1573     case GC_JOINT :
1574       for (i=0;i<4;i++)
1575 	if (w->gate->wires[i] && (w->gate->wires[i] != w))
1576 	  count += GWire_getNetWires_aux(w->gate->wires[i],wlist+count,which,0);
1577       break;
1578     case GC_TAP :
1579       if (w == w->gate->wires[TAP_OUT])
1580 	count += GWire_getNetWires_aux(w->gate->wires[TAP_IN],wlist+count,which,0);
1581       else if (w == w->gate->wires[TAP_IN])
1582 	count += GWire_getNetWires_aux(w->gate->wires[TAP_OUT],wlist+count,which,0);
1583       break;
1584     }
1585   }
1586   return count;
1587 }
1588 
GWire_getNetWires(GWire * w,GWire ** wlist,unsigned which)1589 int GWire_getNetWires(GWire *w,GWire **wlist,unsigned which)
1590 {
1591   GWire *o_w;
1592   int count = 0;
1593 
1594   if (!w) return 0;
1595 
1596   o_w = wire_other(w);
1597 
1598   count = GWire_getNetWires_aux(w,wlist,which,0);
1599   count += GWire_getNetWires_aux(o_w,wlist+count,which,1);
1600 
1601   return count;
1602 }
1603 
GWire_insertNode(GWire * w)1604 void GWire_insertNode(GWire*w)
1605 {
1606   GWireNode *n = new_GWireNode();
1607 
1608   ob_touch(w->nodes);
1609   ob_touch(w);
1610 
1611   if (!w->nodes->in) {
1612     w->nodes->in = n;
1613     n->out = w->nodes;
1614   } else {
1615     w->nodes->out = n;
1616     n->in = w->nodes;
1617   }
1618 
1619   n->x = w->nodes->x;
1620   n->y = w->nodes->y;
1621 
1622   w->nodes->end = 0;
1623   n->end = w;
1624   w->nodes = n;
1625 
1626 }
1627