1 /*
2  * readdef.c --
3  *
4  * This module incorporates the LEF/DEF format for standard-cell place and
5  * route.
6  *
7  * Version 0.1 (September 26, 2003):  DEF input of designs.
8  *
9  * Written by Tim Edwards, Open Circuit Design
10  * Modified April 2013 for use with qrouter
11  * Modified December 2018 for use with qflow (DEF2Verilog, back-annotate verilog
12  * netlist from DEF output).
13  *
14  * It is assumed that the LEF files have been read in prior to this, and
15  * layer information is already known.  The DEF file should have information
16  * primarily on die are, track placement, pins, components, and nets.
17  *
18  * Routed nets have their routes dropped into track obstructions, and the
19  * nets are ignored.
20  *
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <stdarg.h>
29 #include <math.h>		/* for roundf() function, if std=c99 */
30 
31 #include "readlef.h"
32 #include "readdef.h"
33 #include "hash.h"
34 
35 int numSpecial = 0;		/* Tracks number of specialnets */
36 int Numnets = 0;		/* Total nets, including special nets */
37 int Numgates = 0;		/* Number of components */
38 int Numpins = 0;		/* Number of pins */
39 
40 /* These hash tables speed up DEF file reading */
41 
42 struct hashtable InstanceTable;
43 struct hashtable NetTable;
44 struct hashtable RowTable;
45 char *DEFDesignName;
46 
47 DSEG UserObs = NULL;
48 double Xlowerbound = 0, Xupperbound = 0, Ylowerbound = 0, Yupperbound = 0;
49 double PitchX = 1.0, PitchY = 1.0;
50 NET *Nlnets = NULL;
51 GATE Nlgates = NULL;
52 GATE PinMacro;
53 
54 /*--------------------------------------------------------------*/
55 /* Cell macro lookup based on the hash table			*/
56 /*--------------------------------------------------------------*/
57 
58 static void
DefHashInit(void)59 DefHashInit(void)
60 {
61    /* Initialize the macro hash table */
62 
63    InitializeHashTable(&InstanceTable, LARGEHASHSIZE);
64    InitializeHashTable(&NetTable, LARGEHASHSIZE);
65    InitializeHashTable(&RowTable, TINYHASHSIZE);
66 }
67 
68 GATE
DefFindGate(char * name)69 DefFindGate(char *name)
70 {
71     GATE ginst;
72 
73     ginst = (GATE)HashLookup(name, &InstanceTable);
74     return ginst;
75 }
76 
77 ROW
DefFindRow(int yval)78 DefFindRow(int yval)
79 {
80     ROW row;
81     char namepos[32];
82 
83     sprintf(namepos, "%d", yval);
84     row = (ROW)HashLookup(namepos, &RowTable);
85     return row;
86 }
87 
88 /*--------------------------------------------------------------*/
89 /* Find the lowest row and return the row record.		*/
90 /*--------------------------------------------------------------*/
91 
rowfindlowest(struct hashlist * p,void * clientdata)92 struct nlist *rowfindlowest(struct hashlist *p, void *clientdata)
93 {
94     ROW row = (ROW)(p->ptr);
95     ROW *lrow = (ROW *)clientdata;
96 
97     if ((*lrow == NULL) || (row->y < (*lrow)->y))
98 	*lrow = row;
99 
100     return NULL;
101 }
102 
103 /*--------------------------------------------------------------*/
104 
105 ROW
DefLowestRow()106 DefLowestRow()
107 {
108     ROW row = NULL;
109 
110     RecurseHashTablePointer(&RowTable, rowfindlowest, (void *)(&row));
111 
112     return row;
113 }
114 
115 /*--------------------------------------------------------------*/
116 
117 NET
DefFindNet(char * name)118 DefFindNet(char *name)
119 {
120     NET net;
121 
122     // Guard against calls to find nets before DEF file is read
123     if (Numnets == 0) return NULL;
124 
125     net = (NET)HashLookup(name, &NetTable);
126     return net;
127 }
128 
129 /*--------------------------------------------------------------*/
130 /* Cell macro hash table generation				*/
131 /* Given an instance record, create an entry in the hash table	*/
132 /* for the instance name, with the record entry pointing to the	*/
133 /* instance record.						*/
134 /*--------------------------------------------------------------*/
135 
136 static void
DefHashInstance(GATE gateginfo)137 DefHashInstance(GATE gateginfo)
138 {
139     HashPtrInstall(gateginfo->gatename, gateginfo, &InstanceTable);
140 }
141 
142 /*--------------------------------------------------------------*/
143 
144 char *
DefDesign()145 DefDesign()
146 {
147     return DEFDesignName;
148 }
149 
150 /*--------------------------------------------------------------*/
151 /* Net hash table generation					*/
152 /* Given a net record, create an entry in the hash table for	*/
153 /* the net name, with the record entry pointing to the net	*/
154 /* record.							*/
155 /*--------------------------------------------------------------*/
156 
157 static void
DefHashNet(NET net)158 DefHashNet(NET net)
159 {
160     HashPtrInstall(net->netname, net, &NetTable);
161 }
162 
163 /*
164  *------------------------------------------------------------
165  *
166  * DefAddRoutes --
167  *
168  *	Parse a network route statement from the DEF file.
169  *	If "special" is 1, then, add the geometry to the
170  *	list of obstructions.  If "special" is 0, then read
171  *	the geometry into a route structure for the net.
172  *
173  * Results:
174  *	Returns the last token encountered.
175  *
176  * Side Effects:
177  *	Reads from input stream;
178  *	Adds information to the layout database.
179  *
180  *------------------------------------------------------------
181  */
182 
183 static char *
DefAddRoutes(FILE * f,float oscale,NET net,char special)184 DefAddRoutes(FILE *f, float oscale, NET net, char special)
185 {
186     char *token;
187     DSEG lr, drect;
188     struct point_ refp;
189     char valid = FALSE;		/* is there a valid reference point? */
190     char noobstruct;
191     char initial = TRUE;
192     struct dseg_ locarea;
193     double x, y, lx, ly, w, hw, s;
194     int routeLayer = -1, paintLayer;
195     LefList lefl;
196 
197     refp.x1 = 0;
198     refp.y1 = 0;
199 
200     /* Don't create obstructions or routes on routed specialnets inputs	*/
201     noobstruct = (special == (char)1) ? TRUE : FALSE;
202 
203     while (initial || (token = LefNextToken(f, TRUE)) != NULL)
204     {
205 	/* Get next point, token "NEW", or via name */
206 	if (initial || !strcmp(token, "NEW") || !strcmp(token, "new"))
207 	{
208 	    /* initial pass is like a NEW record, but has no NEW keyword */
209 	    initial = FALSE;
210 
211 	    /* invalidate reference point */
212 	    valid = FALSE;
213 
214 	    token = LefNextToken(f, TRUE);
215 	    routeLayer = LefFindLayerNum(token);
216 
217 	    if (routeLayer < 0)
218 	    {
219 		LefError(DEF_ERROR, "Unknown layer type \"%s\" for NEW route\n", token);
220 		continue;
221 	    }
222 	    paintLayer = routeLayer;
223 
224 	    if (special == (char)1)
225 	    {
226 		/* SPECIALNETS has the additional width */
227 		token = LefNextToken(f, TRUE);
228 		if (sscanf(token, "%lg", &w) != 1)
229 		{
230 		    LefError(DEF_ERROR, "Bad width in special net\n");
231 		    continue;
232 		}
233 		if (w != 0)
234 		    w /= oscale;
235 		else
236 		    w = LefGetRouteWidth(paintLayer);
237 	    }
238 	    else
239 		w = LefGetRouteWidth(paintLayer);
240 
241 	}
242 	else if (*token != '(')	/* via name */
243 	{
244 	    /* A '+' or ';' record ends the route */
245 	    if (*token == ';' || *token == '+')
246 		break;
247 
248 	    else if (valid == FALSE)
249 	    {
250 		LefError(DEF_ERROR, "Route has via name \"%s\" but no points!\n", token);
251 		continue;
252 	    }
253 	    lefl = LefFindLayer(token);
254 	    if (lefl != NULL)
255 	    {
256 		/* The area to paint is derived from the via definitions. */
257 
258 		if (lefl != NULL)
259 		{
260 		    if (lefl->lefClass == CLASS_VIA) {
261 
262 			// Note: layers may be defined in any order, metal or cut.
263 			// Check both via.area and via.lr layers, and reject those
264 			// that exceed the number of metal layers (those are cuts).
265 
266 			paintLayer = 100;
267 			routeLayer = -1;
268 			routeLayer = lefl->info.via.area.layer;
269 			if (routeLayer < paintLayer) paintLayer = routeLayer;
270 			if ((routeLayer >= 0) && (special == (char)1) &&
271 					(valid == TRUE) && (noobstruct == FALSE)) {
272 			    s = LefGetRouteSpacing(routeLayer);
273 			    drect = (DSEG)malloc(sizeof(struct dseg_));
274 			    drect->x1 = x + (lefl->info.via.area.x1 / 2.0) - s;
275 			    drect->x2 = x + (lefl->info.via.area.x2 / 2.0) + s;
276 			    drect->y1 = y + (lefl->info.via.area.y1 / 2.0) - s;
277 			    drect->y2 = y + (lefl->info.via.area.y2 / 2.0) + s;
278 			    drect->layer = routeLayer;
279 			    drect->next = UserObs;
280 			    UserObs = drect;
281 			}
282 			for (lr = lefl->info.via.lr; lr; lr = lr->next) {
283 			   routeLayer = lr->layer;
284 			   if (routeLayer < paintLayer) paintLayer = routeLayer;
285 			   if ((routeLayer >= 0) && (special == (char)1) &&
286 					(valid == TRUE) && (noobstruct == FALSE)) {
287 				s = LefGetRouteSpacing(routeLayer);
288 				drect = (DSEG)malloc(sizeof(struct dseg_));
289 				drect->x1 = x + (lr->x1 / 2.0) - s;
290 				drect->x2 = x + (lr->x2 / 2.0) + s;
291 				drect->y1 = y + (lr->y1 / 2.0) - s;
292 				drect->y2 = y + (lr->y2 / 2.0) + s;
293 				drect->layer = routeLayer;
294 				drect->next = UserObs;
295 				UserObs = drect;
296 			   }
297 			}
298 			if (routeLayer == -1) paintLayer = lefl->type;
299 		    }
300 		    else {
301 		    	paintLayer = lefl->type;
302 			if (special == (char)1)
303 			    s = LefGetRouteSpacing(paintLayer);
304 		    }
305 		}
306 		else
307 		{
308 		    LefError(DEF_ERROR, "Error: Via \"%s\" named but undefined.\n", token);
309 		    paintLayer = routeLayer;
310 		}
311 	    }
312 	    else
313 		LefError(DEF_ERROR, "Via name \"%s\" unknown in route.\n", token);
314 	}
315 	else
316 	{
317 	    /* Revert to the routing layer type, in case we painted a via */
318 	    paintLayer = routeLayer;
319 
320 	    /* Record current reference point */
321 	    locarea.x1 = refp.x1;
322 	    locarea.y1 = refp.y1;
323 	    lx = x;
324 	    ly = y;
325 
326 	    /* Read an (X Y) point */
327 	    token = LefNextToken(f, TRUE);	/* read X */
328 	    if (*token == '*')
329 	    {
330 		if (valid == FALSE)
331 		{
332 		    LefError(DEF_ERROR, "No reference point for \"*\" wildcard\n");
333 		    goto endCoord;
334 		}
335 	    }
336 	    else if (sscanf(token, "%lg", &x) == 1)
337 	    {
338 		x /= oscale;		// In microns
339 		/* Note: offsets and stubs are always less than half a pitch,	*/
340 		/* so round to the nearest integer grid point.			*/
341 		refp.x1 = (int)(0.5 + ((x - Xlowerbound) / PitchX));
342 	    }
343 	    else
344 	    {
345 		LefError(DEF_ERROR, "Cannot parse X coordinate.\n");
346 		goto endCoord;
347 	    }
348 	    token = LefNextToken(f, TRUE);	/* read Y */
349 	    if (*token == '*')
350 	    {
351 		if (valid == FALSE)
352 		{
353 		    LefError(DEF_ERROR, "No reference point for \"*\" wildcard\n");
354 		    goto endCoord;
355 		}
356 	    }
357 	    else if (sscanf(token, "%lg", &y) == 1)
358 	    {
359 		y /= oscale;		// In microns
360 		refp.y1 = (int)(0.5 + ((y - Ylowerbound) / PitchY));
361 	    }
362 	    else
363 	    {
364 		LefError(DEF_ERROR, "Cannot parse Y coordinate.\n");
365 		goto endCoord;
366 	    }
367 
368 	    /* Indicate that we have a valid reference point */
369 
370 	    if (valid == FALSE)
371 	    {
372 		valid = TRUE;
373 	    }
374 	    else if ((locarea.x1 != refp.x1) && (locarea.y1 != refp.y1))
375 	    {
376 		/* Skip over nonmanhattan segments, reset the reference	*/
377 		/* point, and output a warning.				*/
378 
379 		LefError(DEF_ERROR, "Can't deal with nonmanhattan geometry in route.\n");
380 		locarea.x1 = refp.x1;
381 		locarea.y1 = refp.y1;
382 		lx = x;
383 		ly = y;
384 	    }
385 	    else
386 	    {
387 		locarea.x2 = refp.x1;
388 		locarea.y2 = refp.y1;
389 
390 		if (special != (char)0) {
391 		   if ((valid == TRUE) && (noobstruct == FALSE)) {
392 		      s = LefGetRouteSpacing(routeLayer);
393 		      hw = w / 2;
394 		      drect = (DSEG)malloc(sizeof(struct dseg_));
395 		      if (lx > x) {
396 		         drect->x1 = x - s;
397 		         drect->x2 = lx + s;
398 		      }
399 		      else if (lx < x) {
400 		         drect->x1 = lx - s;
401 		         drect->x2 = x + s;
402 		      }
403 		      else {
404 		         drect->x1 = x - hw - s;
405 		         drect->x2 = x + hw + s;
406 		      }
407 		      if (ly > y) {
408 		         drect->y1 = y - s;
409 		         drect->y2 = ly + s;
410 		      }
411 		      else if (ly < y) {
412 		         drect->y1 = ly - s;
413 		         drect->y2 = y + s;
414 		      }
415 		      else {
416 		         drect->y1 = y - hw - s;
417 		         drect->y2 = y + hw + s;
418 		      }
419 		      drect->layer = routeLayer;
420 		      drect->next = UserObs;
421 		      UserObs = drect;
422 		   }
423 		}
424 	    }
425 
426 endCoord:
427 	    /* Find the closing parenthesis for the coordinate pair */
428 	    while (*token != ')')
429 		token = LefNextToken(f, TRUE);
430 	}
431     }
432 
433     return token;	/* Pass back the last token found */
434 }
435 
436 /*
437  *------------------------------------------------------------
438  *
439  * DefReadGatePin ---
440  *
441  *	Given a gate name and a pin name in a net from the
442  *	DEF file NETS section, find the position of the
443  *	gate, then the position of the pin within the gate,
444  *	and add pin and obstruction information to the grid
445  *	network.
446  *
447  *------------------------------------------------------------
448  */
449 
450 static void
DefReadGatePin(NET net,NODE node,char * instname,char * pinname)451 DefReadGatePin(NET net, NODE node, char *instname, char *pinname)
452 {
453     int i;
454     GATE gateginfo;
455     DSEG drect;
456     GATE g;
457     double dx, dy;
458     int gridx, gridy;
459     DPOINT dp;
460 
461     g = DefFindGate(instname);
462     if (g) {
463 
464 	gateginfo = g->gatetype;
465 
466 	if (!gateginfo) {
467 	    // Instances marked "<net>/pin have a NULL gatetype;  this is okay.
468 	    if (strcmp(pinname, "pin"))
469 		LefError(DEF_ERROR, "Endpoint %s/%s of net %s not found\n",
470 				instname, pinname, net->netname);
471 	    return;
472 	}
473 	for (i = 0; i < gateginfo->nodes; i++) {
474 	    if (!strcasecmp(gateginfo->node[i], pinname)) {
475 		node->taps = (DPOINT)NULL;
476 		node->extend = (DPOINT)NULL;
477 
478 		for (drect = g->taps[i]; drect; drect = drect->next) {
479 
480 		    // Add all routing gridpoints that fall inside
481 		    // the rectangle.  Much to do here:
482 		    // (1) routable area should extend 1/2 route width
483 		    // to each side, as spacing to obstructions allows.
484 		    // (2) terminals that are wide enough to route to
485 		    // but not centered on gridpoints should be marked
486 		    // in some way, and handled appropriately.
487 
488 		    gridx = (int)((drect->x1 - Xlowerbound) / PitchX) - 1;
489 
490 		    if (gridx < 0) gridx = 0;
491 		    while (1) {
492 			dx = (gridx * PitchX) + Xlowerbound;
493 			if (dx > drect->x2) break;
494 			if (dx < drect->x1) {
495 			    gridx++;
496 			    continue;
497 			}
498 			gridy = (int)((drect->y1 - Ylowerbound) / PitchY) - 1;
499 
500 			if (gridy < 0) gridy = 0;
501 			while (1) {
502 			    dy = (gridy * PitchY) + Ylowerbound;
503 			    if (dy > drect->y2) break;
504 			    if (dy < drect->y1) {
505 				gridy++;
506 				continue;
507 			    }
508 
509 			    // Routing grid point is an interior point
510 			    // of a gate port.  Record the position
511 
512 			    dp = (DPOINT)malloc(sizeof(struct dpoint_));
513 			    dp->layer = drect->layer;
514 			    dp->x = dx;
515 			    dp->y = dy;
516 			    dp->gridx = gridx;
517 			    dp->gridy = gridy;
518 
519 			    if ((dy >= drect->y1) &&
520 					(dx >= drect->x1) &&
521 					(dy <= drect->y2) &&
522 					(dx <= drect->x2)) {
523 				dp->next = node->taps;
524 				node->taps = dp;
525 			    }
526 			    else {
527 				dp->next = node->extend;
528 				node->extend = dp;
529 			    }
530 			    gridy++;
531 			}
532 			gridx++;
533 		    }
534 		}
535 		node->netnum = net->netnum;
536 		g->netnum[i] = net->netnum;
537 		g->noderec[i] = node;
538 		node->netname = net->netname;
539 		node->next = net->netnodes;
540 		net->netnodes = node;
541 		break;
542 	    }
543 	}
544 	if (i < gateginfo->nodes) return;
545     }
546 }
547 
548 /*
549  *------------------------------------------------------------
550  *
551  * DefReadNets --
552  *
553  *	Read a NETS or SPECIALNETS section from a DEF file.
554  *
555  * Results:
556  *	Return the total number of fixed or cover nets,
557  *	excluding power and ground nets.  This gives the
558  *	base number of nets to be copied verbatim from
559  *	input to output (used only for SPECIALNETS, as
560  *	regular nets are tracked with the NET_IGNORED flag).
561  *
562  * Side Effects:
563  *	Many.  Networks are created, and geometry may be
564  *	painted into the database top-level cell.
565  *
566  *------------------------------------------------------------
567  */
568 
569 enum def_net_keys {DEF_NET_START = 0, DEF_NET_END};
570 enum def_netprop_keys {
571 	DEF_NETPROP_USE = 0, DEF_NETPROP_ROUTED, DEF_NETPROP_FIXED,
572 	DEF_NETPROP_COVER, DEF_NETPROP_SHAPE, DEF_NETPROP_SOURCE,
573 	DEF_NETPROP_WEIGHT, DEF_NETPROP_PROPERTY};
574 
575 static int
DefReadNets(FILE * f,char * sname,float oscale,char special,int total)576 DefReadNets(FILE *f, char *sname, float oscale, char special, int total)
577 {
578     char *token;
579     int keyword, subkey;
580     int i, processed = 0;
581     int nodeidx;
582     int fixed = 0;
583     char instname[MAX_NAME_LEN], pinname[MAX_NAME_LEN];
584     u_char is_new;
585 
586     NET net;
587     int netidx;
588     NODE node;
589 
590     static char *net_keys[] = {
591 	"-",
592 	"END",
593 	NULL
594     };
595 
596     static char *net_property_keys[] = {
597 	"USE",
598 	"ROUTED",
599 	"FIXED",
600 	"COVER",
601 	"SHAPE",
602 	"SOURCE",
603 	"WEIGHT",
604 	"PROPERTY",
605 	NULL
606     };
607 
608     if (Numnets == 0)
609     {
610 	// Initialize net and node records
611 	netidx = 0;
612 	Nlnets = (NET *)malloc(total * sizeof(NET));
613 	for (i = 0; i < total; i++) Nlnets[i] = NULL;
614     }
615     else {
616 	netidx = Numnets;
617 	Nlnets = (NET *)realloc(Nlnets, (Numnets + total) * sizeof(NET));
618 	for (i = Numnets; i < (Numnets + total); i++) Nlnets[i] = NULL;
619     }
620 
621     while ((token = LefNextToken(f, TRUE)) != NULL)
622     {
623 	keyword = Lookup(token, net_keys);
624 	if (keyword < 0)
625 	{
626 	    LefError(DEF_WARNING, "Unknown keyword \"%s\" in NET "
627 			"definition; ignoring.\n", token);
628 	    LefEndStatement(f);
629 	    continue;
630 	}
631 
632 	switch (keyword)
633 	{
634 	    case DEF_NET_START:
635 
636 		/* Get net name */
637 		token = LefNextToken(f, TRUE);
638 		net = DefFindNet(token);
639 
640 		if (net == NULL) {
641 		    net = (NET)malloc(sizeof(struct net_));
642 		    Nlnets[Numnets++] = net;
643 		    net->numnodes = 0;
644 		    net->netname = strdup(token);
645 		    net->netnodes = (NODE)NULL;
646 		    net->Flags = (special) ? NET_SPECIAL : 0;
647 
648 		    /* Check for backslash-escape names modified by other tools */
649 		    /* (e.g., vlog2Cel) which replace the trailing space with a */
650 		    /* backslash, making the name verilog-incompatible.         */
651 
652 		    if (*net->netname == '\\') {
653 			char *sptr, *bptr;
654 		        sptr = strchr(net->netname, ' ');
655 		        if (sptr == NULL) {
656 		            bptr = strrchr(net->netname + 1, '\\');
657 		            if (bptr != NULL) *bptr = ' ';
658 		        }
659 		    }
660 
661 		    net->netnum = netidx++;
662 		    DefHashNet(net);
663 
664 		    nodeidx = 0;
665 		    is_new = TRUE;
666 		}
667 		else {
668 		    nodeidx = net->numnodes;
669 		    is_new = FALSE;
670 		}
671 
672 		/* Update the record of the number of nets processed	*/
673 		/* and spit out a message for every 5% finished.	*/
674 
675 		processed++;
676 
677 		/* Get next token;  will be '(' if this is a netlist	*/
678 		token = LefNextToken(f, TRUE);
679 
680 		/* Process all properties */
681 		while (token && (*token != ';'))
682 		{
683 		    /* Find connections for the net */
684 		    if (*token == '(')
685 		    {
686 			token = LefNextToken(f, TRUE);  /* get pin or gate */
687 			strcpy(instname, token);
688 
689 			/* Check for instname with sanitized backslash syntax */
690 			if (*instname == '\\') {
691 			    char *sptr, *bptr;
692 			    sptr = strchr(instname, ' ');
693 			    if (sptr == NULL) {
694 			        bptr = strrchr(instname + 1, '\\');
695 			        if (bptr != NULL) *bptr = ' ';
696 			    }
697 			}
698 
699 			token = LefNextToken(f, TRUE);	/* get node name */
700 
701 			if (!strcasecmp(instname, "pin")) {
702 			    strcpy(instname, token);
703 			    strcpy(pinname, "pin");
704 			}
705 			else
706 			    strcpy(pinname, token);
707 
708 			node = (NODE)calloc(1, sizeof(struct node_));
709 			node->nodenum = nodeidx++;
710 			DefReadGatePin(net, node, instname, pinname);
711 
712 			token = LefNextToken(f, TRUE);	/* should be ')' */
713 
714 			continue;
715 		    }
716 		    else if (*token != '+')
717 		    {
718 			token = LefNextToken(f, TRUE);	/* Not a property */
719 			continue;	/* Ignore it, whatever it is */
720 		    }
721 		    else
722 			token = LefNextToken(f, TRUE);
723 
724 		    subkey = Lookup(token, net_property_keys);
725 		    if (subkey < 0)
726 		    {
727 			LefError(DEF_WARNING, "Unknown net property \"%s\" in "
728 				"NET definition; ignoring.\n", token);
729 			continue;
730 		    }
731 		    switch (subkey)
732 		    {
733 			case DEF_NETPROP_USE:
734 			    /* Presently, we ignore this */
735 			    break;
736 			case DEF_NETPROP_SHAPE:
737 			    /* Ignore this too, along with the next keyword */
738 			    token = LefNextToken(f, TRUE);
739 			    break;
740 			case DEF_NETPROP_FIXED:
741 			case DEF_NETPROP_COVER:
742 			    /* Read in fixed nets like regular nets but mark
743 			     * them as NET_IGNORED.  HOWEVER, if the net
744 			     * already exists and is not marked NET_IGNORED,
745 			     * then don't force it to be ignored.  That is
746 			     * particularly an issue for a net like power or
747 			     * ground, which may need to be routed like a
748 			     * regular net but also has fixed portions. */
749 			    if (is_new) {
750 				fixed++;
751 			    }
752 			    // fall through
753 			case DEF_NETPROP_ROUTED:
754 			    // Read in the route;  qrouter now takes
755 			    // responsibility for this route.
756 			    while (token && (*token != ';'))
757 			        token = DefAddRoutes(f, oscale, net, special);
758 			    // Treat power and ground nets in specialnets as fixed
759 			    if (subkey == DEF_NETPROP_ROUTED && special == (char)1)
760 				fixed++;
761 			    break;
762 		    }
763 		}
764 		break;
765 
766 	    case DEF_NET_END:
767 		if (!LefParseEndStatement(f, sname))
768 		{
769 		    LefError(DEF_ERROR, "Net END statement missing.\n");
770 		    keyword = -1;
771 		}
772 		break;
773 	}
774 	if (keyword == DEF_NET_END) break;
775     }
776 
777     // Set the number of nodes per net for each node on the net
778 
779     if (special == FALSE) {
780 
781 	// Fill in the netnodes list for each net, needed for checking
782 	// for isolated routed groups within a net.
783 
784 	for (i = 0; i < Numnets; i++) {
785 	    net = Nlnets[i];
786 	    for (node = net->netnodes; node; node = node->next)
787 		net->numnodes++;
788 	    for (node = net->netnodes; node; node = node->next)
789 		node->numnodes = net->numnodes;
790 	}
791     }
792 
793     if (processed == total) {
794 	if (Verbose > 0)
795 	    fprintf(stdout, "  Processed %d%s nets total.\n", processed,
796 			(special) ? " special" : "");
797     }
798     else
799 	LefError(DEF_WARNING, "Warning:  Number of nets read (%d) does not match "
800 		"the number declared (%d).\n", processed, total);
801     return fixed;
802 }
803 
804 /*
805  *------------------------------------------------------------
806  *
807  * DefReadUseLocation --
808  *
809  *	Read location and orientation of a cell use
810  *	Syntax: ( X Y ) O
811  *
812  * Results:
813  *	0 on success, -1 on failure
814  *
815  * Side Effects:
816  *	GATE definition for the use has the placedX, placedY,
817  *	and orient values filled.
818  *------------------------------------------------------------
819  */
820 enum def_orient {DEF_NORTH, DEF_SOUTH, DEF_EAST, DEF_WEST,
821 	DEF_FLIPPED_NORTH, DEF_FLIPPED_SOUTH, DEF_FLIPPED_EAST,
822 	DEF_FLIPPED_WEST};
823 
824 static int
DefReadLocation(gate,f,oscale)825 DefReadLocation(gate, f, oscale)
826     GATE gate;
827     FILE *f;
828     float oscale;
829 {
830     int keyword;
831     char *token;
832     float x, y;
833     char mxflag, myflag;
834 
835     static char *orientations[] = {
836 	"N", "S", "E", "W", "FN", "FS", "FE", "FW"
837     };
838     static int oflags[] = {
839 	RN, RS, RE, RW, RN | RF, RS | RF, RE | RF, RW | RF
840     };
841 
842     token = LefNextToken(f, TRUE);
843     if (*token != '(') goto parse_error;
844     token = LefNextToken(f, TRUE);
845     if (sscanf(token, "%f", &x) != 1) goto parse_error;
846     token = LefNextToken(f, TRUE);
847     if (sscanf(token, "%f", &y) != 1) goto parse_error;
848     token = LefNextToken(f, TRUE);
849     if (*token != ')') goto parse_error;
850     token = LefNextToken(f, TRUE);
851 
852     keyword = Lookup(token, orientations);
853     if (keyword < 0)
854     {
855 	LefError(DEF_ERROR, "Unknown macro orientation \"%s\".\n", token);
856 	return -1;
857     }
858 
859     mxflag = myflag = (char)0;
860 
861     switch (keyword)
862     {
863 	case DEF_NORTH:
864 	    break;
865 	case DEF_SOUTH:
866 	    mxflag = 1;
867 	    myflag = 1;
868 	    break;
869 	case DEF_FLIPPED_NORTH:
870 	    mxflag = 1;
871 	    break;
872 	case DEF_FLIPPED_SOUTH:
873 	    myflag = 1;
874 	    break;
875     }
876 
877     if (gate) {
878 	gate->placedX = x / oscale;
879 	gate->placedY = y / oscale;
880 	gate->orient = MNONE;
881 	if (mxflag) gate->orient |= MX;
882 	if (myflag) gate->orient |= MY;
883 	gate->orient |= oflags[keyword];
884     }
885     return 0;
886 
887 parse_error:
888     LefError(DEF_ERROR, "Cannot parse location: must be ( X Y ) orient\n");
889     return -1;
890 }
891 
892 /*
893  *------------------------------------------------------------
894  *
895  * DefReadPins --
896  *
897  *	Read a PINS section from a DEF file.
898  *
899  * Results:
900  *	None.
901  *
902  * Side Effects:
903  *	Generates paint and labels in the layout.
904  *
905  *------------------------------------------------------------
906  */
907 
908 enum def_pins_keys {DEF_PINS_START = 0, DEF_PINS_END};
909 enum def_pins_prop_keys {
910 	DEF_PINS_PROP_NET = 0, DEF_PINS_PROP_DIR,
911 	DEF_PINS_PROP_LAYER, DEF_PINS_PROP_PLACED,
912 	DEF_PINS_PROP_USE, DEF_PINS_PROP_FIXED,
913 	DEF_PINS_PROP_COVER};
914 
915 static void
DefReadPins(FILE * f,char * sname,float oscale,int total)916 DefReadPins(FILE *f, char *sname, float oscale, int total)
917 {
918     char *token;
919     char pinname[MAX_NAME_LEN];
920     int keyword, subkey;
921     int processed = 0;
922     DSEG currect, drect;
923     GATE gate;
924     int curlayer;
925     double hwidth;
926     u_char pin_use;
927 
928     static char *pin_keys[] = {
929 	"-",
930 	"END",
931 	NULL
932     };
933 
934     static char *pin_property_keys[] = {
935 	"NET",
936 	"DIRECTION",
937 	"LAYER",
938 	"PLACED",
939 	"USE",
940 	"FIXED",
941 	"COVER",
942 	NULL
943     };
944 
945     static char *pin_classes[] = {
946 	"DEFAULT",
947 	"INPUT",
948 	"OUTPUT TRISTATE",
949 	"OUTPUT",
950 	"INOUT",
951 	"FEEDTHRU",
952 	NULL
953     };
954 
955     static char *pin_uses[] = {
956 	"DEFAULT",
957 	"SIGNAL",
958 	"ANALOG",
959 	"POWER",
960 	"GROUND",
961 	"CLOCK",
962 	"TIEOFF",
963 	"SCAN",
964 	"RESET",
965 	NULL
966     };
967 
968     pin_use = PORT_USE_DEFAULT;
969 
970     while ((token = LefNextToken(f, TRUE)) != NULL)
971     {
972 	keyword = Lookup(token, pin_keys);
973 
974 	if (keyword < 0)
975 	{
976 	    LefError(DEF_WARNING, "Unknown keyword \"%s\" in PINS "
977 			"definition; ignoring.\n", token);
978 	    LefEndStatement(f);
979 	    continue;
980 	}
981 	switch (keyword)
982 	{
983 	    case DEF_PINS_START:		/* "-" keyword */
984 
985 		/* Update the record of the number of pins		*/
986 		/* processed and spit out a message for every 5% done.	*/
987 
988 		processed++;
989 
990 		/* Get pin name */
991 		token = LefNextToken(f, TRUE);
992 		if (sscanf(token, "%2047s", pinname) != 1)
993 		{
994 		    LefError(DEF_ERROR, "Bad pin statement:  Need pin name\n");
995 		    LefEndStatement(f);
996 		    break;
997 		}
998 
999 		/* Create the pin record */
1000 		gate = (GATE)malloc(sizeof(struct gate_));
1001 		gate->gatetype = PinMacro;
1002 		gate->gatename = NULL;	/* Use NET, but if none, use	*/
1003 					/* the pin name, set at end.	*/
1004 		gate->width = gate->height = 0;
1005 		curlayer = -1;
1006 
1007 		/* Pin record has one node;  allocate memory for it */
1008 		gate->taps = (DSEG *)malloc(sizeof(DSEG));
1009 		gate->noderec = (NODE *)malloc(sizeof(NODE));
1010 		gate->direction = (u_char *)malloc(sizeof(u_char));
1011 		gate->area = (float *)malloc(sizeof(float));
1012 		gate->netnum = (int *)malloc(sizeof(int));
1013 		gate->node = (char **)malloc(sizeof(char *));
1014 		gate->taps[0] = NULL;
1015 		gate->noderec[0] = NULL;
1016 		gate->netnum[0] = -1;
1017 		gate->node[0] = NULL;
1018 		gate->direction[0] = PORT_CLASS_DEFAULT;
1019 		gate->area[0] = 0.0;
1020 		gate->nomirror = FALSE;
1021 		gate->clientdata = (void *)NULL;
1022 
1023 		/* Now do a search through the line for "+" entries	*/
1024 		/* And process each.					*/
1025 
1026 		while ((token = LefNextToken(f, TRUE)) != NULL)
1027 		{
1028 		    if (*token == ';') break;
1029 		    if (*token != '+') continue;
1030 
1031 		    token = LefNextToken(f, TRUE);
1032 		    subkey = Lookup(token, pin_property_keys);
1033 		    if (subkey < 0)
1034 		    {
1035 			LefError(DEF_WARNING, "Unknown pin property \"%s\" in "
1036 				"PINS definition; ignoring.\n", token);
1037 			continue;
1038 		    }
1039 		    switch (subkey)
1040 		    {
1041 			case DEF_PINS_PROP_NET:
1042 			    /* Get the net name */
1043 			    token = LefNextToken(f, TRUE);
1044 			    gate->gatename = strdup(token);
1045 			    gate->node[0] = strdup(token);
1046 			    break;
1047 			case DEF_PINS_PROP_DIR:
1048 			    token = LefNextToken(f, TRUE);
1049 			    subkey = Lookup(token, pin_classes);
1050 			    if (subkey < 0)
1051 				LefError(DEF_ERROR, "Unknown pin class %s\n", token);
1052 			    else
1053 				gate->direction[0] = subkey;
1054 			    break;
1055 			case DEF_PINS_PROP_LAYER:
1056 			    curlayer = LefReadLayer(f, FALSE);
1057 			    currect = LefReadRect(f, curlayer, oscale);
1058 			    /* Warn if pin is on layer above routing layer limit? */
1059 			    if (currect) {
1060 				gate->width = currect->x2 - currect->x1;
1061 				gate->height = currect->y2 - currect->y1;
1062 			    }
1063 			    break;
1064 			case DEF_PINS_PROP_USE:
1065 			    token = LefNextToken(f, TRUE);
1066 			    subkey = Lookup(token, pin_uses);
1067 			    if (subkey < 0)
1068 				LefError(DEF_ERROR, "Unknown pin use %s\n", token);
1069 			    else
1070 				pin_use = subkey;
1071 			    break;
1072 			case DEF_PINS_PROP_PLACED:
1073 			case DEF_PINS_PROP_FIXED:
1074 			case DEF_PINS_PROP_COVER:
1075 			    DefReadLocation(gate, f, oscale);
1076 			    break;
1077 		    }
1078 		}
1079 
1080 		/* If no NET was declared for pin, use pinname */
1081 		if (gate->gatename == NULL)
1082 		    gate->gatename = strdup(pinname);
1083 
1084 		/* Make sure pin is at least the size of the route layer */
1085 		drect = (DSEG)malloc(sizeof(struct dseg_));
1086 		gate->taps[0] = drect;
1087 		drect->next = (DSEG)NULL;
1088 
1089 		hwidth = LefGetRouteWidth(curlayer);
1090 		if (gate->width < hwidth) gate->width = hwidth;
1091 		if (gate->height < hwidth) gate->height = hwidth;
1092 		hwidth /= 2.0;
1093 		drect->x1 = gate->placedX - hwidth;
1094 		drect->y1 = gate->placedY - hwidth;
1095 		drect->x2 = gate->placedX + hwidth;
1096 		drect->y2 = gate->placedY + hwidth;
1097 		drect->layer = curlayer;
1098 		gate->obs = (DSEG)NULL;
1099 		gate->nodes = 1;
1100 		gate->next = Nlgates;
1101 		gate->last = (GATE)NULL;
1102 		if (Nlgates) Nlgates->last = gate;
1103 		Nlgates = gate;
1104 		Numpins++;
1105 
1106 		// Used by Tcl version of qrouter
1107 		DefHashInstance(gate);
1108 
1109 		break;
1110 
1111 	    case DEF_PINS_END:
1112 		if (!LefParseEndStatement(f, sname))
1113 		{
1114 		    LefError(DEF_ERROR, "Pins END statement missing.\n");
1115 		    keyword = -1;
1116 		}
1117 		if (pin_use != PORT_USE_DEFAULT && gate->direction[0] ==
1118 			PORT_CLASS_DEFAULT)
1119 		{
1120 		    /* Derive pin use from pin class, if needed */
1121 		    switch (pin_use) {
1122 			case PORT_USE_SIGNAL:
1123 			case PORT_USE_RESET:
1124 			case PORT_USE_CLOCK:
1125 			case PORT_USE_SCAN:
1126 			    gate->direction[0] = PORT_CLASS_INPUT;
1127 			    break;
1128 
1129 			case PORT_USE_POWER:
1130 			case PORT_USE_GROUND:
1131 			case PORT_USE_TIEOFF:
1132 			case PORT_USE_ANALOG:
1133 			    gate->direction[0] = PORT_CLASS_BIDIRECTIONAL;
1134 			    break;
1135 		    }
1136 		}
1137 		break;
1138 	}
1139 	if (keyword == DEF_PINS_END) break;
1140     }
1141 
1142     if (processed == total) {
1143 	if (Verbose > 0)
1144 	    fprintf(stdout, "  Processed %d pins total.\n", processed);
1145     }
1146     else
1147 	LefError(DEF_WARNING, "Warning:  Number of pins read (%d) does not match "
1148 		"the number declared (%d).\n", processed, total);
1149 }
1150 
1151 /*
1152  *------------------------------------------------------------
1153  *
1154  * DefReadVias --
1155  *
1156  *	Read a VIAS section from a DEF file.
1157  *
1158  * Results:
1159  *	None.
1160  *
1161  * Side Effects:
1162  *	Technically, this routine should be creating a cell for
1163  *	each defined via.  For now, it just computes the bounding
1164  *	rectangle and layer.
1165  *
1166  *------------------------------------------------------------
1167  */
1168 
1169 enum def_vias_keys {DEF_VIAS_START = 0, DEF_VIAS_END};
1170 enum def_vias_prop_keys {
1171 	DEF_VIAS_PROP_RECT = 0};
1172 
1173 static void
DefReadVias(f,sname,oscale,total)1174 DefReadVias(f, sname, oscale, total)
1175     FILE *f;
1176     char *sname;
1177     float oscale;
1178     int total;
1179 {
1180     char *token;
1181     char vianame[LEF_LINE_MAX];
1182     int keyword, subkey;
1183     int processed = 0;
1184     int curlayer;
1185     LefList lefl;
1186 
1187     static char *via_keys[] = {
1188 	"-",
1189 	"END",
1190 	NULL
1191     };
1192 
1193     static char *via_property_keys[] = {
1194 	"RECT",
1195 	NULL
1196     };
1197 
1198     while ((token = LefNextToken(f, TRUE)) != NULL)
1199     {
1200 	keyword = Lookup(token, via_keys);
1201 
1202 	if (keyword < 0)
1203 	{
1204 	    LefError(DEF_WARNING, "Unknown keyword \"%s\" in VIAS "
1205 			"definition; ignoring.\n", token);
1206 	    LefEndStatement(f);
1207 	    continue;
1208 	}
1209 	switch (keyword)
1210 	{
1211 	    case DEF_VIAS_START:		/* "-" keyword */
1212 
1213 		/* Update the record of the number of vias		*/
1214 		/* processed and spit out a message for every 5% done.	*/
1215 
1216 		processed++;
1217 
1218 		/* Get via name */
1219 		token = LefNextToken(f, TRUE);
1220 		if (sscanf(token, "%2047s", vianame) != 1)
1221 		{
1222 		    LefError(DEF_ERROR, "Bad via statement:  Need via name\n");
1223 		    LefEndStatement(f);
1224 		    break;
1225 		}
1226 		lefl = LefFindLayer(token);
1227                 if (lefl == NULL)
1228                 {
1229                     lefl = (LefList)calloc(1, sizeof(lefLayer));
1230                     lefl->type = -1;
1231                     lefl->obsType = -1;
1232                     lefl->lefClass = CLASS_VIA;
1233                     lefl->info.via.area.x1 = 0.0;
1234                     lefl->info.via.area.y1 = 0.0;
1235                     lefl->info.via.area.x2 = 0.0;
1236                     lefl->info.via.area.y2 = 0.0;
1237                     lefl->info.via.area.layer = -1;
1238                     lefl->info.via.cell = (GATE)NULL;
1239                     lefl->info.via.lr = (DSEG)NULL;
1240 		    /* Note:  "generated" flag only refers to vias that	*/
1241 		    /* are internally generated by qrouter.  All others	*/
1242 		    /* in the DEF file are read/written verbatim.	*/
1243 		    lefl->info.via.generated = FALSE;
1244                     lefl->lefName = strdup(token);
1245 
1246                     lefl->next = LefInfo;
1247                     LefInfo = lefl;
1248 		}
1249 		else
1250 		{
1251 		    LefError(DEF_WARNING, "Warning:  Composite via \"%s\" "
1252 				"redefined.\n", vianame);
1253 		    lefl = LefRedefined(lefl, vianame);
1254 		}
1255 
1256 		/* Now do a search through the line for "+" entries	*/
1257 		/* And process each.					*/
1258 
1259 		while ((token = LefNextToken(f, TRUE)) != NULL)
1260 		{
1261 		    if (*token == ';') break;
1262 		    if (*token != '+') continue;
1263 
1264 		    token = LefNextToken(f, TRUE);
1265 		    subkey = Lookup(token, via_property_keys);
1266 		    if (subkey < 0)
1267 		    {
1268 			LefError(DEF_WARNING, "Unknown via property \"%s\" in "
1269 				"VIAS definition; ignoring.\n", token);
1270 			continue;
1271 		    }
1272 		    switch (subkey)
1273 		    {
1274 			case DEF_VIAS_PROP_RECT:
1275 			    curlayer = LefReadLayer(f, FALSE);
1276 			    LefAddViaGeometry(f, lefl, curlayer, oscale);
1277 			    break;
1278 		    }
1279 		}
1280 		break;
1281 
1282 	    case DEF_VIAS_END:
1283 		if (!LefParseEndStatement(f, sname))
1284 		{
1285 		    LefError(DEF_ERROR, "Vias END statement missing.\n");
1286 		    keyword = -1;
1287 		}
1288 		break;
1289 	}
1290 	if (keyword == DEF_VIAS_END) break;
1291     }
1292 
1293     if (processed == total) {
1294 	if (Verbose > 0)
1295 	    fprintf(stdout, "  Processed %d vias total.\n", processed);
1296     }
1297     else
1298 	LefError(DEF_WARNING, "Warning:  Number of vias read (%d) does not match "
1299 		"the number declared (%d).\n", processed, total);
1300 }
1301 
1302 /*
1303  *------------------------------------------------------------
1304  *
1305  * DefReadBlockages --
1306  *
1307  *	Read a BLOCKAGES section from a DEF file.
1308  *
1309  * Results:
1310  *	None.
1311  *
1312  * Side Effects:
1313  *	UserObs list is updated with the additional
1314  *	obstructions.
1315  *
1316  *------------------------------------------------------------
1317  */
1318 
1319 enum def_block_keys {DEF_BLOCK_START = 0, DEF_BLOCK_END};
1320 
1321 static void
DefReadBlockages(FILE * f,char * sname,float oscale,int total)1322 DefReadBlockages(FILE *f, char *sname, float oscale, int total)
1323 {
1324     char *token;
1325     int keyword;
1326     int processed = 0;
1327     DSEG drect, rsrch;
1328     LefList lefl;
1329 
1330     static char *blockage_keys[] = {
1331 	"-",
1332 	"END",
1333 	NULL
1334     };
1335 
1336     while ((token = LefNextToken(f, TRUE)) != NULL)
1337     {
1338 	keyword = Lookup(token, blockage_keys);
1339 
1340 	if (keyword < 0)
1341 	{
1342 	    LefError(DEF_WARNING, "Unknown keyword \"%s\" in BLOCKAGE "
1343 			"definition; ignoring.\n", token);
1344 	    LefEndStatement(f);
1345 	    continue;
1346 	}
1347 	switch (keyword)
1348 	{
1349 	    case DEF_BLOCK_START:		/* "-" keyword */
1350 
1351 		/* Update the record of the number of components	*/
1352 		/* processed and spit out a message for every 5% done.	*/
1353 
1354 		processed++;
1355 
1356 		/* Get layer name */
1357 		token = LefNextToken(f, TRUE);
1358 		lefl = LefFindLayer(token);
1359 		if (lefl != NULL)
1360 		{
1361 		    drect = LefReadGeometry(NULL, f, oscale);
1362 		    if (UserObs == NULL)
1363 			UserObs = drect;
1364 		    else {
1365 			for (rsrch = UserObs; rsrch->next; rsrch = rsrch->next);
1366 			rsrch->next = drect;
1367 		    }
1368 		}
1369 		else
1370 		{
1371 		    LefError(DEF_ERROR, "Bad blockage statement:  Need layer name\n");
1372 		    LefEndStatement(f);
1373 		    break;
1374 		}
1375 		break;
1376 
1377 	    case DEF_BLOCK_END:
1378 		if (!LefParseEndStatement(f, sname))
1379 		{
1380 		    LefError(DEF_ERROR, "Blockage END statement missing.\n");
1381 		    keyword = -1;
1382 		}
1383 		break;
1384 	}
1385 	if (keyword == DEF_BLOCK_END) break;
1386     }
1387 
1388     if (processed == total) {
1389 	if (Verbose > 0)
1390 	    fprintf(stdout, "  Processed %d blockages total.\n", processed);
1391     }
1392     else
1393 	LefError(DEF_WARNING, "Warning:  Number of blockages read (%d) does not match "
1394 		"the number declared (%d).\n", processed, total);
1395 }
1396 
1397 /*
1398  *------------------------------------------------------------
1399  *
1400  * DefAddGateInstance --
1401  *
1402  *	Add a gate instance to the list of instances and
1403  *	instance hash table.  The instance is assumed to
1404  *	have records gatename, gatetype, placedX, and
1405  *	placedY already set.  The gate macro is found from
1406  *	the gatetype record, and all information about the
1407  *	cell macro is copied to the instance record, with
1408  *	positions adjusted for the instance.
1409  *
1410  * Results:
1411  *	None.
1412  *
1413  * Side Effects:
1414  *	Many.  Cell instances are created and added to
1415  *	the database.
1416  *
1417  *------------------------------------------------------------
1418  */
1419 
1420 void
DefAddGateInstance(GATE gate)1421 DefAddGateInstance(GATE gate)
1422 {
1423     GATE gateginfo;
1424     int i;
1425     DSEG drect, newrect;
1426     double tmp;
1427 
1428     if (gate == NULL) return;
1429     gateginfo = gate->gatetype;
1430     if (gateginfo == NULL) return;
1431 
1432     /* Process the gate */
1433     gate->width = gateginfo->width;
1434     gate->height = gateginfo->height;
1435     gate->nodes = gateginfo->nodes;
1436     gate->nomirror = gateginfo->nomirror;
1437     gate->obs = (DSEG)NULL;
1438 
1439     gate->taps = (DSEG *)malloc(gate->nodes * sizeof(DSEG));
1440     gate->noderec = (NODE *)malloc(gate->nodes * sizeof(NODE));
1441     gate->direction = (u_char *)malloc(gate->nodes * sizeof(u_char));
1442     gate->area = (float *)malloc(gate->nodes * sizeof(float));
1443     gate->netnum = (int *)malloc(gate->nodes * sizeof(int));
1444     gate->node = (char **)malloc(gate->nodes * sizeof(char *));
1445 
1446     /* Let the node names point to the master cell; */
1447     /* this is just diagnostic;  allows us, for	    */
1448     /* instance, to identify vdd and gnd nodes, so  */
1449     /* we don't complain about them being	    */
1450     /* disconnected.				    */
1451 
1452     for (i = 0; i < gate->nodes; i++) {
1453 	gate->node[i] = gateginfo->node[i];  /* copy pointer */
1454 	gate->direction[i] = gateginfo->direction[i];  /* copy */
1455 	gate->area[i] = gateginfo->area[i];
1456 	gate->taps[i] = (DSEG)NULL;
1457 	gate->netnum[i] = 0;		/* Until we read NETS */
1458 	gate->noderec[i] = NULL;
1459 
1460 	/* Make a copy of the gate nodes and adjust for	*/
1461 	/* instance position and number of layers	*/
1462 
1463 	for (drect = gateginfo->taps[i]; drect; drect = drect->next) {
1464 	    newrect = (DSEG)malloc(sizeof(struct dseg_));
1465 	    *newrect = *drect;
1466 	    newrect->next = gate->taps[i];
1467 	    gate->taps[i] = newrect;
1468 	}
1469 
1470 	for (drect = gate->taps[i]; drect; drect = drect->next) {
1471 	    // handle offset from gate origin
1472 	    drect->x1 -= gateginfo->placedX;
1473 	    drect->x2 -= gateginfo->placedX;
1474 	    drect->y1 -= gateginfo->placedY;
1475 	    drect->y2 -= gateginfo->placedY;
1476 
1477 	    // handle rotations and orientations here
1478 	    if (gate->orient & MX) {
1479 		tmp = drect->x1;
1480 		drect->x1 = -drect->x2;
1481 		drect->x1 += gate->placedX + gateginfo->width;
1482 		drect->x2 = -tmp;
1483 		drect->x2 += gate->placedX + gateginfo->width;
1484 	    }
1485 	    else {
1486 		drect->x1 += gate->placedX;
1487 		drect->x2 += gate->placedX;
1488 	    }
1489 	    if (gate->orient & MY) {
1490 		tmp = drect->y1;
1491 		drect->y1 = -drect->y2;
1492 		drect->y1 += gate->placedY + gateginfo->height;
1493 		drect->y2 = -tmp;
1494 		drect->y2 += gate->placedY + gateginfo->height;
1495 	    }
1496 	    else {
1497 		drect->y1 += gate->placedY;
1498 		drect->y2 += gate->placedY;
1499 	    }
1500 	}
1501     }
1502 
1503     /* Make a copy of the gate obstructions and adjust	*/
1504     /* for instance position				*/
1505     for (drect = gateginfo->obs; drect; drect = drect->next) {
1506 	newrect = (DSEG)malloc(sizeof(struct dseg_));
1507 	*newrect = *drect;
1508 	newrect->next = gate->obs;
1509 	gate->obs = newrect;
1510     }
1511 
1512     for (drect = gate->obs; drect; drect = drect->next) {
1513 	drect->x1 -= gateginfo->placedX;
1514 	drect->x2 -= gateginfo->placedX;
1515 	drect->y1 -= gateginfo->placedY;
1516 	drect->y2 -= gateginfo->placedY;
1517 
1518 	// handle rotations and orientations here
1519 	if (gate->orient & MX) {
1520 	    tmp = drect->x1;
1521 	    drect->x1 = -drect->x2;
1522 	    drect->x1 += gate->placedX + gateginfo->width;
1523 	    drect->x2 = -tmp;
1524 	    drect->x2 += gate->placedX + gateginfo->width;
1525 	}
1526 	else {
1527 	    drect->x1 += gate->placedX;
1528 	    drect->x2 += gate->placedX;
1529 	}
1530 	if (gate->orient & MY) {
1531 	    tmp = drect->y1;
1532 	    drect->y1 = -drect->y2;
1533 	    drect->y1 += gate->placedY + gateginfo->height;
1534 	    drect->y2 = -tmp;
1535 	    drect->y2 += gate->placedY + gateginfo->height;
1536 	}
1537 	else {
1538 	    drect->y1 += gate->placedY;
1539 	    drect->y2 += gate->placedY;
1540 	}
1541     }
1542     gate->next = Nlgates;
1543     gate->last = (GATE)NULL;
1544     if (Nlgates) Nlgates->last = gate;
1545     Nlgates = gate;
1546     Numgates++;
1547 
1548     // Used by Tcl version of qrouter
1549     DefHashInstance(gate);
1550 }
1551 
1552 /*
1553  *------------------------------------------------------------
1554  *
1555  * DefReadComponents --
1556  *
1557  *	Read a COMPONENTS section from a DEF file.
1558  *
1559  * Results:
1560  *	0 on success, 1 on fatal error.
1561  *
1562  * Side Effects:
1563  *	Many.  Cell instances are created and added to
1564  *	the database.
1565  *
1566  *------------------------------------------------------------
1567  */
1568 
1569 enum def_comp_keys {DEF_COMP_START = 0, DEF_COMP_END};
1570 enum def_prop_keys {
1571 	DEF_PROP_FIXED = 0, DEF_PROP_COVER,
1572 	DEF_PROP_PLACED, DEF_PROP_UNPLACED,
1573 	DEF_PROP_SOURCE, DEF_PROP_WEIGHT, DEF_PROP_FOREIGN,
1574 	DEF_PROP_REGION, DEF_PROP_GENERATE, DEF_PROP_PROPERTY,
1575 	DEF_PROP_EEQMASTER};
1576 
1577 static int
DefReadComponents(FILE * f,char * sname,float oscale,int total)1578 DefReadComponents(FILE *f, char *sname, float oscale, int total)
1579 {
1580     GATE gateginfo;
1581     GATE gate = NULL;
1582     char *token;
1583     char usename[512];
1584     int keyword, subkey, i;
1585     int processed = 0;
1586     char OK;
1587     int err_fatal = 0;
1588 
1589     static char *component_keys[] = {
1590 	"-",
1591 	"END",
1592 	NULL
1593     };
1594 
1595     static char *property_keys[] = {
1596 	"FIXED",
1597 	"COVER",
1598 	"PLACED",
1599 	"UNPLACED",
1600 	"SOURCE",
1601 	"WEIGHT",
1602 	"FOREIGN",
1603 	"REGION",
1604 	"GENERATE",
1605 	"PROPERTY",
1606 	"EEQMASTER",
1607 	NULL
1608     };
1609 
1610     while ((token = LefNextToken(f, TRUE)) != NULL)
1611     {
1612 	keyword = Lookup(token, component_keys);
1613 
1614 	if (keyword < 0)
1615 	{
1616 	    LefError(DEF_WARNING, "Unknown keyword \"%s\" in COMPONENT "
1617 			"definition; ignoring.\n", token);
1618 	    LefEndStatement(f);
1619 	    continue;
1620 	}
1621 	switch (keyword)
1622 	{
1623 	    case DEF_COMP_START:		/* "-" keyword */
1624 
1625 		/* Update the record of the number of components	*/
1626 		/* processed and spit out a message for every 5% done.	*/
1627 
1628 		processed++;
1629 
1630 		/* Get use and macro names */
1631 		token = LefNextToken(f, TRUE);
1632 		if (sscanf(token, "%511s", usename) != 1)
1633 		{
1634 		    LefError(DEF_ERROR, "Bad component statement:  Need use "
1635 				"and macro names\n");
1636 		    LefEndStatement(f);
1637 		    err_fatal++;
1638 		    break;
1639 		}
1640 		token = LefNextToken(f, TRUE);
1641 
1642 		// Watch for backslash-escaped instance names that have
1643 		// been sanitized for use in SPICE netlists with an
1644 		// extra backslash replacing the space, which needs to
1645 		// be converted back.
1646 
1647 		if (*usename == '\\') {
1648 		    char *sptr, *bptr;
1649 		    sptr = strchr(usename, ' ');
1650 		    if (sptr == NULL) {
1651 		        bptr = strrchr(usename + 1, '\\');
1652 		        if (bptr != NULL) *bptr = ' ';
1653 		    }
1654 		}
1655 
1656 		/* Find the corresponding macro */
1657 		OK = 0;
1658 		for (gateginfo = GateInfo; gateginfo; gateginfo = gateginfo->next) {
1659 		    if (!strcasecmp(gateginfo->gatename, token)) {
1660 			OK = 1;
1661 			break;
1662 		    }
1663 		}
1664 		if (!OK) {
1665 		    LefError(DEF_ERROR, "Could not find a macro definition for \"%s\"\n",
1666 				token);
1667 		    gate = NULL;
1668 		    err_fatal++;
1669 		}
1670 		else {
1671 		    gate = (GATE)malloc(sizeof(struct gate_));
1672 		    gate->gatename = strdup(usename);
1673 		    gate->gatetype = gateginfo;
1674 		    gate->nomirror = FALSE;
1675 		    gate->clientdata = (void *)NULL;
1676 		}
1677 
1678 		/* Now do a search through the line for "+" entries	*/
1679 		/* And process each.					*/
1680 
1681 		while ((token = LefNextToken(f, TRUE)) != NULL)
1682 		{
1683 		    if (*token == ';') break;
1684 		    if (*token != '+') continue;
1685 
1686 		    token = LefNextToken(f, TRUE);
1687 		    subkey = Lookup(token, property_keys);
1688 		    if (subkey < 0)
1689 		    {
1690 			LefError(DEF_WARNING, "Unknown component property \"%s\" in "
1691 				"COMPONENT definition; ignoring.\n", token);
1692 			continue;
1693 		    }
1694 		    switch (subkey)
1695 		    {
1696 			case DEF_PROP_PLACED:
1697 			case DEF_PROP_UNPLACED:
1698 			case DEF_PROP_FIXED:
1699 			case DEF_PROP_COVER:
1700 			    DefReadLocation(gate, f, oscale);
1701 			    break;
1702 			case DEF_PROP_SOURCE:
1703 			case DEF_PROP_WEIGHT:
1704 			case DEF_PROP_FOREIGN:
1705 			case DEF_PROP_REGION:
1706 			case DEF_PROP_GENERATE:
1707 			case DEF_PROP_PROPERTY:
1708 			case DEF_PROP_EEQMASTER:
1709 			    token = LefNextToken(f, TRUE);
1710 			    break;
1711 		    }
1712 		}
1713 		DefAddGateInstance(gate);
1714 		break;
1715 
1716 	    case DEF_COMP_END:
1717 		if (!LefParseEndStatement(f, sname))
1718 		{
1719 		    LefError(DEF_ERROR, "Component END statement missing.\n");
1720 		    keyword = -1;
1721 		    err_fatal++;
1722 		}
1723 
1724 		/* Finish final call by placing the cell use */
1725 		if ((total > 0) && (gate != NULL))
1726 		{
1727 		    // Nothing to do. . . gate has already been placed in list.
1728 		    gate = NULL;
1729 		}
1730 		break;
1731 	}
1732 	if (keyword == DEF_COMP_END) break;
1733     }
1734 
1735     if (processed == total) {
1736 	if (Verbose > 0)
1737 	    fprintf(stdout, "  Processed %d subcell instances total.\n", processed);
1738     }
1739     else
1740 	LefError(DEF_WARNING, "Warning:  Number of subcells read (%d) does not match "
1741 		"the number declared (%d).\n", processed, total);
1742     return err_fatal;
1743 }
1744 
1745 /*
1746  *------------------------------------------------------------
1747  *
1748  * DefRead --
1749  *
1750  *	Read a .def file and parse die area, track positions,
1751  *	components, pins, and nets.
1752  *
1753  * Results:
1754  *	Returns the units scale, so the routed output can be
1755  *	scaled to match the DEF file header.
1756  *
1757  * Side Effects:
1758  *	Many.
1759  *
1760  *------------------------------------------------------------
1761  */
1762 
1763 /* Enumeration of sections defined in DEF files */
1764 
1765 enum def_sections {DEF_VERSION = 0, DEF_NAMESCASESENSITIVE,
1766 	DEF_UNITS, DEF_DESIGN, DEF_REGIONS, DEF_ROW, DEF_TRACKS,
1767 	DEF_GCELLGRID, DEF_DIVIDERCHAR, DEF_BUSBITCHARS,
1768 	DEF_PROPERTYDEFINITIONS, DEF_DEFAULTCAP, DEF_TECHNOLOGY,
1769 	DEF_HISTORY, DEF_DIEAREA, DEF_COMPONENTS, DEF_VIAS,
1770 	DEF_PINS, DEF_PINPROPERTIES, DEF_SPECIALNETS,
1771 	DEF_NETS, DEF_IOTIMINGS, DEF_SCANCHAINS, DEF_BLOCKAGES,
1772 	DEF_CONSTRAINTS, DEF_GROUPS, DEF_EXTENSION,
1773 	DEF_END};
1774 
1775 int
DefRead(char * inName,float * retscale)1776 DefRead(char *inName, float *retscale)
1777 {
1778     FILE *f;
1779     char filename[256];
1780     char namepos[32];
1781     char *token;
1782     int keyword, dscale, total;
1783     int curlayer = -1, channels;
1784     int i;
1785     int err_fatal = 0;
1786     float oscale;
1787     double start, step;
1788     double llx, lly, urx, ury, locpitch;
1789     double dXlowerbound, dYlowerbound, dXupperbound, dYupperbound;
1790     char corient = '.';
1791     DSEG diearea;
1792     ROW newrow;
1793 
1794     static char *orientations[] = {
1795 	"N", "S", "E", "W", "FN", "FS", "FE", "FW"
1796     };
1797     static int oflags[] = {
1798 	RN, RS, RE, RW, RN | RF, RS | RF, RE | RF, RW | RF
1799     };
1800 
1801     static char *sections[] = {
1802 	"VERSION",
1803 	"NAMESCASESENSITIVE",
1804 	"UNITS",
1805 	"DESIGN",
1806 	"REGIONS",
1807 	"ROW",
1808 	"TRACKS",
1809 	"GCELLGRID",
1810 	"DIVIDERCHAR",
1811 	"BUSBITCHARS",
1812 	"PROPERTYDEFINITIONS",
1813 	"DEFAULTCAP",
1814 	"TECHNOLOGY",
1815 	"HISTORY",
1816 	"DIEAREA",
1817 	"COMPONENTS",
1818 	"VIAS",
1819 	"PINS",
1820 	"PINPROPERTIES",
1821 	"SPECIALNETS",
1822 	"NETS",
1823 	"IOTIMINGS",
1824 	"SCANCHAINS",
1825 	"BLOCKAGES",
1826 	"CONSTRAINTS",
1827 	"GROUPS",
1828 	"BEGINEXT",
1829 	"END",
1830 	NULL
1831     };
1832 
1833     if (!strrchr(inName, '.'))
1834 	sprintf(filename, "%s.def", inName);
1835     else
1836 	strcpy(filename, inName);
1837 
1838     f = fopen(filename, "r");
1839 
1840     if (f == NULL)
1841     {
1842 	fprintf(stderr, "Cannot open input file: ");
1843 	perror(filename);
1844 	*retscale = (float)0.0;
1845 	return 1;
1846     }
1847 
1848     /* Initialize */
1849 
1850     if (Verbose > 0) {
1851 	fprintf(stdout, "Reading DEF data from file %s.\n", filename);
1852 	fflush(stdout);
1853     }
1854 
1855     oscale = 1;
1856     lefCurrentLine = 0;
1857 
1858     DefHashInit();
1859 
1860     /* Read file contents */
1861 
1862     while ((token = LefNextToken(f, TRUE)) != NULL)
1863     {
1864 	keyword = Lookup(token, sections);
1865 	if (keyword < 0)
1866 	{
1867 	    LefError(DEF_WARNING, "Unknown keyword \"%s\" in DEF file; "
1868 			"ignoring.\n", token);
1869 	    LefEndStatement(f);
1870 	    continue;
1871 	}
1872 	if (keyword != DEF_TRACKS) corient = '.';
1873 
1874 	switch (keyword)
1875 	{
1876 	    case DEF_VERSION:
1877 		LefEndStatement(f);
1878 		break;
1879 	    case DEF_NAMESCASESENSITIVE:
1880 		LefEndStatement(f);
1881 		break;
1882 	    case DEF_TECHNOLOGY:
1883 		token = LefNextToken(f, TRUE);
1884 		if (Verbose > 0)
1885 		    fprintf(stdout, "Diagnostic: DEF file technology: \"%s\"\n",
1886 				token);
1887 		LefEndStatement(f);
1888 	 	break;
1889 	    case DEF_REGIONS:
1890 		LefSkipSection(f, sections[DEF_REGIONS]);
1891 		break;
1892 	    case DEF_DESIGN:
1893 		token = LefNextToken(f, TRUE);
1894 		if (Verbose > 0)
1895 		    fprintf(stdout, "Diagnostic: Design name: \"%s\"\n", token);
1896 		DEFDesignName = strdup(token);
1897 		LefEndStatement(f);
1898 		break;
1899 	    case DEF_UNITS:
1900 		token = LefNextToken(f, TRUE);
1901 		token = LefNextToken(f, TRUE);
1902 		token = LefNextToken(f, TRUE);
1903 		if (sscanf(token, "%d", &dscale) != 1)
1904 		{
1905 		    LefError(DEF_ERROR, "Invalid syntax for UNITS statement.\n");
1906 		    LefError(DEF_WARNING, "Assuming default value of 100\n");
1907 		    dscale = 100;
1908 		}
1909 		/* We don't care if the scale is 100, 200, 1000, or 2000. */
1910 		/* Do we need to deal with numeric roundoff issues?	  */
1911 		oscale *= (float)dscale;
1912 		LefEndStatement(f);
1913 		break;
1914 	    case DEF_ROW:
1915 		newrow = (ROW)malloc(sizeof(struct row_));
1916 		token = LefNextToken(f, TRUE);
1917 		newrow->rowname = strdup(token);
1918 		token = LefNextToken(f, TRUE);
1919 		newrow->sitename = strdup(token);
1920 		token = LefNextToken(f, TRUE);
1921 		sscanf(token, "%d", &newrow->x);
1922 		token = LefNextToken(f, TRUE);
1923 		sscanf(token, "%d", &newrow->y);
1924 		token = LefNextToken(f, TRUE);
1925 		keyword = Lookup(token, orientations);
1926 		if (keyword < 0)
1927 		    newrow->orient = 0;
1928 		else
1929 		    newrow->orient = oflags[keyword];
1930 		token = LefNextToken(f, TRUE);	    /* skip "DO" */
1931 		token = LefNextToken(f, TRUE);
1932 		sscanf(token, "%d", &newrow->xnum);
1933 		token = LefNextToken(f, TRUE);	    /* skip "BY" */
1934 		token = LefNextToken(f, TRUE);
1935 		sscanf(token, "%d", &newrow->ynum);
1936 		token = LefNextToken(f, TRUE);	    /* skip "STEP" */
1937 		token = LefNextToken(f, TRUE);
1938 		sscanf(token, "%d", &newrow->xstep);
1939 		token = LefNextToken(f, TRUE);
1940 		sscanf(token, "%d", &newrow->ystep);
1941 		sprintf(namepos, "%d", newrow->y);
1942 		HashPtrInstall(namepos, newrow, &RowTable);
1943 		LefEndStatement(f);
1944 		break;
1945 	    case DEF_TRACKS:
1946 		token = LefNextToken(f, TRUE);
1947 		if (strlen(token) != 1) {
1948 		    LefError(DEF_ERROR, "Problem parsing track orientation (X or Y).\n");
1949 		}
1950 		corient = tolower(token[0]);	// X or Y
1951 		token = LefNextToken(f, TRUE);
1952 		if (sscanf(token, "%lg", &start) != 1) {
1953 		    LefError(DEF_ERROR, "Problem parsing track start position.\n");
1954 		    err_fatal++;
1955 		}
1956 		token = LefNextToken(f, TRUE);
1957 		if (strcmp(token, "DO")) {
1958 		    LefError(DEF_ERROR, "TRACKS missing DO loop.\n");
1959 		    err_fatal++;
1960 		}
1961 		token = LefNextToken(f, TRUE);
1962 		if (sscanf(token, "%d", &channels) != 1) {
1963 		    LefError(DEF_ERROR, "Problem parsing number of track channels.\n");
1964 		    err_fatal++;
1965 		}
1966 		token = LefNextToken(f, TRUE);
1967 		if (strcmp(token, "STEP")) {
1968 		    LefError(DEF_ERROR, "TRACKS missing STEP size.\n");
1969 		    err_fatal++;
1970 		}
1971 		token = LefNextToken(f, TRUE);
1972 		if (sscanf(token, "%lg", &step) != 1) {
1973 		    LefError(DEF_ERROR, "Problem parsing track step size.\n");
1974 		    err_fatal++;
1975 		}
1976 		token = LefNextToken(f, TRUE);
1977 		if (!strcmp(token, "LAYER")) {
1978 		    curlayer = LefReadLayer(f, FALSE);
1979 		}
1980 		if (corient == 'x') {
1981 		    locpitch = step / oscale;
1982 		    if ((PitchX == 0.0) || ((locpitch < PitchX) && (locpitch != 0)))
1983 			PitchX = locpitch;
1984 		    llx = start;
1985 		    urx = start + step * channels;
1986 		    if ((llx / oscale) < Xlowerbound)
1987 			Xlowerbound = llx / oscale;
1988 		    if ((urx / oscale) > Xupperbound)
1989 			Xupperbound = urx / oscale;
1990 		}
1991 		else {
1992 		    locpitch = step / oscale;
1993 		    if ((PitchY == 0.0) || ((locpitch < PitchY) && (locpitch != 0)))
1994 			PitchY = locpitch;
1995 		    lly = start;
1996 		    ury = start + step * channels;
1997 		    if ((lly / oscale) < Ylowerbound)
1998 			Ylowerbound = lly / oscale;
1999 		    if ((ury / oscale) > Yupperbound)
2000 			Yupperbound = ury / oscale;
2001 		}
2002 		LefEndStatement(f);
2003 		break;
2004 	    case DEF_GCELLGRID:
2005 		LefEndStatement(f);
2006 		break;
2007 	    case DEF_DIVIDERCHAR:
2008 		LefEndStatement(f);
2009 		break;
2010 	    case DEF_BUSBITCHARS:
2011 		LefEndStatement(f);
2012 		break;
2013 	    case DEF_HISTORY:
2014 		LefEndStatement(f);
2015 		break;
2016 	    case DEF_DIEAREA:
2017 		diearea = LefReadRect(f, 0, oscale); // no current layer, use 0
2018 		dXlowerbound = diearea->x1;
2019 		dYlowerbound = diearea->y1;
2020 		dXupperbound = diearea->x2;
2021 		dYupperbound = diearea->y2;
2022 		/* Seed actual lower/upper bounds with the midpoint */
2023 		Xlowerbound = (diearea->x1 + diearea->x2) / 2;
2024 		Ylowerbound = (diearea->y1 + diearea->y2) / 2;
2025 		Xupperbound = Xlowerbound;
2026 		Yupperbound = Ylowerbound;
2027 		LefEndStatement(f);
2028 		break;
2029 	    case DEF_PROPERTYDEFINITIONS:
2030 		LefSkipSection(f, sections[DEF_PROPERTYDEFINITIONS]);
2031 		break;
2032 	    case DEF_DEFAULTCAP:
2033 		LefSkipSection(f, sections[DEF_DEFAULTCAP]);
2034 		break;
2035 	    case DEF_COMPONENTS:
2036 		token = LefNextToken(f, TRUE);
2037 		if (sscanf(token, "%d", &total) != 1) total = 0;
2038 		LefEndStatement(f);
2039 		err_fatal += DefReadComponents(f, sections[DEF_COMPONENTS], oscale, total);
2040 		break;
2041 	    case DEF_BLOCKAGES:
2042 		token = LefNextToken(f, TRUE);
2043 		if (sscanf(token, "%d", &total) != 1) total = 0;
2044 		LefEndStatement(f);
2045 		DefReadBlockages(f, sections[DEF_BLOCKAGES], oscale, total);
2046 		break;
2047 	    case DEF_VIAS:
2048 		token = LefNextToken(f, TRUE);
2049 		if (sscanf(token, "%d", &total) != 1) total = 0;
2050 		LefEndStatement(f);
2051 		DefReadVias(f, sections[DEF_VIAS], oscale, total);
2052 		break;
2053 	    case DEF_PINS:
2054 		token = LefNextToken(f, TRUE);
2055 		if (sscanf(token, "%d", &total) != 1) total = 0;
2056 		LefEndStatement(f);
2057 		DefReadPins(f, sections[DEF_PINS], oscale, total);
2058 		break;
2059 	    case DEF_PINPROPERTIES:
2060 		LefSkipSection(f, sections[DEF_PINPROPERTIES]);
2061 		break;
2062 	    case DEF_SPECIALNETS:
2063 		token = LefNextToken(f, TRUE);
2064 		if (sscanf(token, "%d", &total) != 1) total = 0;
2065 		LefEndStatement(f);
2066 		numSpecial = DefReadNets(f, sections[DEF_SPECIALNETS], oscale, TRUE,
2067 				total);
2068 		break;
2069 	    case DEF_NETS:
2070 		token = LefNextToken(f, TRUE);
2071 		if (sscanf(token, "%d", &total) != 1) total = 0;
2072 		LefEndStatement(f);
2073 		DefReadNets(f, sections[DEF_NETS], oscale, FALSE, total);
2074 		break;
2075 	    case DEF_IOTIMINGS:
2076 		LefSkipSection(f, sections[DEF_IOTIMINGS]);
2077 		break;
2078 	    case DEF_SCANCHAINS:
2079 		LefSkipSection(f, sections[DEF_SCANCHAINS]);
2080 		break;
2081 	    case DEF_CONSTRAINTS:
2082 		LefSkipSection(f, sections[DEF_CONSTRAINTS]);
2083 		break;
2084 	    case DEF_GROUPS:
2085 		LefSkipSection(f, sections[DEF_GROUPS]);
2086 		break;
2087 	    case DEF_EXTENSION:
2088 		LefSkipSection(f, sections[DEF_EXTENSION]);
2089 		break;
2090 	    case DEF_END:
2091 		if (!LefParseEndStatement(f, "DESIGN"))
2092 		{
2093 		    LefError(DEF_ERROR, "END statement out of context.\n");
2094 		    keyword = -1;
2095 		}
2096 		break;
2097 	}
2098 	if (keyword == DEF_END) break;
2099     }
2100     if (Verbose > 0)
2101 	fprintf(stdout, "DEF read: Processed %d lines.\n", lefCurrentLine);
2102     LefError(DEF_ERROR, NULL);	/* print statement of errors, if any, and reset */
2103 
2104     /* If there were no TRACKS statements, then use the DIEAREA */
2105     if (Xlowerbound == Xupperbound) {
2106 	Xlowerbound = dXlowerbound;
2107 	Xupperbound = dXupperbound;
2108     }
2109     if (Ylowerbound == Yupperbound) {
2110 	Ylowerbound = dYlowerbound;
2111 	Yupperbound = dYupperbound;
2112     }
2113 
2114     /* Cleanup */
2115 
2116     if (f != NULL) fclose(f);
2117     *retscale = oscale;
2118     return err_fatal;
2119 }
2120