1
2 #ifndef lint
3 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResPrint.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
4 #endif /* not lint */
5
6 #include <stdio.h>
7 #include <string.h>
8 #include <ctype.h>
9 #include <math.h>
10
11 #include "tcltk/tclmagic.h"
12 #include "utils/magic.h"
13 #include "utils/geometry.h"
14 #include "utils/geofast.h"
15 #include "tiles/tile.h"
16 #include "utils/hash.h"
17 #include "database/database.h"
18 #include "utils/malloc.h"
19 #include "textio/textio.h"
20 #include "extract/extract.h"
21 #include "extract/extractInt.h"
22 #include "windows/windows.h"
23 #include "dbwind/dbwind.h"
24 #include "utils/utils.h"
25 #include "cif/cif.h"
26 #include "utils/tech.h"
27 #include "textio/txcommands.h"
28 #include "utils/stack.h"
29 #include "utils/styles.h"
30 #include "resis/resis.h"
31
32 #define MAXNAME 1000
33 #define KV_TO_mV 1000000
34
35 extern ResSimNode *ResInitializeNode();
36
37
38 /*
39 *-------------------------------------------------------------------------
40 *
41 * ResPrintExtRes-- Print resistor network to output file.
42 *
43 * Results:none
44 *
45 * Side Effects:prints network.
46 *
47 *-------------------------------------------------------------------------
48 */
49
50 void
ResPrintExtRes(outextfile,resistors,nodename)51 ResPrintExtRes(outextfile, resistors, nodename)
52 FILE *outextfile;
53 resResistor *resistors;
54 char *nodename;
55
56 {
57 int nodenum=0;
58 char newname[MAXNAME];
59 HashEntry *entry;
60 ResSimNode *node, *ResInitializeNode();
61
62 for (; resistors != NULL; resistors = resistors->rr_nextResistor)
63 {
64 /*
65 * These names shouldn't be null; they should either be set by
66 * the device name or by the node printing routine. This
67 * code is included in case the resistor network is printed
68 * before the nodes.
69 */
70
71 if (resistors->rr_connection1->rn_name == NULL)
72 {
73 (void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
74 entry = HashFind(&ResNodeTable, newname);
75 node = ResInitializeNode(entry);
76 resistors->rr_connection1->rn_name = node->name;
77 node->oldname = nodename;
78 }
79 if (resistors->rr_connection2->rn_name == NULL)
80 {
81 (void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
82 entry = HashFind(&ResNodeTable, newname);
83 node = ResInitializeNode(entry);
84 resistors->rr_connection2->rn_name = node->name;
85 node->oldname = nodename;
86 }
87 if (ResOptionsFlags & ResOpt_DoExtFile)
88 {
89 fprintf(outextfile, "resist \"%s\" \"%s\" %g\n",
90 resistors->rr_connection1->rn_name,
91 resistors->rr_connection2->rn_name,
92 resistors->rr_value / (float)ExtCurStyle->exts_resistScale);
93 }
94 }
95 }
96
97 /*
98 *-------------------------------------------------------------------------
99 *
100 * ResPrintExtDev-- Print out all devices that have had at least
101 * one terminal changed.
102 *
103 * Results:none
104 *
105 * Side Effects:prints device lines to output file
106 *
107 *-------------------------------------------------------------------------
108 */
109
110 void
ResPrintExtDev(outextfile,devices)111 ResPrintExtDev(outextfile, devices)
112 FILE *outextfile;
113 RDev *devices;
114 {
115 TileType t;
116 char *subsName;
117 ExtDevice *devptr;
118
119 for (; devices != NULL; devices = devices->nextDev)
120 {
121 if (devices->status & TRUE)
122 {
123 if (ResOptionsFlags & ResOpt_DoExtFile)
124 {
125 t = devices->layout->rd_devtype;
126 devptr = ExtCurStyle->exts_device[t];
127 subsName = devptr->exts_deviceSubstrateName;
128
129 #ifdef MAGIC_WRAPPER
130 /* Substrate variable name substitution */
131 if (subsName && subsName[0] == '$' && subsName[1] != '$')
132 {
133 char *varsub = (char *)Tcl_GetVar(magicinterp, &subsName[1],
134 TCL_GLOBAL_ONLY);
135 if (varsub != NULL) subsName = varsub;
136 }
137 #endif
138 /* Output according to device type and class. */
139 /* Code largely matches what's in ExtBasic.c extOutputDevices() */
140
141 if (devptr->exts_deviceClass != DEV_FET)
142 fprintf(outextfile,"device ");
143
144 fprintf(outextfile,"%s %s %d %d %d %d ",
145 extDevTable[devptr->exts_deviceClass],
146 devptr->exts_deviceName,
147 devices->layout->rd_inside.r_ll.p_x,
148 devices->layout->rd_inside.r_ll.p_y,
149 devices->layout->rd_inside.r_ll.p_x + 1,
150 devices->layout->rd_inside.r_ll.p_y + 1);
151
152 switch (devptr->exts_deviceClass)
153 {
154 case DEV_FET:
155 fprintf(outextfile," %d %d",
156 devices->layout->rd_area,
157 devices->layout->rd_perim);
158 break;
159
160 case DEV_MOSFET:
161 case DEV_ASYMMETRIC:
162 case DEV_BJT:
163 fprintf(outextfile," %d %d",
164 devices->layout->rd_length,
165 devices->layout->rd_width);
166 break;
167 }
168
169 if (devices->subs != NULL)
170 fprintf(outextfile, " \"%s\"", devices->subs->name);
171 else if (subsName != NULL)
172 fprintf(outextfile, " \"%s\"", subsName);
173 else
174 fprintf(outextfile, " \"None\"");
175
176 if (devices->gate != NULL)
177 fprintf(outextfile, " \"%s\" %d %s",
178 devices->gate->name,
179 devices->layout->rd_length * 2,
180 devices->rs_gattr);
181
182 if (devices->source != NULL)
183 fprintf(outextfile, " \"%s\" %d %s",
184 devices->source->name,
185 devices->layout->rd_width,
186 devices->rs_sattr);
187
188 if (devices->drain != NULL)
189 fprintf(outextfile, " \"%s\" %d %s",
190 devices->drain->name,
191 devices->layout->rd_width,
192 devices->rs_dattr);
193
194 fprintf(outextfile, "\n");
195 }
196 }
197 }
198 }
199
200
201 /*
202 *-------------------------------------------------------------------------
203 *
204 * ResPrintExtNode-- Prints out all the nodes in the extracted net.
205 *
206 * Results:none
207 *
208 * Side Effects: Prints out extracted net. It may add new nodes to the
209 * node hash table.
210 *
211 *-------------------------------------------------------------------------
212 */
213
214 void
ResPrintExtNode(outextfile,nodelist,nodename)215 ResPrintExtNode(outextfile, nodelist, nodename)
216 FILE *outextfile;
217 resNode *nodelist;
218 char *nodename;
219 {
220 int nodenum = 0;
221 char newname[MAXNAME], tmpname[MAXNAME], *cp;
222 HashEntry *entry;
223 ResSimNode *node, *ResInitializeNode();
224 bool DoKillNode = TRUE;
225 resNode *snode = nodelist;
226
227 /* If any of the subnode names match the original node name, then */
228 /* we don't want to rip out that node with a "killnode" statement. */
229
230 for (; nodelist != NULL; nodelist = nodelist->rn_more)
231 {
232 if (nodelist->rn_name != NULL)
233 if (!strcmp(nodelist->rn_name, nodename))
234 {
235 DoKillNode = FALSE;
236 break;
237 }
238 }
239
240 if ((ResOptionsFlags & ResOpt_DoExtFile) && DoKillNode)
241 {
242 fprintf(outextfile, "killnode \"%s\"\n", nodename);
243 }
244
245 /* Create "rnode" entries for each subnode */
246
247 for (; snode != NULL; snode = snode->rn_more)
248 {
249 if (snode->rn_name == NULL)
250 {
251 (void)sprintf(tmpname,"%s",nodename);
252
253 cp = tmpname + strlen(tmpname) - 1;
254 if (*cp == '!' || *cp == '#') *cp = '\0';
255
256 (void)sprintf(newname, "%s%s%d", tmpname, ".n", nodenum++);
257 entry = HashFind(&ResNodeTable, newname);
258 node = ResInitializeNode(entry);
259 snode->rn_name = node->name;
260 node->oldname = nodename;
261 }
262
263 if (ResOptionsFlags & ResOpt_DoExtFile)
264 {
265 /* rnode name R C x y type (R is always 0) */
266 fprintf(outextfile, "rnode \"%s\" 0 %g %d %d %d\n",
267 snode->rn_name,
268 (snode->rn_float.rn_area / ExtCurStyle->exts_capScale),
269 snode->rn_loc.p_x,
270 snode->rn_loc.p_y,
271 /* the following is TEMPORARILY set to 0 */
272 0);
273 }
274 }
275 }
276
277 /*
278 *-------------------------------------------------------------------------
279 *
280 * ResPrintStats -- Prints out the node name, the number of devices,
281 * and the number of nodes for each net added. Also keeps a running
282 * track of the totals.
283 *
284 * Results:
285 *
286 * Side Effects:
287 *
288 *-------------------------------------------------------------------------
289 */
290
291 void
ResPrintStats(goodies,name)292 ResPrintStats(goodies, name)
293 ResGlobalParams *goodies;
294 char *name;
295 {
296 static int totalnets = 0, totalnodes = 0, totalresistors = 0;
297 int nodes, resistors;
298 resNode *node;
299 resResistor *res;
300
301 if (goodies == NULL)
302 {
303 TxError("nets:%d nodes:%d resistors:%d\n",
304 totalnets, totalnodes, totalresistors);
305 totalnets = 0;
306 totalnodes = 0;
307 totalresistors = 0;
308 return;
309 }
310 nodes = 0;
311 resistors = 0;
312 totalnets++;
313 for (node = ResNodeList; node != NULL; node=node->rn_more)
314
315 {
316 nodes++;
317 totalnodes++;
318 }
319 for (res = ResResList; res != NULL; res=res->rr_nextResistor)
320 {
321 resistors++;
322 totalresistors++;
323 }
324 TxError("%s %d %d\n", name, nodes, resistors);
325 }
326
327 /*
328 *-------------------------------------------------------------------------
329 *
330 * Write the nodename to the output. If the name does not exist, the node
331 * ID number is used as the name. Assumes that node has either a valid
332 * name or valid ID record.
333 *
334 *-------------------------------------------------------------------------
335 */
336
337 void
resWriteNodeName(fp,nodeptr)338 resWriteNodeName(fp, nodeptr)
339 FILE *fp;
340 resNode *nodeptr;
341 {
342 if (nodeptr->rn_name == NULL)
343 fprintf(fp, "N%d", nodeptr->rn_id);
344 else
345 fprintf(fp, "N%s", nodeptr->rn_name);
346 }
347
348 /*
349 *-------------------------------------------------------------------------
350 *
351 * Write a description of the resistor network geometry, compatible
352 * with FastHenry (mainly for doing inductance extraction)
353 *
354 *-------------------------------------------------------------------------
355 */
356
357 void
ResPrintFHNodes(fp,nodelist,nodename,nidx,celldef)358 ResPrintFHNodes(fp, nodelist, nodename, nidx, celldef)
359 FILE *fp;
360 resNode *nodelist;
361 char *nodename;
362 int *nidx;
363 CellDef *celldef;
364 {
365 char newname[16];
366 resNode *nodeptr;
367 resResistor *resptr, *contact_res;
368 resElement *elemptr;
369 float oscale, height;
370 int np;
371
372 if (fp == NULL) return;
373
374 oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
375
376 fprintf(fp, "\n* List of nodes in network\n");
377 for (nodeptr = nodelist; nodeptr; nodeptr = nodeptr->rn_more)
378 {
379 if (nodeptr->rn_name == NULL)
380 {
381 nodeptr->rn_id = (*nidx);
382 (*nidx)++;
383 }
384 else
385 {
386 HashEntry *entry;
387 ResSimNode *simnode;
388
389 /* If we process another sim file node while doing this */
390 /* one, mark it as status "REDUNDANT" so we don't duplicate */
391 /* the entry. */
392
393 entry = HashFind(&ResNodeTable, nodeptr->rn_name);
394 simnode = (ResSimNode *)HashGetValue(entry);
395 if (simnode != NULL)
396 simnode->status |= REDUNDANT;
397 }
398 resWriteNodeName(fp, nodeptr);
399
400 /* Height of the layer is the height of the first non-contact */
401 /* layer type connected to any resistor connected to this node. */
402
403 contact_res = (resResistor *)NULL;
404 for (elemptr = nodeptr->rn_re; elemptr; elemptr = elemptr->re_nextEl)
405 {
406 resptr = elemptr->re_thisEl;
407 if (!DBIsContact(resptr->rr_tt))
408 {
409 height = ExtCurStyle->exts_height[resptr->rr_tt];
410 if (height == 0)
411 {
412 int pnum = DBPlane(resptr->rr_tt);
413 int hnum = ExtCurStyle->exts_planeOrder[pnum];
414 height = 0.1 * hnum;
415 }
416 }
417 else
418 contact_res = resptr;
419 }
420 height *= oscale;
421
422 fprintf(fp, " x=%1.2f y=%1.2f z=%1.2f\n",
423 (float)nodeptr->rn_loc.p_x * oscale,
424 (float)nodeptr->rn_loc.p_y * oscale,
425 height);
426
427 /* If it's a contact region and has more than one contact, add */
428 /* contact points as individual nodes and connect to the main */
429 /* node with an "equiv" record. */
430
431 if (contact_res != (resResistor *)NULL &&
432 (contact_res->rr_cl > 1 ||
433 contact_res->rr_width > 1))
434 {
435 int i, j, edge, spacing;
436 float del, cx, cy, cxb, cyb;
437
438 CIFGetContactSize(contact_res->rr_tt, &edge, &spacing, NULL);
439
440 del = (float)(spacing + edge) / (oscale * 100);
441
442 cxb = (float)(contact_res->rr_cl - 1) / 2;
443 for (i = 0; i < contact_res->rr_cl; i++)
444 {
445 cx = del * ((float)i - cxb);
446 cyb = (float)(contact_res->rr_width - 1) / 2;
447 for (j = 0; j < contact_res->rr_width; j++)
448 {
449 cy = del * ((float)j - cyb);
450 resWriteNodeName(fp, nodeptr);
451 fprintf(fp, "_%d_%d ", i, j);
452 fprintf(fp, "x=%1.2f y=%1.2f z=%1.2f\n",
453 ((float)nodeptr->rn_loc.p_x + cx) * oscale,
454 ((float)nodeptr->rn_loc.p_y + cy) * oscale,
455 height);
456 }
457 }
458
459 /* Short all the contact nodes together with .equiv records */
460
461 fprintf(fp, ".equiv ");
462 resWriteNodeName(fp, nodeptr);
463 for (i = 0; i < contact_res->rr_cl; i++)
464 {
465 for (j = 0; j < contact_res->rr_width; j++)
466 {
467 fprintf(fp, " ");
468 resWriteNodeName(fp, nodeptr);
469 fprintf(fp, "_%d_%d", i, j);
470 }
471 }
472 fprintf(fp, "\n");
473 }
474 }
475
476 fprintf(fp, "\n* List of externally-connected ports\n.external");
477 np = 0;
478 for (nodeptr = nodelist; nodeptr; nodeptr = nodeptr->rn_more)
479 {
480 if (nodeptr->rn_name != NULL)
481 {
482 if (np < 2)
483 {
484 Label *lab;
485
486 fprintf(fp, " N%s", nodeptr->rn_name);
487
488 /* This part is sort of a hack---need a better hook to */
489 /* the original label this external port connects to, */
490 /* rather than search for it every time we write an */
491 /* external connection. */
492
493 for (lab = celldef->cd_labels; lab != NULL; lab = lab->lab_next)
494 if (lab->lab_flags & PORT_DIR_MASK)
495 if (!strcmp(lab->lab_text, nodeptr->rn_name))
496 {
497 if (lab->lab_port != ResPortIndex)
498 {
499 lab->lab_port = ResPortIndex;
500 TxPrintf("Port %s reassigned index %d\n",
501 lab->lab_text, lab->lab_port);
502 celldef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
503 }
504 ResPortIndex++;
505 }
506 }
507 else
508 {
509 if (np == 2)
510 fprintf(fp, "\n* Warning! external nodes not recorded:");
511 fprintf(fp, " N%s", nodeptr->rn_name);
512 }
513 np++;
514 }
515 }
516 fprintf(fp, "\n\n");
517
518 /* Shouldn't this work? */
519
520 /*
521 fprintf(fp, "\n* List of externally-connected ports\n");
522 for (nodeptr = nodelist; nodeptr; nodeptr = nodeptr->rn_more)
523 if (nodeptr->rn_name != NULL)
524 fprintf(fp, ".external N%s Nsub\n", nodeptr->rn_name);
525
526 fprintf(fp, "\n");
527 */
528 }
529
530 /*
531 *-------------------------------------------------------------------------
532 * ResPrintFHRects --
533 * Generate FastHenry segment output to the FastHenry data file
534 * "fp".
535 *
536 * Results:
537 * None.
538 *
539 * Side effects:
540 * Stuff written to the stream file "fp".
541 *
542 *-------------------------------------------------------------------------
543 */
544
545 void
ResPrintFHRects(fp,reslist,nodename,eidx)546 ResPrintFHRects(fp, reslist, nodename, eidx)
547 FILE *fp;
548 resResistor *reslist;
549 char *nodename;
550 int *eidx; /* element (segment) index */
551 {
552 resResistor *resistors;
553 float oscale, thick, cwidth;
554 int edge;
555
556 if (fp == NULL) return;
557
558 oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
559
560 fprintf(fp, "* Segments connecting nodes in network\n");
561 for (resistors = reslist; resistors; resistors = resistors->rr_nextResistor)
562 {
563 if (DBIsContact(resistors->rr_tt) &&
564 (resistors->rr_cl > 1 || resistors->rr_width > 1))
565 {
566 int i, j;
567
568 CIFGetContactSize(resistors->rr_tt, &edge, NULL, NULL);
569
570 /* 100 is for centimicrons to microns conversion */
571 cwidth = (float)edge / 100;
572
573 /* for contacts, rr_cl = squares in x, rr_width = squares in y */
574
575 for (i = 0; i < resistors->rr_cl; i++)
576 {
577 for (j = 0; j < resistors->rr_width; j++)
578 {
579 fprintf(fp, "E%d ", *eidx);
580 resWriteNodeName(fp, resistors->rr_connection1);
581 fprintf(fp, "_%d_%d ", i, j);
582 resWriteNodeName(fp, resistors->rr_connection2);
583 fprintf(fp, "_%d_%d ", i, j);
584
585 /* Vias are vertical and so w and h are the dimensions of */
586 /* the via hole. For other layers, h is layer thickness. */
587
588 fprintf(fp, "w=%1.2f h=%1.2f\n", cwidth, cwidth);
589
590 (*eidx)++;
591 }
592 }
593 }
594 else
595 {
596 fprintf(fp, "E%d ", *eidx);
597 resWriteNodeName(fp, resistors->rr_connection1);
598 fprintf(fp, " ");
599 resWriteNodeName(fp, resistors->rr_connection2);
600
601 if (DBIsContact(resistors->rr_tt))
602 {
603 CIFGetContactSize(resistors->rr_tt, &edge, NULL, NULL);
604 /* 100 for centimicrons to microns conversion */
605 cwidth = (float)edge / 100;
606 fprintf(fp, " w=%1.2f h=%1.2f\n", cwidth, cwidth);
607 }
608 else
609 {
610 /* For non-via layers, h is layer thickness. */
611
612 thick = ExtCurStyle->exts_thick[resistors->rr_tt];
613 if (thick == 0) thick = 0.05;
614 fprintf(fp, " w=%1.2f h=%1.2f\n",
615 (float)resistors->rr_width * oscale,
616 thick * oscale);
617
618 }
619 (*eidx)++;
620 }
621 }
622 }
623
624 /*
625 *-------------------------------------------------------------------------
626 *
627 * ResPrintReference --
628 *
629 * Write the reference plane (substrate) definition to the geometry
630 * (FastHenry) file output.
631 *
632 * NOTE: For now, I am assuming that substrate = ground (GND).
633 * However, a device list is passed, and it should be parsed
634 * for substrate devices, allowing the creation of VDD and GND
635 * reference planes for both substrate and wells.
636 *
637 * Another note: For now, I am assuming a uniform reference
638 * plane of the size of the cell bounding box. It may be
639 * preferable to search tiles and generate multiple, connected
640 * reference planes. Or it may be desirable to have an effectively
641 * infinite reference plane by extending it far out from the
642 * subcircuit bounding box.
643 *
644 *-------------------------------------------------------------------------
645 */
646
647 void
ResPrintReference(fp,devices,cellDef)648 ResPrintReference(fp, devices, cellDef)
649 FILE *fp;
650 RDev *devices;
651 CellDef *cellDef;
652 {
653 char *outfile = cellDef->cd_name;
654 Rect *bbox = &(cellDef->cd_bbox);
655 int numsegsx, numsegsy;
656 float oscale, llx, lly, urx, ury;
657
658 oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
659 llx = (float)bbox->r_xbot * oscale;
660 lly = (float)bbox->r_ybot * oscale;
661 urx = (float)bbox->r_xtop * oscale;
662 ury = (float)bbox->r_ytop * oscale;
663
664 fprintf(fp, "* FastHenry output for magic cell %s\n\n", outfile);
665 fprintf(fp, ".Units um\n");
666 fprintf(fp, ".Default rho=0.02 nhinc=3 nwinc=3 rh=2 rw=2\n\n");
667 fprintf(fp, "* Reference plane (substrate, ground)\n");
668
669 fprintf(fp, "Gsub x1=%1.2f y1=%1.2f z1=0 x2=%1.2f y2=%1.2f z2=0\n",
670 llx, lly, urx, lly);
671 fprintf(fp, "+ x3=%1.2f y3=%1.2f z3=0\n", urx, ury);
672
673 /* Grid the reference plane at 20 lambda intervals. This */
674 /* may warrant a more rigorous treatment. 20 is arbitrary. */
675 /* Minimum number of segments is 4 (also arbitrary). */
676
677 numsegsx = (bbox->r_xtop - bbox->r_xbot) / 20;
678 numsegsy = (bbox->r_ytop - bbox->r_ybot) / 20;
679 if (numsegsx < 4) numsegsx = 4;
680 if (numsegsy < 4) numsegsy = 4;
681
682 fprintf(fp, "+ thick=0.1 seg1=%d seg2=%d\n", numsegsx, numsegsy);
683
684 fprintf(fp, "+ Ngp (%1.2f,%1.2f,0)\n", llx, lly);
685
686 fprintf(fp, "\nNsub x=%1.2f y=%1.2f z=0\n", llx, lly);
687 fprintf(fp, ".Equiv Nsub Ngp\n");
688 }
689
690 /*
691 *-------------------------------------------------------------------------
692 * ResCreateCenterlines --
693 * Generate centerline markers on the layout that correspond to
694 * network routes. Use the "DBWelement" mechanism.
695 *
696 * Results:
697 * 0 on success, -1 if a window cannot be found.
698 *
699 * Side effects:
700 * Database "line" elements are generated in the layout.
701 *
702 *-------------------------------------------------------------------------
703 */
704
705 int
ResCreateCenterlines(reslist,nidx,def)706 ResCreateCenterlines(reslist, nidx, def)
707 resResistor *reslist;
708 int *nidx;
709 CellDef *def;
710 {
711 resResistor *resistors;
712 resNode *nodeptr;
713 Rect r, rcanon;
714 MagWindow *w; /* should be passed from up in CmdExtResis. . . */
715 char name[128];
716
717 w = ToolGetBoxWindow (&r, (int *)NULL);
718 if (w == (MagWindow *)NULL)
719 windCheckOnlyWindow(&w, DBWclientID);
720 if ((w == (MagWindow *) NULL) || (w->w_client != DBWclientID)) {
721 TxError("Put the cursor in a layout window.\n");
722 return -1;
723 }
724
725 for (resistors = reslist; resistors; resistors = resistors->rr_nextResistor)
726 {
727 /* Ignore vias */
728
729 if (!DBIsContact(resistors->rr_tt))
730 {
731 nodeptr = resistors->rr_connection1;
732 r.r_xbot = nodeptr->rn_loc.p_x;
733 r.r_ybot = nodeptr->rn_loc.p_y;
734 if (nodeptr->rn_name == NULL)
735 {
736 nodeptr->rn_id = (*nidx);
737 (*nidx)++;
738 sprintf(name, "N%d_", nodeptr->rn_id);
739 }
740 else
741 sprintf(name, "N%s_", nodeptr->rn_name);
742
743 nodeptr = resistors->rr_connection2;
744 r.r_xtop = nodeptr->rn_loc.p_x;
745 r.r_ytop = nodeptr->rn_loc.p_y;
746 GeoCanonicalRect(&r, &rcanon);
747 if (nodeptr->rn_name == NULL)
748 {
749 nodeptr->rn_id = (*nidx);
750 (*nidx)++;
751 sprintf(name + strlen(name), "%d", nodeptr->rn_id);
752 }
753 else
754 strcat(name, nodeptr->rn_name);
755
756 /* Note that if any element exists with name "name" */
757 /* it will be deleted (overwritten). */
758 DBWElementAddLine(w, name, &rcanon, def, STYLE_YELLOW1);
759 }
760 }
761 return 0;
762 }
763
764