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