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 Mon Dec 22 06:31:44 2008
19 ****************************************************************************/
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include "tkgate.h"
25
26 #define DEBUG_NET 0
27
28 static char *vtype_table[] = {
29 "wire", "tri", "wand", "triand", "wor", "trior", "tri0", "tri1", "trireg"
30 };
31 static int vtype_table_length = sizeof(vtype_table)/sizeof(vtype_table[0]);
32
33 int ycIsKW(char*);
34
35 /*****************************************************************************
36 *
37 * Get a string for the "display type" of a net.
38 *
39 * Parameters:
40 * n Net on which to lookup the dtype.
41 *
42 * Returns: String representing the display type.
43 *
44 * Get the string for the net's "dtype". The dtype is the type used to determine what
45 * type of symbol should be displayed next to the net in the list of nets. It
46 * is not necessarily the actual verilog type.
47 *
48 *****************************************************************************/
GNet_getDTypeStr(GNet * n)49 const char *GNet_getDTypeStr(GNet *n)
50 {
51 /*
52 * Translate type code from HDL modules
53 */
54 switch (n->n_dtype) {
55 case NT_INPUT : return "input";
56 case NT_OUTPUT : return "output";
57 case NT_INOUT : return "inout";
58 case NT_REG : return "reg";
59 case NT_WIRE : return "wire";
60 }
61
62 if (n->n_ionet) {
63 switch (n->n_ionet->typeinfo->code) {
64 case GC_LOGICIN : return "input";
65 case GC_LOGICOUT : return "output";
66 case GC_LOGICTRI : return "inout";
67 }
68 }
69
70 return "wire";
71 }
72
73 /*****************************************************************************
74 *
75 * Get a string for the "verilog type" of a net.
76 *
77 * Parameters:
78 * n Net on which to lookup the dtype.
79 *
80 * Returns: String representing the verilog type.
81 *
82 *****************************************************************************/
GNet_getVType(GNet * n)83 const char *GNet_getVType(GNet *n)
84 {
85 int code = 0;
86
87 if (n->n_ionet) {
88 switch (n->n_ionet->typeinfo->code) {
89 case GC_SWITCH :
90 case GC_DIP :
91 return "switch";
92 case GC_LOGICIN :
93 case GC_LOGICOUT :
94 case GC_LOGICTRI :
95 return "port";
96 }
97 return n->n_ionet->typeinfo->vnames;
98 }
99
100 code = n->n_vtype;
101 if (code > vtype_table_length)
102 code = 0;
103
104
105 return vtype_table[code];
106 }
107
GNet_setVType(GNet * n,const char * vtype)108 void GNet_setVType(GNet *n,const char *vtype)
109 {
110 int i;
111
112 ob_touch(n);
113
114 for (i = 0;i < vtype_table_length;i++)
115 if (strcmp(vtype_table[i],vtype) == 0) break;
116
117 if (i >= vtype_table_length)
118 i = 0;
119
120 n->n_vtype = i;
121 n->n_labelWidth = 0;
122 }
123
124
125 /*****************************************************************************
126 *
127 * Create a new net in a module with properties similar to another net
128 *
129 * Parameters:
130 * name Net name hint
131 * rnet Reference net on which to base the new net's properties
132 * M Module in which to create net
133 *
134 *****************************************************************************/
new_GNet_compatable(const char * name,GNet * rnet,GModuleDef * M)135 GNet *new_GNet_compatable(const char *name,GNet *rnet,GModuleDef *M)
136 {
137 GNet *net;
138 static unsigned generation = 0;
139
140 net = (GNet*) ob_malloc(sizeof(GNet),"GNet");
141
142 if (M) {
143 char buf[STRMAX];
144
145 pickValidName(buf,name,"w",M->m_nets);
146 net->n_signame = ob_strdup(buf);
147 if (name) {
148 net->n_show_name = 1;
149 } else {
150 net->n_show_name = 0;
151 }
152 } else {
153 net->n_signame = 0;
154 net->n_show_name = 0;
155 }
156
157 net->n_nbits = rnet ? rnet->n_nbits : 1;
158 net->n_dtype = NT_NONE;
159 net->n_vtype = NV_WIRE;
160 net->n_refs = 0;
161 net->n_mark = 0;
162 net->n_ionet = 0;
163 net->n_mod = M;
164 net->n_driver = 0;
165 net->n_next = 0;
166 net->n_finalized = 0;
167 net->n_labelWidth = 0;
168 net->n_generation = generation++;
169
170 SHash_insert(M->m_nets,net->n_signame,net);
171
172 if (M && TkGate.circuit->es && M == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE) {
173 DoTcl("NetList::add %s -hidden %d -bits %d -type %s",net->n_signame,!net->n_show_name,net->n_nbits,GNet_getDTypeStr(net));
174 }
175
176 #if DEBUG_NET
177 printf("new_GNet() -> %x",net);
178 if (net->n_signame)
179 printf(" (%s)\n",net->n_signame);
180 else
181 printf("\n");
182 #endif
183
184 return net;
185 }
186
187 /*****************************************************************************
188 *
189 * Create a new net in a module
190 *
191 * Parameters:
192 * name Net name hint
193 * M Module in which to create net
194 *
195 *****************************************************************************/
new_GNet(const char * name,GModuleDef * M)196 GNet *new_GNet(const char *name,GModuleDef *M)
197 {
198 return new_GNet_compatable(name,0,M);
199 }
200
201 /*****************************************************************************
202 *
203 * Update net in the net list box
204 *
205 * Parameters:
206 * n Target net for operation.
207 *
208 *****************************************************************************/
net_update(GNet * n)209 void net_update(GNet *n)
210 {
211 if (n->n_mod && TkGate.circuit->es && n->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE)
212 DoTcl("NetList::replace %s -hidden %d -bits %d -type %s",n->n_signame,!n->n_show_name,n->n_nbits,GNet_getDTypeStr(n));
213 }
214
delete_GNet(GNet * net)215 void delete_GNet(GNet *net)
216 {
217 ob_touch(net);
218 #if DEBUG_NET
219 printf("GNet::Delete(%s) %x",net->n_signame ?: "",net);
220 #endif
221
222 if (net->n_signame) {
223 SHash_remove(net->n_mod->m_nets,net->n_signame);
224 if (net->n_mod && TkGate.circuit->es && net->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE) {
225 DoTcl("NetList::del %s",net->n_signame);
226 }
227 ob_free(net->n_signame);
228 #if DEBUG_NET
229 printf(" [%d]",r);
230 #endif
231 }
232 #if DEBUG_NET
233 printf("\n");
234 #endif
235 ob_free(net);
236 }
237
238 /*****************************************************************************
239 *
240 * Increment the reference count of a net.
241 *
242 * Parameters:
243 * net Target net for operation.
244 *
245 *****************************************************************************/
net_incref(GNet * net)246 void net_incref(GNet *net)
247 {
248 ob_touch(net);
249 #if 0
250 printf("net_incref(%s) [%d]\n",net->n_signame,net->n_refs+1);
251 #endif
252 net->n_refs++;
253 }
254
255 /*
256 * Decrement the reference count of a net. If the reference
257 * count goes to zero, the net is deleted.
258 */
net_decref(GNet * net)259 void net_decref(GNet *net)
260 {
261 ob_touch(net);
262 #if 0
263 printf("net_decref(%s) [%d]\n",net->n_signame,net->n_refs-1);
264 #endif
265 if (--net->n_refs <= 0)
266 delete_GNet(net);
267 }
268
269 /*
270 * Select one of the nets 'a' or 'b'. Typically used when joining two wires
271 * to determine which net name will be retained and which will be deleted.
272 */
net_pickOne(GNet * a,GNet * b,int decref_loser)273 GNet *net_pickOne(GNet *a,GNet *b,int decref_loser)
274 {
275 GNet *r = 0; /* Net to return */
276 GNet *l = 0; /* Losing net */
277
278 if (!a)
279 r = b;
280 else if (!b)
281 r = a;
282 else if (a == b) {
283 r = a;
284 l = b;
285 } else if (a->n_ionet) {
286 r = a;
287 l = b;
288 } else if (b->n_ionet) {
289 r = b;
290 l = a;
291 } else if (a->n_show_name) {
292 r = a;
293 l = b;
294 } else if (b->n_show_name) {
295 r = b;
296 l = a;
297 } else if (a->n_generation < b->n_generation) {
298 r = a;
299 l = b;
300 } else {
301 r = b;
302 l = a;
303 }
304
305 if (l && decref_loser) net_decref(l);
306
307 return r;
308 }
309
310 /*
311 Check to see if it is OK to connect wires from the
312 specified nets. Return 1 if OK, return 0 and display
313 a status bar message if not OK.
314 */
net_connectOK(GNet * n1,GNet * n2,int isMidWire)315 int net_connectOK(GNet *n1,GNet *n2,int isMidWire)
316 {
317 if (n1 == n2) {
318 message(0,msgLookup("err.badconsame")); /* Connection refused because wires are part of the same net. */
319 return 0;
320 }
321 if (n1->n_ionet && n2->n_ionet) {
322 message(0,msgLookup("err.badconptsp")); /* Connection refused because both wires are module ports or supply. */
323 return 0;
324 }
325
326 if (!isMidWire && n1->n_nbits != n2->n_nbits) {
327 message(0,msgLookup("err.badconbitw")); /* Connection refused because bit widths do not match. */
328 return 0;
329 }
330
331 return 1;
332 }
333
334 /*
335 Unselect all nets.
336 */
net_unselect(int drawp)337 void net_unselect(int drawp)
338 {
339 if (TkGate.circuit->nsel) {
340 GNet *n = TkGate.circuit->nsel;
341 if (drawp) GNet_draw(n);
342 TkGate.circuit->nsel = 0;
343 if (drawp) GNet_draw(n);
344 }
345 }
346
347 /*
348 Make 'n' the selected net.
349 */
net_select(GNet * n,int drawp)350 void net_select(GNet *n,int drawp)
351 {
352 if (TkGate.circuit->nsel == n) return;
353 net_unselect(drawp);
354
355 if (!n) return;
356
357 DoTcl("NetList::shadowselection %s",n->n_signame);
358
359 ob_touch(TkGate.circuit);
360
361 if (drawp) GNet_draw(n);
362 TkGate.circuit->nsel = n;
363 if (drawp) GNet_draw(n);
364 }
365
366
367
368 /*
369 Redraw an entire net.
370 */
GNet_draw(GNet * net)371 void GNet_draw(GNet *net)
372 {
373 wire_drawnet(net->n_driver);
374 }
375
net_setDType(GNet * net,int dtype)376 void net_setDType(GNet *net,int dtype)
377 {
378 if (net->n_dtype == dtype) return;
379
380 ob_touch(net);
381 net->n_dtype = dtype;
382 net->n_labelWidth = 0;
383
384 if (net->n_mod && TkGate.circuit->es && net->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE) {
385 DoTcl("NetList::replace %s -hidden %d -bits %d -type %s",net->n_signame,!net->n_show_name,net->n_nbits,GNet_getDTypeStr(net));
386 }
387 }
388
net_setSize(GNet * net,int nbits)389 void net_setSize(GNet *net,int nbits)
390 {
391 if (net->n_nbits == nbits) return;
392
393 ob_touch(net);
394 net->n_nbits = nbits;
395
396 if (net->n_mod && TkGate.circuit->es && net->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE) {
397 DoTcl("NetList::replace %s -hidden %d -bits %d -type %s",net->n_signame,!net->n_show_name,net->n_nbits,GNet_getDTypeStr(net));
398 }
399 }
400
net_editProps(GNet * n,int x,int y)401 void net_editProps(GNet *n,int x,int y)
402 {
403 char *sn = n->n_show_name ? "" :"@";
404 int ioCode = 0;
405 int wx = ctow_x(x-50);
406 int wy = ctow_y(y-50);
407 const char *result;
408 const char *vtype = GNet_getVType(n);
409
410 if (n->n_ionet) {
411 ioCode = n->n_ionet->typeinfo->code;
412 if (ioCode != GC_LOGICIN && ioCode != GC_LOGICOUT && ioCode != GC_LOGICTRI)
413 ioCode = 0; /* yappari yameta */
414 }
415
416
417 if (n->n_nbits == 1)
418 DoTcl("tkg_editNet %d %d {%s%s} %d %s\n",wx,wy,n->n_signame,sn,ioCode,vtype);
419 else
420 DoTcl("tkg_editNet %d %d {%s[%d:0]%s} %d %s\n",wx,wy,n->n_signame,n->n_nbits-1,sn,ioCode,vtype);
421
422 result = Tcl_GetStringResult(TkGate.tcl);
423
424 if (*result != '0')
425 SetModified(MF_NET);
426 }
427
428 /*
429 Set the signal name of a wire to s.
430 */
net_rename(GNet * net,const char * s,int showName)431 void net_rename(GNet *net,const char *s,int showName)
432 {
433 char *oldName = ob_strdup(net->n_signame);
434 char buf[STRMAX];
435
436 if (net->n_signame) {
437 if (net->n_mod && TkGate.circuit->es && net->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE)
438 DoTcl("NetList::del %s",net->n_signame);
439
440 SHash_remove(net->n_mod->m_nets,net->n_signame);
441 ob_free(net->n_signame);
442 }
443 ob_touch(net);
444 net->n_signame = 0;
445 net->n_labelWidth = 0;
446
447 pickValidName(buf,s,"w",net->n_mod->m_nets);
448 net->n_signame = ob_strdup(buf);
449
450 if (showName)
451 GNet_showName(net);
452 else
453 GNet_hideName(net);
454
455 SHash_insert(net->n_mod->m_nets,net->n_signame,net);
456
457 if (net->n_mod && TkGate.circuit->es && net->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE) {
458 DoTcl("NetList::replace %s -hidden %d -bits %d -type %s",
459 net->n_signame,!net->n_show_name,net->n_nbits,GNet_getDTypeStr(net));
460 }
461 ob_free(oldName);
462 }
463
464 /*
465 * Check 'name' to see if it is a valid name. If 'H' is non-null, then the
466 * name may not appear as a key in the hash table. Returns 0 if the name
467 * is valid.
468 */
checkValidName(const char * name,SHash * H)469 int checkValidName(const char *name,SHash *H)
470 {
471 const char *p = name;
472
473 if (!isalpha(*p) && *p != '_')
474 return -1;
475
476 for (p++;*p;p++) {
477 if (!isalpha(*p) && !isdigit(*p) && *p != '_')
478 return -1;
479 }
480
481 if (H && SHash_find(H,name))
482 return -1;
483
484 return 0;
485 }
486
487 /*****************************************************************************
488 *
489 * Pick name for an object based on suggested name.
490 *
491 * Parameters:
492 * buf Return for generated name
493 * name Suggested name
494 * base Type-dependent base name for name generation
495 * H Table of already registered names
496 *
497 * Pick a valid name for an object based on a possible suggested name 'name',
498 * a base name 'base' for objects of a that type, and a hash table 'H' for objects
499 * of that type. One or more of 'name', 'base' and 'H' may be null. The generated
500 * name will be placed in 'buf'. If 'name' is a valid name that does not appear in the
501 * hash table 'H', 'name' will become the selected name.
502 *
503 *****************************************************************************/
pickValidName(char * buf,const char * name,const char * base,SHash * H)504 void pickValidName(char *buf,const char *name,const char *base,SHash *H)
505 {
506 int reason;
507
508 if (!base || !*base)
509 base = "n";
510
511 reason = 0;
512 if (name) {
513 if (buf != (char*)name)
514 strcpy(buf,name);
515
516 if (trimName(buf)) {
517 reason = 1;
518 if (!*buf) {
519 if (base)
520 strcpy(buf,base);
521 else
522 strcpy(buf,"name");
523 }
524 }
525
526 if (!*buf)
527 sprintf(buf,"%s0",base);
528
529 if (H && SHash_find(H,buf))
530 reason = 2;
531 else if (ycIsKW(buf))
532 reason = 4;
533 else {
534 if (reason)
535 message(0,msgLookup("err.badnetname")); /* "Illegal characters in identifier deleted." */
536 return;
537 }
538 } else
539 sprintf(buf,"%s0",base);
540
541 /** @TODO to remove */
542 /*p = buf+strlen(buf);*/
543
544 if ((H && SHash_find(H,buf)) || ycIsKW(buf)) {
545 char *p;
546 int n;
547
548 p = buf + strlen(buf);
549 while (p > buf && isdigit((int)p[-1])) p--;
550
551 n = 0;
552 if (*p) sscanf(p,"%d",&n);
553
554 do {
555 sprintf(p,"%d",n++);
556 } while ((H && SHash_find(H,buf)) || ycIsKW(buf));
557 }
558
559 switch (reason) {
560 case 1 :
561 message(0,msgLookup("err.netbcrename"),buf); /* "Identifier renamed to '%s' because of illegal characters." */
562 break;
563 case 2 :
564 message(0,msgLookup("err.netconfnet"),buf);
565 break;
566 case 3 :
567 message(0,msgLookup("err.netconfgat"));
568 break;
569 case 4 :
570 message(0,msgLookup("err.netconfkw"));
571 break;
572 }
573 }
574
GWire_pickProbePosition(GWire * w,int * x,int * y)575 int GWire_pickProbePosition(GWire *w,int *x,int *y)
576 {
577 int orig_x = *x;
578 int orig_y = *y;
579 int best_d = 0x7ffffff;
580 int best_x = 0, best_y = 0;
581 GWireNode *n;
582
583
584 w = wire_driver(w);
585 for (n = w->nodes;n && n->out;n = n->out) {
586 int x1 = n->x;
587 int y1 = n->y;
588 int x2 = n->out->x;
589 int y2 = n->out->y;
590 int d = 0x7fffffff;
591 int test_x, test_y;
592
593 if (x1 == x2) {
594 if (iabs(orig_y-y1) <= iabs(y1-y2) && iabs(orig_y-y2) <= iabs(y1-y2)) {
595 d = iabs(orig_x-x1)*iabs(orig_x-x1);
596 test_x = x1;
597 test_y = orig_y;
598 }
599 } else {
600 if (iabs(orig_x-x1) <= iabs(x1-x2) && iabs(orig_x-x2) <= iabs(x1-x2)) {
601 d = iabs(orig_y-y1)*iabs(orig_y-y1);
602 test_x = orig_x;
603 test_y = y1;
604 }
605 }
606 if (d == 0x7fffffff) {
607 int d1 = iabs(orig_x-x1)*iabs(orig_x-x1) + iabs(orig_y-y1)*iabs(orig_y-y1);
608 int d2 = iabs(orig_x-x2)*iabs(orig_x-x2) + iabs(orig_y-y2)*iabs(orig_y-y2);
609 if (d1 < d2) {
610 d = d1;
611 test_x = x1;
612 test_y = y1;
613 } else {
614 d = d2;
615 test_x = x2;
616 test_y = y2;
617 }
618 }
619
620 if (d < best_d) {
621 best_d = d;
622 best_x = test_x;
623 best_y = test_y;
624 }
625 }
626
627 *x = best_x;
628 *y = best_y;
629
630 return best_d;
631 }
632
GNet_getDisplayLabel(GNet * net,char label[],int len,int mode)633 int GNet_getDisplayLabel(GNet *net,char label[],int len,int mode)
634 {
635 *label = 0;
636
637 if (net->n_ionet && mode == DLM_GET_VISIBLE) {
638 switch (net->n_ionet->typeinfo->code) {
639 case GC_LOGICIN :
640 case GC_LOGICOUT :
641 case GC_LOGICTRI :
642 return 0;
643 }
644 }
645
646 if ((net->n_show_name && net->n_signame) || mode != DLM_GET_VISIBLE) {
647 if (net->n_vtype != NV_WIRE)
648 sprintf(label,"%s(%s)",net->n_signame,GNet_getVType(net));
649 else
650 sprintf(label,"%s",net->n_signame);
651 } else if (net->n_vtype != NV_WIRE)
652 sprintf(label,"(%s)",GNet_getVType(net));
653
654 return strlen(label);
655 }
656
657 /*
658 Get the position (x,y) and justification p for a signal name
659 on wire w.
660 */
SignalNamePos(GWireNode * n1,GWireNode * n2,int * x,int * y,int * p,int * q)661 void SignalNamePos(GWireNode *n1,GWireNode *n2,int *x,int *y,int *p,int *q)
662 {
663 *x = n1->x + (n2->x - n1->x)/3;
664 *y = n1->y + (n2->y - n1->y)/3;
665
666 if (n1->x == n2->x) {
667 *x += 5;
668 if (p) *p = AtLeft|BetweenTopAndBottom;
669 } else {
670 *x -= 5;
671 if (p) *p = BetweenLeftAndRight|AtBottom;
672 }
673
674
675 if (q) *q = (n1->x == n2->x) ? (n1->y <= n2->y) : 2 + (n1->x <= n2->x);
676 }
677
GNet_getWires(GNet * n,GWire ** wlist,unsigned which)678 int GNet_getWires(GNet *n,GWire **wlist,unsigned which)
679 {
680 return GWire_getNetWires(n->n_driver,wlist,which);
681 }
682
683 /*****************************************************************************
684 *
685 * Make sure the name on a net is hidden
686 *
687 * Parameter:
688 * net Net on which to make all labels hidden
689 *
690 *****************************************************************************/
GNet_hideName(GNet * net)691 void GNet_hideName(GNet *net)
692 {
693 ob_touch(net);
694 net->n_show_name = 0;
695 GNet_checkNameVisibility(net,0);
696 net_update(net);
697 }
698
699 /*****************************************************************************
700 *
701 * Make sure the name on a net is visible
702 *
703 * Parameter:
704 * net Net on which to make the label visible
705 *
706 *****************************************************************************/
GNet_showName(GNet * net)707 void GNet_showName(GNet *net)
708 {
709 ob_touch(net);
710 net->n_show_name = 1;
711 GNet_checkNameVisibility(net,1);
712 net_update(net);
713 }
714
GNet_checkNameVisibility(GNet * net,int action)715 void GNet_checkNameVisibility(GNet *net,int action)
716 {
717 if (net->n_show_name) {
718 GWire *wlist[GNet_numWires(net)];
719 GWireNode *n;
720 int count = GNet_getWires(net,wlist,GW_DRIVER);
721 int i;
722
723 #if 0
724 printf("checkNameVis %s nw=%d count=%d\n",net->n_signame,GNet_numWires(net),count);
725 #endif
726
727 /*
728 * Look for a labeled wire, if there is one, then return and do nothing further.
729 */
730 for (i = 0;i < count;i++) {
731 #if 0
732 printf(" pad %d\n",i);
733 #endif
734 for (n = wlist[i]->nodes;n;n = n->out) {
735 #if 0
736 printf(" wire %p islab=%d\n",n,n->isLabeled);
737 #endif
738 if (n->isLabeled) return;
739 }
740 }
741
742 /*
743 * None of the existing wires were labeled, so pick one and label it.
744 */
745 for (n = net->n_driver->nodes;n && n->out;n = n->out)
746 if (!n->showSize)
747 break;
748
749 if (action) {
750 ob_touch(n);
751 //printf("%p: make labeled (1)\n",n);
752 n->isLabeled = 1;
753 n->offset = 50;
754 } else {
755 ob_touch(net);
756 net->n_show_name = 0;
757 }
758 }
759 }
760
761
GNet_getLabelWidth(GNet * n)762 int GNet_getLabelWidth(GNet *n)
763 {
764 if (!n->n_labelWidth) {
765 char label[STRMAX];
766
767 if (GNet_getDisplayLabel(n, label, STRMAX, DLM_GET_ALWAYS) > 0) {
768 n->n_labelWidth = GKTextWidth(TkGate.stextbXF[TkGate.circuit->zoom_factor],label,strlen(label));
769 } else
770 n->n_labelWidth = 42;
771 }
772
773 return n->n_labelWidth;
774 }
775
776 /*****************************************************************************
777 *
778 * Square of distance from a point to a line segment.
779 *
780 *****************************************************************************/
segment_distance(int x,int y,int x1,int y1,int x2,int y2)781 int segment_distance(int x,int y,int x1,int y1,int x2,int y2)
782 {
783 if (x1 == x2) { /* Veritical segment */
784 if (y1 > y2) { int t = y1;y1=y2;y2=t;}
785
786 if (y < y1) {
787 return (y-y1)*(y-y1) + (x-x1)*(x-x1);
788 } else if (y > y2) {
789 return (y-y2)*(y-y2) + (x-x2)*(x-x2);
790 } else {
791 return (x-x1)*(x-x1);
792 }
793
794 } else { /* Horizontal segment */
795 if (x1 > x2) { int t = x1;x1=x2;x2=t;}
796
797 if (x < x1) {
798 return (y-y1)*(y-y1) + (x-x1)*(x-x1);
799 } else if (x > x2) {
800 return (y-y2)*(y-y2) + (x-x2)*(x-x2);
801 } else {
802 return (y-y1)*(y-y1);
803 }
804 }
805 }
806
GNet_labelClosest(GNet * net,int x,int y)807 void GNet_labelClosest(GNet *net,int x,int y)
808 {
809 GWire *wlist[GNet_numWires(net)];
810 GWireNode *n,*best_n = 0;
811 int best_dist = 0;
812 int count = GNet_getWires(net,wlist,GW_DRIVER);
813 int offset;
814 int side;
815 int i;
816
817
818 for (i = 0;i < count;i++) {
819 for (n = wlist[i]->nodes;n && n->out;n = n->out) {
820 int d = segment_distance(x,y,n->x,n->y,n->out->x,n->out->y);
821
822 if (!best_n || d < best_dist) {
823 best_dist = d;
824 best_n = n;
825 }
826 }
827 }
828
829 if (best_dist > 50*50) {
830 GNet_checkNameVisibility(net,0);
831 net_update(net);
832 return;
833 }
834
835
836 /*
837 * We found the node we wish to label...
838 */
839 if (best_n) {
840 int x1 = best_n->x;
841 int y1 = best_n->y;
842 int x2 = best_n->out->x;
843 int y2 = best_n->out->y;
844 GrabbedLabel *gl = TkGate.circuit->labelsel;
845
846 GNet_draw(net);
847 ob_touch(best_n);
848 best_n->isLabeled = 1;
849
850 if (y1 != y2) {
851 /* Vertical */
852 int ay = y + gl->oy;
853
854 if ((gl->position & AtTop))
855 ay += 12;
856
857 offset = 100*(ay-y1)/(y2-y1);
858 side = (x < x1);
859 } else if (x1 != x2) {
860 /* Horizontal */
861 int ax = x + gl->ox;
862
863 if ((gl->position & AtRight))
864 ax -= GNet_getLabelWidth(net);
865
866 offset = 100*(ax-x1)/(x2-x1);
867 side = (y > y1);
868 } else {
869 offset = 50;
870 side = 0;
871 }
872
873 if (offset < 1) offset = 1;
874 if (offset > 99) offset = 99;
875 best_n->offset = offset;
876 best_n->labelSide = side;
877 GNet_draw(net);
878 }
879 }
880
881