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