1
2 #ifndef lint
3 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResReadSim.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
4 #endif /* not lint */
5
6 /*
7 *-------------------------------------------------------------------------
8 *
9 * ResReadSim.c -- Routines to parse .sim files
10 *
11 *-------------------------------------------------------------------------
12 */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <math.h>
19
20 #include "utils/magic.h"
21 #include "utils/geometry.h"
22 #include "utils/geofast.h"
23 #include "tiles/tile.h"
24 #include "utils/hash.h"
25 #include "database/database.h"
26 #include "utils/malloc.h"
27 #include "textio/textio.h"
28 #include "extract/extract.h"
29 #include "extract/extractInt.h"
30 #include "extflat/extflat.h"
31 #include "windows/windows.h"
32 #include "dbwind/dbwind.h"
33 #include "utils/utils.h"
34 #include "utils/tech.h"
35 #include "textio/txcommands.h"
36 #include "resis/resis.h"
37
38
39 /* constants defining where various fields can be found in .sim files. */
40 #define RDEV_LENGTH 4
41 #define RDEV_WIDTH 5
42 #define RDEV_DEVX 6
43 #define RDEV_DEVY 7
44 #define RDEV_ATTR 8
45 #define RDEV_NUM_ATTR 3
46 #define RESNODENAME 1
47 #define NODERESISTANCE 2
48 #define COUPLETERMINAL1 1
49 #define COUPLETERMINAL2 2
50 #define COUPLEVALUE 3
51 #define REALNAME 1
52 #define ALIASNAME 2
53 #define NODES_NODENAME 0
54 #define NODES_NODEX 1
55 #define NODES_NODEY 2
56 #define NODES_NODETYPE 3
57 #define NODE_BBOX_LL_X 5
58 #define NODE_BBOX_LL_Y 6
59 #define NODE_BBOX_UR_X 7
60 #define NODE_BBOX_UR_Y 8
61 #define NODELAMBDA 2
62 #define NODEUNITS 1
63 #define ATTRIBUTENODENAME 1
64 #define ATTRIBUTEVALUE 2
65
66 #define RES_EXT_ATTR 0
67 #define RES_EXT_ATTR_NAME 1
68 #define RES_EXT_ATTR_X 2
69 #define RES_EXT_ATTR_Y 3
70 #define RES_EXT_ATTR_TILE 6
71 #define RES_EXT_ATTR_TEXT 7
72
73
74 #define MAXTOKEN 256
75 #define MAXLINE 40
76 #define MAXDIGIT 20
77
78
79 ResSimNode *ResInitializeNode();
80
81 ResSimNode *ResOriginalNodes; /*Linked List of Nodes */
82 static float resscale=1.0; /* Scale factor */
83 char RDEV_NOATTR[1]={'0'};
84 ResFixPoint *ResFixList;
85
86 #define nodeinit(n)\
87 {\
88 (n)->rn_more = ResNodeList;\
89 (n)->rn_less = NULL;\
90 if (ResNodeList)\
91 ResNodeList->rn_less = n;\
92 ResNodeList = n;\
93 (n)->rn_te = NULL;\
94 (n)->rn_re = NULL;\
95 (n)->rn_je = NULL;\
96 (n)->rn_ce = NULL;\
97 (n)->rn_noderes = RES_INFINITY;\
98 (n)->location.p_x = MINFINITY;\
99 (n)->location.p_y = MINFINITY;\
100 (n)->rn_why = 0;\
101 (n)->rn_status = TRUE;\
102 }
103
104 /* Forward declarations */
105
106 extern void ResSimProcessDrivePoints();
107
108 /*
109 *-------------------------------------------------------------------------
110 *
111 * ResReadSim--
112 *
113 * Results: returns 0 if sim file is correct, 1 if not.
114 *
115 * Side Effects:Reads in SimTable and makes a hash table of nodes.
116 *
117 *-------------------------------------------------------------------------
118 */
119
120 int
ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc,subproc)121 ResReadSim(simfile, fetproc, capproc, resproc, attrproc, mergeproc, subproc)
122 char *simfile;
123 int (*fetproc)(), (*capproc)(), (*resproc)();
124 int (*attrproc)(), (*mergeproc)(), (*subproc)();
125
126 {
127 char line[MAXLINE][MAXTOKEN];
128 int result, fettype, extfile;
129 FILE *fp, *fopen();
130
131 fp = PaOpen(simfile, "r", ".sim", ".", (char *)NULL, (char **)NULL);
132 if (fp == NULL)
133 {
134 TxError("Cannot open file %s%s\n", simfile, ".sim");
135 return 1;
136 }
137 extfile = 0;
138
139 /* Read in file */
140 while (gettokens(line, fp) != 0)
141 {
142 fettype = MINFINITY;
143 switch(line[0][0])
144 {
145 case '|':
146 if (strcmp(line[NODEUNITS],"units:") == 0)
147 {
148 resscale = (float)atof(line[NODELAMBDA]);
149 if (resscale == 0.0) resscale = 1.0;
150 }
151 result=0;
152 break;
153 case 'e':
154 fettype = DBTechNameType("efet");
155 break;
156 case 'd':
157 fettype = DBTechNameType("dfet");
158 break;
159 case 'n':
160 fettype = DBTechNameType("nfet");
161 break;
162 case 'p':
163 fettype = DBTechNameType("pfet");
164 break;
165 case 'b':
166 fettype = DBTechNameType("bnpn");
167 break;
168 case 'C':
169 if (capproc) result = (*capproc)(line);
170 break;
171 case 'R':
172 if (resproc) result = (*resproc)(line);
173 break;
174 case '=':
175 if (mergeproc) result = (*mergeproc)(line);
176 break;
177 case 'A':
178 if (attrproc)
179 result = (*attrproc)(line[ATTRIBUTENODENAME],
180 line[ATTRIBUTEVALUE], simfile, &extfile);
181 break;
182 case 'x':
183 fettype = DBNumTypes;
184 break;
185 case 'D':
186 case 'c':
187 case 'r':
188 break;
189 default:
190 result = 1;
191 fclose(fp);
192 break;
193 }
194 if (fettype == -1)
195 {
196 TxError("Error in Reading device line of sim file.\n");
197 result = 1;
198 }
199 else if (fettype == DBNumTypes)
200 {
201 result = (*subproc)(line);
202 }
203 else if (fettype != MINFINITY)
204 {
205 float sheetr;
206 ExtDevice *devptr;
207
208 devptr = ExtCurStyle->exts_device[fettype];
209 sheetr = (float)devptr->exts_linearResist;
210 result = (*fetproc)(line, sheetr, devptr);
211 }
212 if (result != 0)
213 {
214 TxError("Error in sim file %s\n", line[0]);
215 return 1;
216 }
217 }
218 fclose(fp);
219 return(result);
220 }
221
222
223 /*
224 *-------------------------------------------------------------------------
225 *
226 * ResReadNode-- Reads in a node file, puts location of nodes into node
227 * structures.
228 *
229 * Results: returns 0 if nodes file is correct, 1 if not.
230 *
231 * Side Effects:see above
232 *
233 *-------------------------------------------------------------------------
234 */
235
236 int
ResReadNode(nodefile)237 ResReadNode(nodefile)
238 char *nodefile;
239 {
240 char line[MAXLINE][MAXTOKEN];
241 FILE *fp, *fopen();
242 HashEntry *entry;
243 ResSimNode *node;
244 char *cp;
245 float lambda;
246
247 fp = PaOpen(nodefile, "r", ".nodes", ".", (char *)NULL, (char **)NULL);
248 if (fp == NULL)
249 {
250 TxError("Cannot open file %s%s\n", nodefile, ".nodes");
251 return 1;
252 }
253 while (gettokens(line,fp) != 0)
254 {
255 entry = HashFind(&ResNodeTable, line[NODES_NODENAME]);
256 node = ResInitializeNode(entry);
257
258 node->location.p_x = atoi(line[NODES_NODEX]);
259 node->location.p_y = atoi(line[NODES_NODEY]);
260 #ifdef ARIEL
261 node->rs_bbox.r_xbot = atoi(line[NODE_BBOX_LL_X]);
262 node->rs_bbox.r_ybot = atoi(line[NODE_BBOX_LL_Y]);
263 node->rs_bbox.r_xtop = atoi(line[NODE_BBOX_UR_X]);
264 node->rs_bbox.r_ytop = atoi(line[NODE_BBOX_UR_Y]);
265 #endif
266 if (cp = strchr(line[NODES_NODETYPE], ';')) *cp = '\0';
267 node->type = DBTechNameType(line[NODES_NODETYPE]);
268
269 if (node->type == -1)
270 {
271 TxError("Bad tile type name in %s.nodes file for node %s\n",
272 nodefile, node->name);
273 TxError("Did you use the newest version of ext2sim?\n");
274 fclose(fp);
275 return 1;
276 }
277 }
278 fclose(fp);
279 return 0;
280 }
281
282 /*
283 *-------------------------------------------------------------------------
284 *
285 * getline-- Gets a line from the current input file and breaks it into
286 * tokens.
287 *
288 * Results:returns the number of tokens in the current line
289 *
290 * Side Effects: loads up its input line with the tokens.
291 *
292 *-------------------------------------------------------------------------
293 */
294
295 int
gettokens(line,fp)296 gettokens(line, fp)
297 char line[][MAXTOKEN];
298 FILE *fp;
299 {
300 int i = 0, j = 0;
301 int c;
302
303 while ((c = getc(fp)) != EOF && c != '\n')
304 {
305 switch(c)
306 {
307 case ' ':
308 case ' ' :
309 line[i++][j] = '\0';
310 j = 0;
311 break;
312 default:
313 line[i][j++] = c;
314 break;
315 }
316 }
317 if (c == '\n')
318 {
319 line[i++][j] = '\0';
320 j = 0;
321 }
322 for (j = i; j < MAXLINE; j++)
323 line[j][0] = '\0';
324
325 return i;
326 }
327
328 /*
329 *-------------------------------------------------------------------------
330 *
331 * ResSimSubckt-- Processes a subcircuit line from a sim file.
332 * This uses the "user subcircuit" extension defined in
333 * IRSIM, although it is mostly intended as a way to work
334 * around the device type limitations of the .sim format
335 * when using extresist.
336 *
337 * Results: returns 0 if line was added correctly.
338 *
339 * Side Effects: Allocates devices and adds nodes to the node hash table.
340 *
341 *-------------------------------------------------------------------------
342 */
343
344 int
ResSimSubckt(line)345 ResSimSubckt(line)
346 char line[][MAXTOKEN];
347 {
348 RDev *device;
349 int rvalue, i, j, k;
350 static int nowarning = TRUE;
351 float lambda;
352 TileType ttype = TT_SPACE;
353 char *lptr = NULL, *wptr = NULL;
354 ExtDevice *devptr;
355
356 device = (RDev *) mallocMagic((unsigned) (sizeof(RDev)));
357
358 device->status = FALSE;
359 device->nextDev = ResRDevList;
360
361 lambda = (float)ExtCurStyle->exts_unitsPerLambda / resscale;
362 device->location.p_x = 0;
363 device->location.p_y = 0;
364
365 device->rs_gattr=RDEV_NOATTR;
366 device->rs_sattr=RDEV_NOATTR;
367 device->rs_dattr=RDEV_NOATTR;
368
369 ResRDevList = device;
370 device->layout = NULL;
371 device->source = device->drain = device->gate = device->subs = NULL;
372
373 /* The last argument is the name of the device */
374 for (i = 1; line[i][0] != '\0'; i++);
375 i--;
376
377 /* To do: Replace this search with a pre-prepared hash */
378 /* table to key off of the device name. */
379 for (j = 0; j < EFDevNumTypes; j++)
380 if (!strcmp(EFDevTypes[j], line[i]))
381 break;
382
383 /* Read attributes, especially to pick up values for L, W, X, and Y,
384 * that are critical for use by extresist.
385 */
386 for (k = 1; line[k][0] != '\0'; k++)
387 {
388 char *eqptr;
389 eqptr = strchr(line[k], '=');
390 if (eqptr != NULL)
391 {
392 if (k < i) i = k;
393 eqptr++;
394 switch (line[k][0]) {
395 case 'l':
396 lptr = eqptr;
397 break;
398 case 'w':
399 wptr = eqptr;
400 break;
401 case 'x':
402 device->location.p_x = (int)((float)atof(eqptr) / lambda);
403 break;
404 case 'y':
405 device->location.p_y = (int)((float)atof(eqptr) / lambda);
406 break;
407 }
408 }
409 }
410
411 if (j == EFDevNumTypes)
412 {
413 TxError("Failure to find device type %s\n", line[i]);
414 return 1;
415 }
416 ttype = extGetDevType(EFDevTypes[j]);
417
418 /* Find the device record that corresponds to the device name */
419 for (devptr = ExtCurStyle->exts_device[ttype]; devptr; devptr = devptr->exts_next)
420 if (!strcmp(devptr->exts_deviceName, EFDevTypes[j]))
421 break;
422
423 device->rs_devptr = devptr;
424 device->rs_ttype = ttype;
425
426 if (lptr != NULL && wptr != NULL)
427 {
428 float rpersquare;
429
430 rpersquare =(float)devptr->exts_linearResist;
431 /* Subcircuit types may not have a length or width value, in which */
432 /* case it is zero. Don't induce a divide-by-zero error. */
433 if (MagAtof(wptr) == 0)
434 device->resistance = 0;
435 else
436 device->resistance = MagAtof(lptr) * rpersquare/MagAtof(wptr);
437 }
438 else
439 device->resistance = 0;
440
441 rvalue = 0;
442 for (k = 1; k < i; k++)
443 {
444 if (k > SUBS)
445 {
446 TxError("Device %s has more than 4 ports (not handled).\n", line[i]);
447 break; /* No method to handle more ports than this */
448 }
449 rvalue += ResSimNewNode(line[k], k, device);
450 }
451
452 return rvalue;
453 }
454
455 /*
456 *-------------------------------------------------------------------------
457 *
458 * ResSimDevice-- Processes a device line from a sim file.
459 *
460 * Results: returns 0 if line was added correctly.
461 *
462 * Side Effects: Allocates devices and adds nodes to the node hash table.
463 *
464 *-------------------------------------------------------------------------
465 */
466
467 int
ResSimDevice(line,rpersquare,devptr)468 ResSimDevice(line, rpersquare, devptr)
469 char line[][MAXTOKEN];
470 float rpersquare;
471 ExtDevice *devptr;
472
473 {
474 RDev *device;
475 int rvalue, i, j, k;
476 char *newattr, tmpattr[MAXTOKEN];
477 static int nowarning = TRUE;
478 float lambda;
479
480 if ((line[RDEV_WIDTH][0] == '\0') || (line[RDEV_LENGTH][0] == '\0'))
481 {
482 TxError("error in input file:\n");
483 return 1;
484 }
485
486 device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
487 if (nowarning && rpersquare == 0)
488 {
489 TxError("Warning: FET resistance not included or "
490 "set to zero in technology file-\n");
491 TxError("All driven nodes will be extracted\n");
492 nowarning = FALSE;
493 }
494 if (MagAtof(line[RDEV_WIDTH]) != 0)
495 device->resistance = MagAtof(line[RDEV_LENGTH]) * rpersquare /
496 MagAtof(line[RDEV_WIDTH]);
497 else
498 device->resistance = 0;
499
500 device->status = FALSE;
501 device->nextDev = ResRDevList;
502
503 lambda = (float)ExtCurStyle->exts_unitsPerLambda / resscale;
504 device->location.p_x = (int)((float)atof(line[RDEV_DEVX]) / lambda);
505 device->location.p_y = (int)((float)atof(line[RDEV_DEVY]) / lambda);
506
507 device->rs_gattr=RDEV_NOATTR;
508 device->rs_sattr=RDEV_NOATTR;
509 device->rs_dattr=RDEV_NOATTR;
510 device->rs_devptr = devptr;
511
512 device->gate = device->source = device->drain = device->subs = NULL;
513
514 device->rs_ttype = extGetDevType(devptr->exts_deviceName);
515
516 /* sim attributes look like g=a1,a2 */
517 /* ext attributes are "a1","a2" */
518 /* do conversion from one to the other here */
519
520 for (i = RDEV_ATTR; i < RDEV_ATTR + RDEV_NUM_ATTR; i++)
521 {
522 if (line[i][0] == '\0') break;
523 k = 0;
524 tmpattr[k++] = '"';
525 for (j = 2; line[i][j] != '\0'; j++)
526 {
527 if (line[i][j] == ',')
528 {
529 tmpattr[k++] = '"';
530 tmpattr[k++] = ',';
531 tmpattr[k++] = '"';
532 }
533 else
534 {
535 tmpattr[k++] = line[i][j];
536 }
537 }
538 tmpattr[k++] = '"';
539 tmpattr[k++] = '\0';
540 newattr = (char *)mallocMagic((unsigned)k);
541 strncpy(newattr, tmpattr, k);
542 switch (line[i][0])
543 {
544 case 'g':
545 device->rs_gattr = newattr;
546 break;
547 case 's':
548 device->rs_sattr = newattr;
549 break;
550 case 'd':
551 device->rs_dattr = newattr;
552 break;
553 default:
554 TxError("Bad fet attribute\n");
555 break;
556 }
557 }
558 ResRDevList = device;
559 device->layout = NULL;
560 rvalue = ResSimNewNode(line[GATE], GATE, device) +
561 ResSimNewNode(line[SOURCE], SOURCE, device) +
562 ResSimNewNode(line[DRAIN], DRAIN, device);
563
564 return rvalue;
565 }
566
567 /*
568 *-------------------------------------------------------------------------
569 *
570 * ResSimNewNode-- Adds a new node to the Node Hash Table.
571 *
572 * Results: returns zero if node is added correctly, one otherwise.
573 *
574 * Side Effects: Allocates a new ResSimNode
575 *
576 *-------------------------------------------------------------------------
577 */
578
579 int
ResSimNewNode(line,type,device)580 ResSimNewNode(line, type, device)
581 char line[];
582 int type;
583 RDev *device;
584
585 {
586 HashEntry *entry;
587 ResSimNode *node;
588 devPtr *tptr;
589
590 if (line[0] == '\0')
591 {
592 TxError("Missing device connection\n");
593 return 1;
594 }
595 entry = HashFind(&ResNodeTable, line);
596 node = ResInitializeNode(entry);
597 tptr = (devPtr *)mallocMagic((unsigned)(sizeof(devPtr)));
598 tptr->thisDev = device;
599 tptr->nextDev = node->firstDev;
600 node->firstDev = tptr;
601 tptr->terminal = type;
602 switch(type)
603 {
604 case GATE:
605 device->gate = node;
606 break;
607 case SOURCE:
608 device->source = node;
609 break;
610 case DRAIN:
611 device->drain = node;
612 break;
613 case SUBS:
614 device->subs = node;
615 break;
616 default:
617 TxError("Bad Terminal Specifier\n");
618 break;
619 }
620 return 0;
621 }
622
623 /*
624 *-------------------------------------------------------------------------
625 *
626 * ResSimCapacitor-- Adds the capacitance from a C line to the appropriate
627 * node. Coupling capacitors are added twice, moving the capacitance
628 * to the substrate.
629 *
630 * Results:
631 * Always return 0
632 *
633 * Side Effects: modifies capacitance field of ResSimNode.
634 *
635 *-------------------------------------------------------------------------
636 */
637
638 int
ResSimCapacitor(line)639 ResSimCapacitor(line)
640 char line[][MAXTOKEN];
641
642 {
643 HashEntry *entry1, *entry2;
644 ResSimNode *node1, *node2;
645
646 if (line[COUPLETERMINAL1][0] == 0 || line[COUPLETERMINAL2][0] == 0)
647 {
648 TxError("Bad Capacitor\n");
649 return(1);
650 }
651 entry1 = HashFind(&ResNodeTable, line[COUPLETERMINAL1]);
652 node1 = ResInitializeNode(entry1);
653 if (ResOptionsFlags & ResOpt_Signal)
654 {
655 node1->capacitance += MagAtof(line[COUPLEVALUE]);
656 if (strcmp(line[COUPLETERMINAL2], "GND") == 0 ||
657 strcmp(line[COUPLETERMINAL2], "Vdd") == 0)
658 {
659 return 0;
660 }
661 entry2 = HashFind(&ResNodeTable, line[COUPLETERMINAL2]);
662 node2 = ResInitializeNode(entry2);
663 node2->capacitance += MagAtof(line[COUPLEVALUE]);
664 return 0;
665 }
666 if (strcmp(line[COUPLETERMINAL2], "GND") == 0)
667 {
668 node1->capacitance += MagAtof(line[COUPLEVALUE]);
669 return 0;
670 }
671 if (strcmp(line[COUPLETERMINAL2], "Vdd") == 0)
672 {
673 node1->cap_vdd += MagAtof(line[COUPLEVALUE]);
674 return 0;
675 }
676 entry2 = HashFind(&ResNodeTable, line[COUPLETERMINAL2]);
677 node2 = ResInitializeNode(entry2);
678 if (strcmp(line[COUPLETERMINAL1], "GND") == 0)
679 {
680 node2->capacitance += MagAtof(line[COUPLEVALUE]);
681 return 0;
682 }
683 if (strcmp(line[COUPLETERMINAL1], "Vdd") == 0)
684 {
685 node2->cap_vdd += MagAtof(line[COUPLEVALUE]);
686 return 0;
687 }
688 node1->cap_couple += MagAtof(line[COUPLEVALUE]);
689 node2->cap_couple += MagAtof(line[COUPLEVALUE]);
690 return 0;
691 }
692
693
694 /*
695 *-------------------------------------------------------------------------
696 *
697 * ResSimResistor-- Adds the capacitance from a R line to the appropriate
698 * node.
699 *
700 * Results
701 * Return 0 to keep search going, 1 to abort
702 *
703 * Side Effects: modifies resistance field of ResSimNode
704 *
705 *-------------------------------------------------------------------------
706 */
707
708 int
ResSimResistor(line)709 ResSimResistor(line)
710 char line[][MAXTOKEN];
711 {
712 HashEntry *entry;
713 ResSimNode *node;
714
715 if (line[RESNODENAME][0] == 0)
716 {
717 TxError("Bad Resistor\n");
718 return 1;
719 }
720 entry = HashFind(&ResNodeTable, line[RESNODENAME]);
721 node = ResInitializeNode(entry);
722 if (node->resistance != 0)
723 {
724 TxError("Duplicate Resistance Entries\n");
725 return 1;
726 }
727 node->resistance = MagAtof(line[NODERESISTANCE]);
728 return(0);
729 }
730
731 /*
732 *-------------------------------------------------------------------------
733 *
734 * ResSimAttribute--checks to see if a node attribute is a resistance
735 * attribute. If it is, add it to the correct node's status flag.
736 * Only works with 5.0 1/line attributes
737 *
738 * Results:
739 * Return 0 to keep search going, 1 to abort
740 *
741 * Side Effects: modifies resistance field of ResSimNode
742 *
743 *-------------------------------------------------------------------------
744 */
745
746 int
ResSimAttribute(aname,avalue,rootname,readextfile)747 ResSimAttribute(aname, avalue, rootname, readextfile)
748 char *aname, *avalue, *rootname;
749 int *readextfile;
750
751 {
752 HashEntry *entry;
753 ResSimNode *node;
754 char digit[MAXDIGIT];
755 int i;
756 static int notwarned=TRUE;
757
758 if (aname[0] == 0)
759 {
760 TxError("Bad Resistor\n");
761 return 1;
762 }
763 entry = HashFind(&ResNodeTable, aname);
764 node = ResInitializeNode(entry);
765 if (strncmp(avalue, "res:skip", 8) == 0)
766 {
767 if (node->status & FORCE)
768 {
769 TxError("Warning: Node %s is both forced and skipped\n", aname);
770 }
771 else
772 {
773 node->status |= SKIP;
774 }
775 }
776 else if (strncmp(avalue, "res:force", 9) == 0)
777 {
778 if (node->status & SKIP)
779 {
780 TxError("Warning: Node %s is both skipped and forced \n", aname);
781 }
782 else
783 {
784 node->status |= FORCE;
785 }
786 }
787 else if (strncmp(avalue, "res:min=", 8) == 0)
788 {
789 node->status |= MINSIZE;
790 for (i = 0, avalue += 8; *avalue != '\0' && *avalue != ','; avalue++)
791 {
792 digit[i++] = *avalue;
793 }
794 digit[i++] = '\0';
795 node->minsizeres = MagAtof(digit);
796 }
797 else if (strncmp(avalue, "res:drive", 9) == 0 &&
798 (ResOptionsFlags & ResOpt_Signal))
799 {
800 if (*readextfile == 0)
801 {
802 ResSimProcessDrivePoints(rootname);
803 *readextfile = 1;
804 }
805 /* is the attribute in root.ext? */
806 if (node->drivepoint.p_x != INFINITY)
807 {
808 node->status |= DRIVELOC;
809 }
810 else
811 {
812 if (notwarned)
813 TxError("Drivepoint for %s not defined in %s.ext; is it "
814 "defined in a child cell?\n", node->name, rootname);
815 notwarned = FALSE;
816 }
817 }
818 #ifdef ARIEL
819 else if (strncmp(avalue, "res:fix", 7) == 0 &&
820 (ResOptionsFlags & ResOpt_Power))
821 {
822 if (*readextfile == 0)
823 {
824 ResSimProcessFixPoints(rootname);
825 *readextfile = 1;
826 }
827 }
828 #endif
829 if (avalue = strchr(avalue, ','))
830 {
831 ResSimAttribute(aname, avalue + 1, rootname, readextfile);
832 }
833 return 0;
834 }
835
836 /*
837 *-------------------------------------------------------------------------
838 *
839 * ResSimProcessDrivePoints -- if the sim file contains a res:drive attribute,
840 * and we are doing a signal extraction,
841 * we need to search through the .ext file looking for attr labels that
842 * contain this text. For efficiency, the .ext file is only parsed when
843 * the first res:drive is encountered. res:drive labels only work if
844 * they are in the root cell.
845 *
846 * Results:
847 * None.
848 *
849 * Side Effects:
850 *
851 *-------------------------------------------------------------------------
852 */
853
854 void
ResSimProcessDrivePoints(filename)855 ResSimProcessDrivePoints(filename)
856 char *filename;
857
858 {
859 char line[MAXLINE][MAXTOKEN];
860 FILE *fp;
861 HashEntry *entry;
862 ResSimNode *node;
863
864 fp = PaOpen(filename, "r", ".ext", ".", (char *)NULL, (char **)NULL);
865 if (fp == NULL)
866 {
867 TxError("Cannot open file %s%s\n", filename, ".ext");
868 return;
869 }
870 while (gettokens(line,fp) != 0)
871 {
872 if (strncmp(line[RES_EXT_ATTR], "attr", 4) != 0 ||
873 strncmp(line[RES_EXT_ATTR_TEXT], "\"res:drive\"", 11) != 0)
874 continue;
875
876 entry = HashFind(&ResNodeTable, line[RES_EXT_ATTR_NAME]);
877 node = ResInitializeNode(entry);
878 node->drivepoint.p_x = atoi(line[RES_EXT_ATTR_X]);
879 node->drivepoint.p_y = atoi(line[RES_EXT_ATTR_Y]);
880 node->rs_ttype = DBTechNoisyNameType(line[RES_EXT_ATTR_TILE]);
881 }
882 }
883
884 /*
885 *-------------------------------------------------------------------------
886 *
887 * ResSimProcessFixPoints -- if the sim file contains a "res:fix:name" label
888 * and we are checking for power supply noise, then we have to
889 * parse the .ext file looking for the fix label locations. This
890 * is only done after the first res:fix label is encountered.
891 *
892 *
893 * Results:
894 * None.
895 *
896 * Side Effects:
897 * For each new name, allocate memory
898 *
899 *-------------------------------------------------------------------------
900 */
901
902 void
ResSimProcessFixPoints(filename)903 ResSimProcessFixPoints(filename)
904 char *filename;
905 {
906 char line[MAXLINE][MAXTOKEN], *label, *c;
907 FILE *fp;
908 ResFixPoint *thisfix;
909
910 fp = PaOpen(filename, "r", ".ext", ".", (char *)NULL, (char **)NULL);
911 if (fp == NULL)
912 {
913 TxError("Cannot open file %s%s\n", filename, ".ext");
914 return;
915 }
916 while (gettokens(line, fp) != 0)
917 {
918 if (strncmp(line[RES_EXT_ATTR], "attr", 4) != 0 ||
919 strncmp(line[RES_EXT_ATTR_TEXT], "\"res:fix", 8) != 0)
920 continue;
921 label = line[RES_EXT_ATTR_TEXT];
922 label += 8;
923 if (*label == ':') label++;
924 if ((c=strrchr(label, '"')) != NULL) *c = '\0';
925 else if (*label != '\0')
926 {
927 TxError("Bad res:fix attribute label %s\n",
928 line[RES_EXT_ATTR_TEXT]);
929 *label ='\0';
930 }
931 thisfix = (ResFixPoint *)mallocMagic((unsigned)(sizeof(ResFixPoint)
932 + strlen(label)));
933 thisfix->fp_next = ResFixList;
934 ResFixList = thisfix;
935 thisfix->fp_loc.p_x = atoi(line[RES_EXT_ATTR_X]);
936 thisfix->fp_loc.p_y = atoi(line[RES_EXT_ATTR_Y]);
937 thisfix->fp_ttype = DBTechNoisyNameType(line[RES_EXT_ATTR_TILE]);
938 thisfix->fp_tile = NULL;
939 strcpy(thisfix->fp_name, label);
940 }
941 }
942
943
944 /*
945 *-------------------------------------------------------------------------
946 *
947 * ResSimMerge-- Processes = line in sim file
948 *
949 * Results: Success/Failure
950 *
951 * Side Effects: The forward field of one node is set to point to the
952 * other node. All of the junkt from the first node is moved to
953 * the second node.
954 *
955 *-------------------------------------------------------------------------
956 */
957
958 int
ResSimMerge(line)959 ResSimMerge(line)
960 char line[][MAXTOKEN];
961
962 {
963 ResSimNode *node;
964 devPtr *ptr;
965
966 if ((line[ALIASNAME][0] == '\0') || (line[REALNAME][0] == '\0'))
967 {
968 TxError("Bad node alias line\n");
969 return(1);
970 }
971 node = ResInitializeNode(HashFind(&ResNodeTable, line[ALIASNAME]));
972 node->status |= FORWARD;
973 node->forward = ResInitializeNode(HashFind(&ResNodeTable, line[REALNAME]));
974 node->forward->resistance += node->resistance;
975 node->forward->capacitance += node->capacitance;
976 while (node->firstDev != NULL)
977 {
978 ptr = node->firstDev;
979 node->firstDev = node->firstDev->nextDev;
980 ptr->nextDev = node->forward->firstDev;
981 node->forward->firstDev = ptr;
982 }
983 return 0;
984 }
985
986 /*
987 *-------------------------------------------------------------------------
988 *
989 * ResInitializeNode-- Gets the node corresponding to a given hash table
990 * entry. If no such node exists, one is created.
991 *
992 * Results:Returns ResSimNode corresponding to entry.
993 *
994 * Side Effects: May allocate a new ResSimNode.
995 *
996 *-------------------------------------------------------------------------
997 */
998
999 ResSimNode *
ResInitializeNode(entry)1000 ResInitializeNode(entry)
1001 HashEntry *entry;
1002 {
1003 ResSimNode *node;
1004
1005 if ((node = (ResSimNode *) HashGetValue(entry)) == NULL)
1006 {
1007 node = (ResSimNode *)mallocMagic((unsigned)(sizeof(ResSimNode)));
1008 HashSetValue(entry, (char *) node);
1009 node->nextnode = ResOriginalNodes;
1010 ResOriginalNodes = node;
1011 node->status = FALSE;
1012 node->forward = (ResSimNode *) NULL;
1013 node->capacitance = 0;
1014 node->cap_vdd = 0;
1015 node->cap_couple = 0;
1016 node->resistance = 0;
1017 node->type = 0;
1018 node->firstDev = NULL;
1019 node->name = entry->h_key.h_name;
1020 node->oldname = NULL;
1021 node->drivepoint.p_x = INFINITY;
1022 node->drivepoint.p_y = INFINITY;
1023 node->location.p_x = INFINITY;
1024 node->location.p_y = INFINITY;
1025 node->rs_sublist[0] = NULL;
1026 node->rs_sublist[1] = NULL;
1027 }
1028 while (node->status & FORWARD)
1029 {
1030 node = node->forward;
1031 }
1032 return node;
1033 }
1034