1 /*------------------------------------------------------*/
2 /* addspacers ---					*/
3 /*							*/
4 /*  Tool for adding fill cells and other post-placement	*/
5 /*  cells and data into a DEF format layout.		*/
6 /*							*/
7 /*  Primary functions are:				*/
8 /*							*/
9 /*  1) Fill the core area out to the bounding box with	*/
10 /*     fill cells to make the edges straight and fill	*/
11 /*     any gaps.					*/
12 /*							*/
13 /*  2) Create power stripes and power posts, adding	*/
14 /*     additional fill under (or near, as available)	*/
15 /*     the power stripes if requested.			*/
16 /*							*/
17 /*  3) Adjust pin positions to match any stretching of	*/
18 /*     the cell done in (2)				*/
19 /*							*/
20 /*  4) Adjust obstruction layers to match any		*/
21 /*     stretching of the cell done in (2)		*/
22 /*							*/
23 /*  5) Write the modified DEF layout			*/
24 /*							*/
25 /*  6) Write the modified obstruction file (if		*/
26 /*     modified).					*/
27 /*							*/
28 /*------------------------------------------------------*/
29 /*							*/
30 /* This file previously addspacers.tcl until it became	*/
31 /* painfully obvious that the amount of calculation	*/
32 /* involved made it a very poor choice to be done by	*/
33 /* an interpreter.					*/
34 /*							*/
35 /*------------------------------------------------------*/
36 
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <unistd.h>     /* For getopt() */
41 #include <math.h>
42 #include <ctype.h>
43 #include <float.h>
44 
45 #include "hash.h"
46 #include "readlef.h"
47 #include "readdef.h"
48 
49 /* Flags fields */
50 
51 #define NOSTRETCH  1
52 #define OBSTRUCT   2
53 #define VERBOSE    4
54 #define FILLWARNED 8
55 
56 /* Structure used to contain core area bounding box.  Also records  */
57 /* core site height and width.					    */
58 
59 typedef struct _corebbox *COREBBOX;
60 
61 typedef struct _corebbox {
62     int llx;	    /* Layout bounds */
63     int lly;
64     int urx;
65     int ury;
66     int urx_exp;    /* Expanded core urx */
67     int sitew;	    /* Core site width */
68     int siteh;	    /* Core site height */
69     int fillmin;    /* Minimum fill cell width */
70     int orient;	    /* Orientation of the first (lowest) row */
71 } corebbox;
72 
73 /* Structure used to hold the final calculated pitch and width of stripes */
74 
75 typedef struct _stripeinfo *SINFO;
76 
77 typedef struct _stripeinfo {
78     int width;
79     int pitch;
80     int offset;
81     int stretch;   /* Maximum amount of layout stretching */
82     int number;    /* Total number of stripes */
83 } stripeinfo;
84 
85 /* List of gates (used to sort fill cells) */
86 typedef struct filllist_ *FILLLIST;
87 
88 struct filllist_ {
89     FILLLIST next;
90     FILLLIST last;
91     GATE gate;
92     int width;
93 };
94 
95 /* Structures for defining a power stripe. */
96 
97 typedef struct _powerpost *PPOST;
98 
99 typedef struct _powerpost {
100     PPOST   next;
101     DSEG    strut;
102     LefList viagen;
103 } powerpost;
104 
105 typedef struct _powerstripe *PSTRIPE;
106 
107 typedef struct _powerstripe {
108     PSTRIPE	next;	    // One stripe definition centered on X = 0
109     PPOST	posts;	    // All posts for one stripe, centered on X = 0
110     DSEG	stripe;
111     int		offset;	    // Horizontal start of posts
112     int		num;	    // Number of stripes
113     int		pitch;	    // Spacing between stripes
114     char       *name;	    // Net name of power rail
115 } powerstripe;
116 
117 /* Hash table of instances hashed by (X, Y) position */
118 struct hashtable CellPosTable;
119 
120 /* Hash table of site macros hashed by site name */
121 struct hashtable SiteDefTable;
122 
123 /* Forward declarations */
124 unsigned char check_overcell_capable(unsigned char Flags);
125 FILLLIST generate_fill(char *fillcellname, float rscale, COREBBOX corearea,
126 	unsigned char Flags);
127 SINFO generate_stripefill(char *VddNet, char *GndNet,
128 	char *stripepat, float stripewidth_t, float stripepitch_t,
129 	char *fillcellname, float scale, FILLLIST fillcells,
130 	COREBBOX corearea, unsigned char Flags);
131 void fix_obstructions(char *definname, SINFO stripevals, float scale,
132 	unsigned char Flags);
133 PSTRIPE generate_stripes(SINFO stripevals, FILLLIST fillcells,
134 	COREBBOX corearea, char *stripepat, char *VddNet, char *GndNet,
135 	float scale, unsigned char Flags);
136 void write_output(char *definname, char *defoutname, float scale,
137 	    COREBBOX corearea, SINFO stripevals, PSTRIPE rails,
138 	    char *VddNet, char *GndNet, unsigned char Flags);
139 void helpmessage(FILE *outf);
140 
141 /*--------------------------------------------------------------*/
142 /*--------------------------------------------------------------*/
143 
main(int argc,char * argv[])144 int main (int argc, char *argv[])
145 {
146     int i, result;
147     unsigned char Flags;
148     float rscale;
149     struct cellrec *topcell;
150     COREBBOX corearea;
151     FILLLIST fillcells;
152     SINFO stripevals;
153     PSTRIPE rails;
154     char *cptr;
155 
156     char *definname = NULL;
157     char *fillcellname = NULL;
158     char *defoutname = NULL;
159 
160     float stripewidth_t, stripepitch_t;
161     static char* default_stripepat = "PG";
162     char *stripepat = default_stripepat;
163 
164     char *VddNet = NULL;
165     char *GndNet = NULL;
166 
167     Flags = 0;
168     stripewidth_t = stripepitch_t = 0.0;
169 
170     while ((i = getopt(argc, argv, "hHvOno:l:p:g:f:w:P:s:")) != EOF) {
171         switch( i ) {
172 	    case 'v':
173 		Flags |= VERBOSE;
174 		/* Also set global variable used by readlef.c */
175 		Verbose = 1;
176 		break;
177             case 'h':
178             case 'H':
179                 helpmessage(stdout);
180                 exit(0);
181                 break;
182 	    case 'n':
183 		Flags |= NOSTRETCH;
184 		break;
185 	    case 'O':
186 		Flags |= OBSTRUCT;
187 		break;
188 	    case 'w':
189 		if (sscanf(optarg, "%g", &stripewidth_t) != 1) {
190 		    fprintf(stderr, "Cannot read numeric value from \"%s\"\n", optarg);
191 		}
192 		break;
193 	    case 'P':
194 		if (sscanf(optarg, "%g", &stripepitch_t) != 1) {
195 		    fprintf(stderr, "Cannot read numeric value from \"%s\"\n", optarg);
196 		}
197 		break;
198 	    case 'o':
199 	        defoutname = strdup(optarg);
200 		break;
201 	    case 'f':
202 	        fillcellname = strdup(optarg);
203 		break;
204 	    case 's':
205 		if (!strcmp(optarg, "tripe")) {
206 		    /* Accept the argument "-stripe <width> <pitch> <pattern>"	*/
207 		    /* that was the option for the old addspacers.tcl script.	*/
208 		    /* Combines width, pitch, and pattern in one argument.	*/
209 		    if (sscanf(argv[optind], "%g", &stripewidth_t) != 1) {
210 			fprintf(stderr, "Cannot read numeric value from \"%s\"\n", argv[optind]);
211 		    }
212 		    optind++;
213 		    if (sscanf(argv[optind], "%g", &stripepitch_t) != 1) {
214 			fprintf(stderr, "Cannot read numeric value from \"%s\"\n", argv[optind]);
215 		    }
216 		    optind++;
217 		    stripepat = strdup(argv[optind]);
218 		    optind++;
219 		}
220 		else {
221 		    stripepat = strdup(optarg);
222 		}
223 		break;
224             case 'l':
225                 LefRead(optarg);        /* Can be called multiple times */
226                 break;
227             case 'p':
228                 VddNet = strdup(optarg);
229 		if ((cptr = strchr(VddNet, ',')) != NULL) *cptr = '\0';
230                 break;
231             case 'g':
232                 GndNet = strdup(optarg);
233 		if ((cptr = strchr(GndNet, ',')) != NULL) *cptr = '\0';
234                 break;
235             default:
236                 fprintf(stderr,"Bad switch \"%c\"\n", (char)i);
237                 helpmessage(stderr);
238                 return 1;
239         }
240     }
241 
242     if (optind < argc) {
243 	char *pptr;
244 
245         definname = (char *)malloc(strlen(argv[optind]) + 5);
246 	strcpy(definname, argv[optind]);
247 	pptr = strrchr(argv[optind], '.');
248 	if (pptr == NULL) strcat(definname, ".def");
249         optind++;
250     }
251     else {
252         fprintf(stderr, "Couldn't find a filename for DEF input file.\n");
253         helpmessage(stderr);
254         return 1;
255     }
256     optind++;
257 
258     result = DefRead(definname, &rscale);
259 
260     corearea = (COREBBOX)malloc(sizeof(corebbox));
261 
262     Flags |= check_overcell_capable(Flags);
263     fillcells = generate_fill(fillcellname, rscale, corearea, Flags);
264     if (fillcells == NULL) {
265 	fprintf(stderr, "Failed to parse any fill cells from the standard cell library.\n");
266 	return 1;
267     }
268     stripevals = generate_stripefill(VddNet, GndNet, stripepat,
269 	    stripewidth_t, stripepitch_t, fillcellname, rscale, fillcells,
270 	    corearea, Flags);
271     fix_obstructions(definname, stripevals, rscale, Flags);
272     rails = generate_stripes(stripevals, fillcells, corearea, stripepat,
273 	    VddNet, GndNet, rscale, Flags);
274     write_output(definname, defoutname, rscale, corearea, stripevals,
275 	    rails, VddNet, GndNet, Flags);
276 
277     return 0;
278 }
279 
280 /*--------------------------------------------------------------*/
281 /* Find empty spaces in the DEF layout and insert fill macros	*/
282 /*--------------------------------------------------------------*/
283 
284 FILLLIST
generate_fill(char * fillcellname,float scale,COREBBOX corearea,unsigned char Flags)285 generate_fill(char *fillcellname, float scale, COREBBOX corearea, unsigned char Flags)
286 {
287     GATE gate, newfillinst;
288     ROW row;
289     int isfill, orient;
290     int defcorew = 1, defcoreh = 0, testh, fillh;
291     int corew = 1, coreh = 0;
292     int instx, insty, instw, insth, fnamelen;
293     int x, y, dx, nx, fillmin;
294     char posname[32];
295 
296     int corellx = 0;
297     int corelly = 0;
298     int coreurx = 0;
299     int coreury = 0;
300 
301     FILLLIST fillcells = NULL;
302     FILLLIST newfill, testfill;
303 
304     InitializeHashTable(&SiteDefTable, TINYHASHSIZE);
305 
306     /* Parse library macros and find CORE SITE definition */
307 
308     testh = 0;
309     for (gate = GateInfo; gate; gate = gate->next)
310     {
311 	/* NOTE: "site_" is prepended during DEF read */
312 	if (!strncmp(gate->gatename, "site_", 5)) {
313 	    if (gate->gateclass == MACRO_CLASS_CORE) {
314 		defcorew = (int)(roundf(gate->width * scale));
315 		defcoreh = (int)(roundf(gate->height * scale));
316 		if (defcoreh > 0) {
317 		    if ((testh == 0) || (defcoreh < testh))
318 			testh = defcoreh;
319 		    HashPtrInstall(gate->gatename, gate, &SiteDefTable);
320 		}
321 	    }
322 	}
323     }
324     if (defcorew == 0) {
325 	fprintf(stderr, "Warning: failed to find any core site.\n");
326 	/* Use route pitch for step size */
327 	defcorew = (int)(roundf(LefGetRoutePitch(0) * scale));
328     }
329     if (defcorew == 0) {
330 	fprintf(stderr, "Error: failed to find any core site or route pitch.\n");
331 	return NULL;
332     }
333 
334     /* Parse library macros and find fill cells.  Use "fillcellname" as	a   */
335     /* prefix, if given;  if not, find spacer cells by class.		    */
336 
337     fnamelen = (fillcellname) ? strlen(fillcellname) : 0;
338 
339     for (gate = GateInfo; gate; gate = gate->next)
340     {
341 	isfill = FALSE;
342 	if (fillcellname) {
343 	    if (!strncmp(gate->gatename, fillcellname, fnamelen))
344 		isfill = TRUE;
345 	}
346 	else if (gate->gatesubclass == MACRO_SUBCLASS_SPACER)
347 	    isfill = TRUE;
348 
349 	if (isfill == TRUE) {
350 	    newfill = (FILLLIST)malloc(sizeof(struct filllist_));
351 	    newfill->gate = gate;
352 	    newfill->width = (int)(roundf(gate->width * scale));
353 
354 	    /* Insert in fill list in width order, high to low */
355 	    if (fillcells == NULL) {
356 		newfill->next = newfill->last = NULL;
357 		fillcells = newfill;
358 	    }
359 	    else {
360 		for (testfill = fillcells; testfill; testfill = testfill->next) {
361 		    if (testfill->width < newfill->width) {
362 			/* insert before */
363 			newfill->next = testfill;
364 			newfill->last = testfill->last;
365 			if (testfill->last == NULL)
366 			    fillcells = newfill;
367 			else
368 			    testfill->last->next = newfill;
369 			testfill->last = newfill;
370 			break;
371 		    }
372 		    else if (testfill->next == NULL) {
373 			/* put at end */
374 			newfill->next = NULL;
375 			testfill->next = newfill;
376 			newfill->last = testfill;
377 			break;
378 		    }
379 		}
380 	    }
381 	}
382     }
383 
384     if (fillcells == NULL) {
385 	fprintf(stderr, "Error:  No fill cells have been specified or found.\n");
386 	return NULL;
387     }
388 
389     if (fillcells) {
390 	fillh = (int)(roundf(fillcells->gate->height * scale));
391 	if ((defcoreh == 0) || (defcoreh < fillh)) {
392 	    /* Use fill cell height for core height */
393 	    defcoreh = fillh;
394 	}
395     }
396     if (defcoreh == 0) {
397 	fprintf(stderr, "Error: failed to find any core site or standard cell height.\n");
398 	return NULL;
399     }
400 
401     /* Rehash all instances by position */
402     /* Find minimum and maximum bounds, and record cell in lower left position */
403 
404     InitializeHashTable(&CellPosTable, LARGEHASHSIZE);
405 
406     /* Do one pass to get core boundaries */
407 
408     for (gate = Nlgates; gate; gate = gate->next)
409     {
410 	/* Do not evaluate pins, only core cells */
411 	if (gate->gatetype == NULL) continue;
412 
413 	instx = (int)(roundf(gate->placedX * scale));
414 	insty = (int)(roundf(gate->placedY * scale));
415 	instw = (int)(roundf(gate->width * scale));
416 	insth = (int)(roundf(gate->height * scale));
417 
418 	if (corellx == coreurx) {
419 	    corellx = instx;
420 	    coreurx = instx + instw;
421 	    corelly = insty;
422 	    coreury = insty + insth;
423 	}
424 	else {
425 	    if (instx < corellx) corellx = instx;
426 	    else if (instx + instw > coreurx) coreurx = instx + instw;
427 
428 	    if (insty < corelly) corelly = insty;
429 	    else if (insty + insth > coreury) coreury = insty + insth;
430 	}
431     }
432 
433     /* Do second pass to record cell positions in a hash table */
434 
435     for (gate = Nlgates; gate; gate = gate->next)
436     {
437 	int locy, m;
438 
439 	/* Do not evaluate pins, only core cells */
440 	if (gate->gatetype == NULL) continue;
441 
442 	instx = (int)(roundf(gate->placedX * scale));
443 	insty = (int)(roundf(gate->placedY * scale));
444 	instw = (int)(roundf(gate->width * scale));
445 	insth = (int)(roundf(gate->height * scale));
446 
447 	/* If cell left boundary does not align with core sites,    */
448 	/* adjust is so that it does.  Note that this does not	    */
449 	/* change the actual position of the cell, just how it is   */
450 	/* marked in the table of cells searched by position.	    */
451 
452 	m = (instx - corellx) / defcorew;
453 	if ((corellx + m * defcorew) != instx) {
454 	    fprintf(stdout, "Cell %s left edge is not aligned with "
455 				"site boundary.\n", gate->gatename);
456 	    instx = corellx + m * defcorew;
457 	}
458 
459 	sprintf(posname, "%dx%d", instx, insty);
460 	HashPtrInstall(posname, gate, &CellPosTable);
461 
462 	/* If cell is a multiple row height, mark its position in all	*/
463 	/* rows that it occupies.					*/
464 
465 	if (insth > defcoreh) {
466 	    locy = insty + defcoreh;
467 	    while (locy < insty + insth) {
468 		sprintf(posname, "%dx%d", instx, locy);
469 		HashPtrInstall(posname, gate, &CellPosTable);
470 		locy += defcoreh;
471 	    }
472 	}
473     }
474 
475 
476     if (Flags & VERBOSE) {
477 	row = DefFindRow(corelly);
478 	if (row) {
479 	    sprintf(posname, "site_%s", row->sitename);
480 	    gate = (GATE)HashLookup(posname, &SiteDefTable);
481 	    if (gate && (gate->width > 0) && (gate->height > 0)) {
482 		defcorew = (int)(roundf(gate->width * scale));
483 		defcoreh = (int)(roundf(gate->height * scale));
484 	    }
485 	}
486 	fprintf(stdout, "Default core site is %g x %g um\n",
487 		    (float)defcorew / scale, (float)defcoreh / scale);
488     }
489 
490     fprintf(stdout, "Initial core layout: (%d %d) to (%d %d) (scale um * %d)\n",
491 		corellx, corelly, coreurx, coreury, (int)scale);
492 
493     if (Flags & VERBOSE) fprintf(stdout, "Adding fill cells.\n");
494 
495     /* Find the orientation of the first row and record this	    */
496     /* in corearea.  NOTE:  This is simpler if the DEF file records */
497     /* ROWs, something that needs to be done in place2def.	    */
498 
499     row = DefFindRow(corelly);
500     if (row) {
501 	corearea->orient = row->orient & (RN | RS);
502     }
503     else {
504 	corearea->orient = RN;
505 	y = corelly;
506 	x = corellx;
507 	while (x < coreurx) {
508 	    sprintf(posname, "%dx%d", x, y);
509 	    gate = (GATE)HashLookup(posname, &CellPosTable);
510 	    if (gate != NULL) {
511 		corearea->orient = gate->orient & (RN | RS);
512 		break;
513 	    }
514 	    x += testfill->width;
515 	}
516     }
517     orient = corearea->orient;
518 
519     /* Starting from the lower-left corner, find gate at each site  */
520     /* position.  If there is no gate at the site position, then    */
521     /* find the next gate forward, and add fill.		    */
522 
523     /* NOTE:  This routine does not account for obstruction areas   */
524     /* used to define a non-rectangular core area (to be done)	    */
525 
526     for (y = corelly; y < coreury;) {
527 	corew = defcorew;
528 	coreh = defcoreh;
529 	row = DefFindRow(y);
530 	if (row) {
531 	    sprintf(posname, "site_%s", row->sitename);
532 	    gate = (GATE)HashLookup(posname, &SiteDefTable);
533 	    if (gate && (gate->width > 0) && (gate->height > 0)) {
534 		corew = (int)(roundf(gate->width * scale));
535 		coreh = (int)(roundf(gate->height * scale));
536 	    }
537 	}
538 	x = corellx;
539 	while (x < coreurx) {
540 	    sprintf(posname, "%dx%d", x, y);
541 	    gate = (GATE)HashLookup(posname, &CellPosTable);
542 	    if (gate == NULL) {
543 		for (nx = x + corew; nx < coreurx; nx += corew) {
544 		    sprintf(posname, "%dx%d", nx, y);
545 		    gate = (GATE)HashLookup(posname, &CellPosTable);
546 		    if (gate != NULL) break;
547 		}
548 		if (Flags & VERBOSE)
549 		    fprintf(stdout, "Add fill from (%d %d) to (%d %d)\n",
550 				x, y, nx, y);
551 		dx = nx - x;
552 
553 		while (dx > 0) {
554 		    for (testfill = fillcells; testfill; testfill = testfill->next) {
555 			if (testfill->width <= dx) break;
556 		    }
557 		    if (testfill == NULL) {
558 			if (nx == coreurx) {
559 			    if (!(Flags & FILLWARNED)) {
560 				fprintf(stderr, "Notice: Right edge of layout"
561 					    " cannot be cleanly aligned due to\n");
562 				fprintf(stderr, "limited fill cell widths.\n");
563 			    }
564 			    Flags |= FILLWARNED;    // Do not repeat this message
565 			    x = nx;
566 			    dx = 0;
567 			    break;
568 			}
569 			else {
570 			    fprintf(stderr, "Error: Empty slot at (%g, %g) is smaller"
571 				    " than any available fill cell.\n",
572 				    (float)x / scale, (float)y / scale);
573 			}
574 		    }
575 
576 		    /* Create new fill instance */
577 		    newfillinst = (GATE)malloc(sizeof(struct gate_));
578 		    if (testfill)
579 			newfillinst->gatetype = testfill->gate;
580 		    else
581 			newfillinst->gatetype = NULL;	/* placeholder */
582 		    sprintf(posname, "FILL%dx%d", x, y);
583 		    newfillinst->gatename = strdup(posname);
584 		    newfillinst->placedX = (double)x / (double)scale;
585 		    newfillinst->placedY = (double)y / (double)scale;
586 		    newfillinst->clientdata = (void *)NULL;
587 		    newfillinst->orient = (row) ? row->orient : orient;
588 		    newfillinst->nomirror = testfill->gate->nomirror;
589 		    /* Flip-restricted cells must be either "N" or "FS" */
590 		    if ((newfillinst->nomirror == TRUE) &&
591 			    (newfillinst->orient == RS)) newfillinst->orient |= RF;
592 		    DefAddGateInstance(newfillinst);
593 
594 		    /* Hash the new instance position */
595 		    sprintf(posname, "%dx%d", x, y);
596 		    HashPtrInstall(posname, newfillinst, &CellPosTable);
597 
598 		    if (testfill) {
599 			x += testfill->width;
600 			dx -= testfill->width;
601 		    }
602 		    else {
603 			newfillinst->width = dx;
604 			x += dx;
605 			dx = 0;
606 		    }
607 		}
608 	    }
609 	    else {
610 		int gw = (int)(roundf(gate->width * scale));
611 		int m = gw / corew;
612 		if ((corew * m) != gw) {
613 		    fprintf(stdout, "Cell %s right edge is not aligned with "
614 				"site boundary.\n", gate->gatename);
615 		    gw = corew * (m + 1);   /* Move to the next site boundary */
616 		}
617 		x += gw;
618 	    }
619 	}
620 	/* Flip orientation each row (NOTE:  This is not needed if ROW	*/
621 	/* statements are in the DEF file!				*/
622 	orient = (orient == RN) ? RS : RN;
623 	y += coreh;
624     }
625 
626     if (fillcells) {
627 	for (testfill = fillcells; testfill->next; testfill = testfill->next);
628 	fillmin = testfill->width;
629     }
630     else fillmin = 0;
631 
632     corearea->llx = corellx;
633     corearea->lly = corelly;
634     corearea->urx = coreurx;
635     corearea->urx_exp = coreurx;
636     corearea->ury = coreury;
637     corearea->sitew = corew;
638     corearea->siteh = coreh;
639     corearea->fillmin = fillmin;
640 
641     return fillcells;
642 }
643 
644 /*--------------------------------------------------------------*/
645 /* Check if there are not enough metal layers to route power	*/
646 /* over the cell.  If not, then force the NOSTRETCH option.	*/
647 /*--------------------------------------------------------------*/
648 
check_overcell_capable(unsigned char Flags)649 unsigned char check_overcell_capable(unsigned char Flags)
650 {
651     int ltop;
652 
653     if (!(Flags & NOSTRETCH)) {
654         ltop = LefGetMaxRouteLayer() - 1;
655         if (LefGetRouteOrientation(ltop) == 1) ltop--;
656         if (ltop < 3) {
657 	    fprintf(stderr, "Warning:  Stretching requested, but not applicable.\n");
658 	    return (unsigned char)NOSTRETCH;
659         }
660     }
661     return (unsigned char)0;
662 }
663 
664 /*--------------------------------------------------------------*/
665 /* Generate power stripes					*/
666 /*--------------------------------------------------------------*/
667 
668 SINFO
generate_stripefill(char * VddNet,char * GndNet,char * stripepat,float stripewidth_t,float stripepitch_t,char * fillcellname,float scale,FILLLIST fillcells,COREBBOX corearea,unsigned char Flags)669 generate_stripefill(char *VddNet, char *GndNet, char *stripepat,
670 	float stripewidth_t, float stripepitch_t,
671 	char *fillcellname, float scale, FILLLIST fillcells,
672 	COREBBOX corearea, unsigned char Flags)
673 {
674     int numstripes;
675     int minstripes;
676     int corew, tw, tp, tr, dx, x, y, nx;
677     int stripepitch_i, stripewidth_i, stripeoffset_i;
678     int stripepitch_f, stripewidth_f, stripeoffset_f;
679     int totalw;
680     int orient;
681     int nextx, totalfx = 0;
682     FILLLIST fillseries, testfill, newfill, sfill;
683     SINFO stripevals;
684     char posname[32];
685     GATE gate, newfillinst;
686     ROW row;
687 
688     stripevals = (SINFO)malloc(sizeof(stripeinfo));
689     stripevals->pitch = 0;
690     stripevals->width = 0;
691     stripevals->offset = 0;
692     stripevals->stretch = 0;
693     stripevals->number = 0;
694 
695     corew = corearea->urx - corearea->llx;
696 
697     if (stripewidth_t <= 0.0 || stripepitch_t <= 0.0) {
698 	fprintf(stdout, "No stripe information provided;  no power stripes added.\n");
699 	return stripevals;
700     }
701 
702     minstripes = strlen(stripepat);
703 
704     /* Scale stripe width and pitch from microns to DEF database units */
705     stripewidth_i = (int)(roundf(stripewidth_t * scale));
706     stripepitch_i = (int)(roundf(stripepitch_t * scale));
707 
708     /* Adjust stripewidth to the nearest core site unit width.	    */
709     /* If stretching is specified and the minimum fill cell width   */
710     /* is greater than the core site width, then adjust to the	    */
711     /* nearest multiple of the minimum fill cell width.		    */
712 
713     if ((!(Flags & NOSTRETCH)) && (corearea->fillmin > corearea->sitew)) {
714 	tw = stripewidth_i / corearea->fillmin;
715 	tr = stripewidth_i % corearea->fillmin;
716 	stripewidth_f = (tw + ((tr == 0) ? 0 : 1)) * corearea->fillmin;
717     }
718     else {
719 	tw = stripewidth_i / corearea->sitew;
720 	tr = stripewidth_i % corearea->sitew;
721 	stripewidth_f = (tw + ((tr == 0) ? 0 : 1)) * corearea->sitew;
722     }
723 
724     if (!(Flags & NOSTRETCH))
725     {
726 	/* Find a series of fill cell macros to match the stripe width */
727 	fillseries = NULL;
728 	dx = stripewidth_f;
729 	while (dx > 0) {
730 	    int diff;
731 
732 	    for (testfill = fillcells; testfill; testfill = testfill->next) {
733 		if (testfill->width <= dx) break;
734 	    }
735 	    if (testfill == NULL) {
736 		/* This can happen if there is no fill cell that is the	*/
737 		/* same width as the minimum site pitch.  If so, find	*/
738 		/* the first non-minimum-size fill cell and change it	*/
739 		/* to minimum size, then continue.			*/
740 		for (testfill = fillcells; testfill && testfill->next;
741 			    testfill = testfill->next);
742 		for (sfill = fillseries; sfill; sfill = sfill->next)
743 		    if (sfill->gate != testfill->gate) break;
744 		if (sfill == NULL) {
745 		    fprintf(stderr, "Warning: failed to find fill cell series matching"
746 			    " the requested stripe width.\n");
747 		    fprintf(stderr, "Stripe width will be modified as needed.\n");
748 		    dx = 0;
749 		    break;
750 		}
751 		diff = sfill->width - testfill->width;
752 		sfill->gate = testfill->gate;
753 		sfill->width = testfill->width;
754 		dx += diff;
755 	    }
756 	    newfill = (FILLLIST)malloc(sizeof(struct filllist_));
757 	    newfill->gate = testfill->gate;
758 	    newfill->width = testfill->width;
759 	    newfill->next = fillseries;
760 	    fillseries = newfill;
761 	    dx -= newfill->width;
762 	}
763 
764 	/* In case the fill series width does not equal the expected	*/
765 	/* stripe width, set the stripe width to the fill series width.	*/
766 
767 	stripewidth_f = 0;
768 	for (sfill = fillseries; sfill; sfill = sfill->next)
769 	    stripewidth_f += sfill->width;
770     }
771 
772     /* Adjust stripepitch to the nearest core site unit width */
773     tp = (int)(0.5 + (float)stripepitch_i / (float)corearea->sitew);
774     stripepitch_f = (tp * corearea->sitew);
775 
776     if (stripepitch_f < stripewidth_f * 2) {
777 	fprintf(stderr, "Error: Stripe pitch is too small (pitch = %g, width = %g)!\n",
778 		(float)stripepitch_f / (float)scale,
779 		(float)stripewidth_f / (float)scale);
780 	return stripevals;
781     }
782     if ((fillcells == NULL) && (!(Flags & NOSTRETCH))) {
783 	fprintf(stderr, "No fill cells defined.  Not stretching layout.\n");
784 	Flags |= NOSTRETCH;
785     }
786 
787     if (stripepitch_f != stripepitch_i) {
788 	fprintf(stderr, "Stripe pitch requested = %g, stripe pitch used = %g\n",
789 		stripepitch_t, (float)stripepitch_f / (float)scale);
790     }
791     if (stripewidth_f != stripewidth_i) {
792 	fprintf(stderr, "Stripe width requested = %g, stripe width used = %g\n",
793 		stripewidth_t, (float)stripewidth_f / (float)scale);
794     }
795 
796     if (!(Flags & NOSTRETCH))
797     {
798 	/* Cell will be stretched, so compute the amount to be	*/
799 	/* streteched per stripe, which is the stripewidth	*/
800 	/* adjusted to the nearest unit site width.		*/
801 
802 	numstripes = corew / (stripepitch_f - stripewidth_f);
803 
804 	if (numstripes < minstripes) {
805 	    numstripes = minstripes;
806 
807 	    /* Recompute stripe pitch */
808 	    stripepitch_f = corew / numstripes;
809 	    tp = (int)(0.5 + (float)stripepitch_f / (float)corearea->sitew);
810 	    stripepitch_f = (tp * corearea->sitew);
811 
812 	    fprintf(stdout, "Stripe pitch reduced from %g to %g to fit in layout\n",
813 		    stripepitch_t, (float)stripepitch_f / (float)scale);
814 
815 	    if (stripepitch_f < stripewidth_f * 2) {
816 		/* pitch is less than width after recomputing.  Usually means	*/
817 		/* the design is too small for any stripes at all, and stripe	*/
818 		/* fill should be disabled.					*/
819 
820 		fprintf(stderr, "Warning: Design is too small for power stripes "
821 			"(pitch = %g, width = %g)!\n",
822 			(float)stripepitch_f / (float)scale,
823 			(float)stripewidth_f / (float)scale);
824 		return stripevals;
825 	    }
826 	}
827     }
828     if (!(Flags & NOSTRETCH))
829     {
830 	totalw = corew + numstripes * stripewidth_f;
831 
832 	/* Find offset to center of 1st power stripe that results in	*/
833 	/* centering the stripes on the layout.				*/
834 
835 	stripeoffset_i = (totalw - (numstripes - 1) * stripepitch_f) / 2;
836 	tp = (int)(0.5 + (float)stripeoffset_i / (float)corearea->sitew);
837 	stripeoffset_f = (tp * corearea->sitew);
838 
839 	/* Add fill cells (approximately) under stripe positions.	*/
840 	/* Note that this is independent of drawing the stripes and	*/
841 	/* power posts.  There is no requirement that the stretch fill	*/
842 	/* must be directly under the stripe, only that the total cell	*/
843 	/* width is increased by the total width of all stripes, and	*/
844 	/* the extra fill is added as close to each stripe as possible.	*/
845 
846 	orient = corearea->orient;
847         for (y = corearea->lly; y < corearea->ury; y += corearea->siteh) {
848 	    nextx = corearea->llx + stripeoffset_f - stripewidth_f / 2;
849 	    totalfx = 0;
850 
851 	    x = corearea->llx;
852 
853 	    sprintf(posname, "%dx%d", x, y);
854 	    gate = (GATE)HashLookup(posname, &CellPosTable);
855 
856 	    while (x < corearea->urx) {
857 		while (x < nextx) {
858 		    nx = x + (int)(roundf(gate->width * scale));
859 
860 		    /* If next position is larger than nextx but is also    */
861 		    /* farther from the stripe centerline than the current  */
862 		    /* position, then break here instead.		    */
863 		    if ((nx > nextx) && ((nextx - x) < (nx - nextx))) break;
864 
865 		    gate->placedX += (double)totalfx / (double)scale;
866 
867 		    sprintf(posname, "%dx%d", nx, y);
868 		    gate = (GATE)HashLookup(posname, &CellPosTable);
869 		    x = nx;
870 
871 		    if ((x >= corearea->urx) || (gate == NULL)) break;
872 		}
873 		if ((x >= corearea->urx) || (gate == NULL)) break;
874 
875 		if (Flags & VERBOSE)
876 		    fprintf(stdout, "Add fill under stripe from (%d %d) to (%d %d)\n",
877 				x, y, x + stripewidth_f, y);
878 
879 		for (testfill = fillseries; testfill; testfill = testfill->next) {
880 		    /* Create new fill instance */
881 		    newfillinst = (GATE)malloc(sizeof(struct gate_));
882 		    newfillinst->gatetype = testfill->gate;
883 		    sprintf(posname, "SFILL%dx%d", x + totalfx, y);
884 		    newfillinst->gatename = strdup(posname);
885 		    newfillinst->placedX = (double)(x + totalfx) / (double)scale;
886 		    newfillinst->placedY = (double)y / (double)scale;
887 		    newfillinst->clientdata = (void *)NULL;
888 		    newfillinst->nomirror = testfill->gate->nomirror;
889 		    row = DefFindRow(y);
890 		    newfillinst->orient = (row) ? row->orient : orient;
891 		    /* Flip-restricted cells must be either "N" or "FS" */
892 		    if ((newfillinst->nomirror == TRUE) &&
893 			    (newfillinst->orient == RS)) newfillinst->orient |= RF;
894 		    DefAddGateInstance(newfillinst);
895 
896 		    /* Position will not be revisited, so no need to 	*/
897 		    /* add to the position hash.			*/
898 
899 		    totalfx += testfill->width;
900 		}
901 		nextx += stripepitch_f - stripewidth_f;
902 	    }
903 	    orient = (orient == RN) ? RS : RN;
904 	}
905 
906 	/* Adjust pins */
907 
908 	for (gate = Nlgates; gate; gate = gate->next) {
909 	    if (gate->gatetype == NULL) {
910 		int px, po, pitches;
911 
912 		px = (int)(roundf(gate->placedX * scale));
913 		po = px - stripeoffset_f - (stripewidth_f / 2);
914 		if (po > 0)
915 		    pitches = 1 + po / (stripepitch_f - stripewidth_f);
916 		else
917 		    pitches = -1;
918 		if (pitches <= 0) continue;
919 
920 		px += pitches * stripewidth_f;
921 		gate->placedX = (float)(px) / scale;
922 	    }
923 	}
924 
925 	if (Flags & VERBOSE) fprintf(stdout, "Layout stretched by %g um\n",
926 		    (double)totalfx / (double)scale);
927     }
928     else
929     {
930 	/* Stripes are overlaid on core without stretching */
931 	numstripes = corew / stripepitch_f;
932 	if (numstripes < minstripes) {
933 	    numstripes = minstripes;
934 
935 	    /* Recompute stripe pitch */
936 	    stripepitch_f = corew / numstripes;
937 	    tp = (int)(0.5 + (float)stripepitch_i / (float)corearea->sitew);
938 	    stripepitch_f = (tp * corearea->sitew);
939 
940 	    fprintf(stdout, "Stripe pitch reduced from %g to %g to fit in layout\n",
941 		    stripepitch_t, (float)stripepitch_f / (float)scale);
942 	}
943 	totalw = corew;
944 
945 	/* Find offset to center of 1st power stripe that results in	*/
946 	/* centering the stripes on the layout.				*/
947 
948 	stripeoffset_i = (totalw - (numstripes - 1) * stripepitch_f) / 2;
949 	tp = (int)(0.5 + (float)stripeoffset_i / (float)corearea->sitew);
950 	stripeoffset_f = (tp * corearea->sitew);
951 
952 	/* Diagnostic */
953 	if (Flags & VERBOSE)
954 	    fprintf(stdout, "Stripe offset = %d (%g microns)\n",
955 		    stripeoffset_i, stripeoffset_f);
956     }
957 
958     /* Record expanded area */
959     corearea->urx_exp = totalw + corearea->llx;
960 
961     /* Record and return final calculated power stripe pitch and width */
962     stripevals->pitch = stripepitch_f;
963     stripevals->width = stripewidth_f;
964     stripevals->offset = stripeoffset_f;
965     stripevals->stretch = totalfx;
966     stripevals->number = numstripes;
967     return stripevals;
968 }
969 
970 
971 /*--------------------------------------------------------------*/
972 /* Adjust obstructions						*/
973 /* If OBSTRUCT flag is set, then obstructions are to be read	*/
974 /* from the file <rootname>.obs, modified, and written to file	*/
975 /* <rootname>.obsx.						*/
976 /*--------------------------------------------------------------*/
977 
978 void
fix_obstructions(char * definname,SINFO stripevals,float scale,unsigned char Flags)979 fix_obstructions(char *definname, SINFO stripevals, float scale,
980 	    unsigned char Flags)
981 {
982     FILE *fobsin, *fobsout;
983     char *filename, *pptr;
984     char line[256];
985     char layer[32];
986     float fllx, flly, furx, fury;
987     int   illx, iurx, pitches, po;
988 
989     /* If no layout stretching was done, then nothing needs to be modified  */
990     if (Flags & NOSTRETCH) return;
991 
992     /* Only handle obstruction layer file if the -O switch was specified    */
993     /* (to do:  Handle obstructions via the DEF file BLOCKAGES records)	    */
994 
995     if (!(Flags & OBSTRUCT)) return;
996 
997     filename = (char *)malloc(strlen(definname) + 6);
998     strcpy(filename, definname);
999     pptr = strrchr(filename, '.');
1000     if (pptr == NULL)
1001 	strcat(filename, ".obs");
1002     else
1003 	sprintf(pptr, ".obs");
1004 
1005     fobsin = fopen(filename, "r");
1006     if (fobsin == NULL) {
1007 	fprintf(stderr, "Cannot open obstruction file %s for reading\n", filename);
1008 	free(filename);
1009 	return;
1010     }
1011 
1012     pptr = strrchr(filename, '.');
1013     sprintf(pptr, ".obsx");
1014 
1015     fobsout = fopen(filename, "w");
1016     if (fobsout == NULL) {
1017 	fprintf(stderr, "Cannot open obstruction file %s for writing\n", filename);
1018 	fclose(fobsin);
1019 	free(filename);
1020 	return;
1021     }
1022 
1023     if (Flags & VERBOSE) fprintf(stdout, "Modifying obstruction positions.\n");
1024 
1025     while (1) {
1026 	if (fgets(line, 256, fobsin) == NULL) break;
1027 
1028 	if ((stripevals->pitch == 0) || (stripevals->width == 0)) break;
1029 
1030 	if (!strncmp(line, "obstruction", 11)) {
1031 	    sscanf(line + 11, "%g %g %g %g %s", &fllx, &flly, &furx, &fury, layer);
1032 
1033 	    if (Flags & VERBOSE)
1034 		fprintf(stdout, "In: %g %g %g %g\n", fllx, flly, furx, fury);
1035 
1036 	    illx = (int)(roundf(fllx * scale));
1037 	    iurx = (int)(roundf(furx * scale));
1038 
1039 	    po = illx - stripevals->offset - (stripevals->width / 2);
1040 	    if (po > 0) {
1041 		pitches = 1 + po / (stripevals->pitch - stripevals->width);
1042 		illx += pitches * stripevals->width;
1043 	    }
1044 	    po = iurx - stripevals->offset - (stripevals->width / 2);
1045 	    if (po > 0) {
1046 		pitches = 1 + po / (stripevals->pitch - stripevals->width);
1047 		iurx += pitches * stripevals->width;
1048 	    }
1049 
1050 	    fllx = (float)illx / scale;
1051 	    furx = (float)iurx / scale;
1052 
1053 	    fprintf(fobsout, "obstruction %g %g %g %g %s\n",
1054 			fllx, flly, furx, fury, layer);
1055 
1056 	    if (Flags & VERBOSE)
1057 		fprintf(stdout, "Out: %g %g %g %g\n", fllx, flly, furx, fury);
1058 	}
1059     }
1060 
1061     free(filename);
1062     fclose(fobsin);
1063     fclose(fobsout);
1064 }
1065 
1066 /*--------------------------------------------------------------*/
1067 /* Create a new VIA record from a VIA or VIARULE record, with	*/
1068 /* total width and height as given.				*/
1069 /*--------------------------------------------------------------*/
1070 
1071 void
via_make_generated(LefList viagen,LefList lefl,int lbot,int lcut,int width,int height,float scale)1072 via_make_generated(LefList viagen, LefList lefl, int lbot, int lcut,
1073 		int width, int height, float scale)
1074 {
1075     float cutsizex, cutsizey;
1076     float bboundx, bboundy;
1077     float tboundx, tboundy;
1078 
1079     int xcuts, ycuts;
1080     char vianame[128];
1081     DSEG newseg;
1082     LefList cutrec;
1083 
1084     float borderx, bordery, spacingx, spacingy;
1085     float fwidth, fheight;
1086     float x, y;
1087     int i, j;
1088 
1089     int ltop = lbot + 1;
1090 
1091     /* Convert width and height to microns */
1092     fwidth = (float)width / scale;
1093     fheight = (float)height / scale;
1094 
1095     sprintf(vianame, "%s_post", lefl->lefName);
1096     viagen->lefName = strdup(vianame);
1097 
1098     /* Determine number of cuts in X and Y */
1099 
1100     cutsizex = LefGetViaWidth(lefl, lcut, 0);
1101     cutsizey = LefGetViaWidth(lefl, lcut, 1);
1102     bboundx = LefGetViaWidth(lefl, lbot, 0);
1103     bboundy = LefGetViaWidth(lefl, lbot, 1);
1104     tboundx = LefGetViaWidth(lefl, ltop, 0);
1105     tboundy = LefGetViaWidth(lefl, ltop, 1);
1106 
1107     /* Calculate number of cuts to fit */
1108 
1109     borderx = (((tboundx > bboundx) ? tboundx : bboundx) - cutsizex) / 2;
1110     bordery = (((tboundy > bboundy) ? tboundy : bboundy) - cutsizey) / 2;
1111 
1112     /* If there is a SPACING record in the via, use it.  If not, see if	*/
1113     /* there is a SPACING record in the record for the via cut.  If	*/
1114     /* not, then assume spacing is twice the border width.		*/
1115 
1116     cutrec = lefl;
1117     if (cutrec->info.via.spacing == NULL) cutrec = LefFindLayerByNum(lcut);
1118     if (cutrec && cutrec->info.via.spacing) {
1119 	spacingx = cutrec->info.via.spacing->spacing;
1120 	if (cutrec->info.via.spacing->next)
1121 	    spacingy = cutrec->info.via.spacing->next->spacing;
1122 	else
1123 	    spacingy = spacingx;
1124     }
1125     else {
1126 	spacingx = 2 * borderx;
1127 	spacingy = 2 * bordery;
1128     }
1129 
1130     xcuts = 1 + (int)((fwidth - 2 * borderx) - cutsizex) / (cutsizex + spacingx);
1131     ycuts = 1 + (int)((fheight - 2 * bordery) - cutsizey) / (cutsizey + spacingy);
1132 
1133     /* Ensure at least one cut! */
1134     if (xcuts < 1) xcuts = 1;
1135     if (ycuts < 1) ycuts = 1;
1136 
1137     /* Make sure that width and height are enough to pass DRC.  Height	*/
1138     /* in particular is taken from the width of the power bus and may	*/
1139     /* not be wide enough for the topmost contacts.			*/
1140 
1141     fwidth = (xcuts * cutsizex) + ((float)(xcuts - 1) * spacingx) + (2 * borderx);
1142     fheight = (ycuts * cutsizey) + ((float)(ycuts - 1) * spacingy) + (2 * bordery);
1143 
1144     viagen->info.via.area.layer = lbot;
1145     viagen->info.via.area.x1 = -fwidth / 2;
1146     viagen->info.via.area.x2 = fwidth / 2;
1147     viagen->info.via.area.y1 = -fheight / 2;
1148     viagen->info.via.area.y2 = fheight / 2;
1149 
1150     newseg = (DSEG)malloc(sizeof(struct dseg_));
1151     newseg->layer = ltop;
1152     newseg->x1 = -fwidth / 2;
1153     newseg->x2 = fwidth / 2;
1154     newseg->y1 = -fheight / 2;
1155     newseg->y2 = fheight / 2;
1156     newseg->next = NULL;
1157     viagen->info.via.lr = newseg;
1158 
1159     x = (-fwidth / 2) + borderx + (cutsizex / 2);
1160     for (i = 0; i < xcuts; i++) {
1161         y = (-fheight / 2) + bordery + (cutsizey / 2);
1162 	for (j = 0; j < ycuts; j++) {
1163 	    newseg = (DSEG)malloc(sizeof(struct dseg_));
1164 	    newseg->layer = lcut;
1165 	    newseg->x1 = x - (cutsizex / 2);
1166 	    newseg->x2 = x + (cutsizex / 2);
1167 	    newseg->y1 = y - (cutsizey / 2);
1168 	    newseg->y2 = y + (cutsizey / 2);
1169 	    newseg->next = viagen->info.via.lr;
1170 	    viagen->info.via.lr = newseg;
1171 	    y += (cutsizey + spacingy);
1172 	}
1173 	x += (cutsizex + spacingy);
1174     }
1175 }
1176 
1177 /*--------------------------------------------------------------*/
1178 /* Routine to check if a LefList entry is a valid via record	*/
1179 /* for a via between metal layers "l" (ell) and "l + 1".	*/
1180 /* Since the LefList record drops metal and cut layers more or	*/
1181 /* less randomly into the area, lr, and lr->next records, all	*/
1182 /* combinations of layers need to be checked.			*/
1183 /*								*/
1184 /* Since the metal layers are known and the cut layer is not	*/
1185 /* necessarily known, return the cut layer number if the via	*/
1186 /* record is valid.  If not, return -1.				*/
1187 /*--------------------------------------------------------------*/
1188 
1189 int
check_valid_via(LefList lefl,int l)1190 check_valid_via(LefList lefl, int l)
1191 {
1192     int cutlayer = -1;
1193 
1194     if (lefl->info.via.area.layer == l) {
1195 	if (lefl->info.via.lr && lefl->info.via.lr->layer == l + 1) {
1196 	    if (lefl->info.via.lr->next)
1197 		cutlayer = lefl->info.via.lr->next->layer;
1198 	}
1199 	else if (lefl->info.via.lr && lefl->info.via.lr->next &&
1200 		lefl->info.via.lr->next->layer == l + 1) {
1201 	    cutlayer = lefl->info.via.lr->layer;
1202 	}
1203     }
1204     else if (lefl->info.via.area.layer == l + 1) {
1205 	if (lefl->info.via.lr && lefl->info.via.lr->layer == l) {
1206 	    if (lefl->info.via.lr->next)
1207 		cutlayer = lefl->info.via.lr->next->layer;
1208 	}
1209 	else if (lefl->info.via.lr && lefl->info.via.lr->next &&
1210 		lefl->info.via.lr->next->layer == l) {
1211 	    cutlayer = lefl->info.via.lr->layer;
1212 	}
1213     }
1214     else if (lefl->info.via.lr && lefl->info.via.lr->layer == l) {
1215 	if (lefl->info.via.lr && lefl->info.via.lr->next &&
1216 		lefl->info.via.lr->next->layer == l + 1)
1217 	    cutlayer = lefl->info.via.area.layer;
1218     }
1219     else if (lefl->info.via.lr && lefl->info.via.lr->layer == l + 1) {
1220 	if (lefl->info.via.lr && lefl->info.via.lr->next &&
1221 		lefl->info.via.lr->next->layer == l)
1222 	    cutlayer = lefl->info.via.area.layer;
1223     }
1224     return cutlayer;
1225 }
1226 
1227 /*--------------------------------------------------------------*/
1228 /* Generate stripe contact posts and metal			*/
1229 /*--------------------------------------------------------------*/
1230 
1231 PSTRIPE
generate_stripes(SINFO stripevals,FILLLIST fillcells,COREBBOX corearea,char * pattern,char * VddNet,char * GndNet,float scale,unsigned char Flags)1232 generate_stripes(SINFO stripevals, FILLLIST fillcells,
1233 	COREBBOX corearea, char *pattern,
1234 	char *VddNet, char *GndNet, float scale, unsigned char Flags)
1235 {
1236     int i, j, l, p, n, y, hh;
1237     int testuse;
1238     int ltop, lbot;
1239     float syt, syb;
1240     double vw, vh;
1241     int cutlayer, lcut;
1242     int gnd_ymin, gnd_ymax, vdd_ymin, vdd_ymax, gate_ymin;
1243     int gnd_xmin, vdd_xmin, tmp;
1244     char *powername, *groundname;
1245     int corew;
1246 
1247     PSTRIPE rails = NULL, prail;
1248     PPOST post;
1249     LefList lefl, *vialist, topvia, vvalid;
1250     DSEG lr;
1251 
1252     /* Pick the first fill cell and parse it for the POWER and	*/
1253     /* GROUND pins as marked by pin USE.  If no pins are marked	*/
1254     /* as use POWER or GROUND then look for pins with names	*/
1255     /* matching the power and ground nets.			*/
1256 
1257     GATE fillgate = fillcells->gate;
1258     DSEG r;
1259     ROW row;
1260 
1261     if (stripevals->width == 0 || stripevals->pitch == 0 || stripevals->number == 0) {
1262 	fprintf(stderr, "No stripe information supplied;  no stripes generated.\n");
1263 	return NULL;
1264     }
1265 
1266     lbot = 0;
1267     for (i = 0; i < fillgate->nodes; i++) {
1268 	testuse = fillgate->use[i];
1269 	if (testuse == PORT_USE_POWER) {
1270 	    if (!strcmp(fillgate->node[i], VddNet)) {
1271 		powername = fillgate->node[i];
1272 		break;
1273 	    }
1274 	}
1275     }
1276     if (i == fillgate->nodes) {
1277 	for (i = 0; i < fillgate->nodes; i++) {
1278 	    if (!strcmp(fillgate->node[i], VddNet)) {
1279 		powername = VddNet;
1280 		lbot = fillgate->taps[i]->layer;
1281 		break;
1282 	    }
1283 	}
1284 	if (i == fillgate->nodes) {
1285 	    fprintf(stderr, "Failed to find power net pin in cell macro.\n");
1286 	    return NULL;
1287 	}
1288     }
1289     /* NOTE:  Need to parse all taps;  find one that crosses the whole	*/
1290     /* cell.  If none, then find one that touches or overlaps the cell	*/
1291     /* bottom or top.							*/
1292 
1293     r = fillcells->gate->taps[i];
1294     if (r == NULL) {
1295 	fprintf(stderr, "Failed to find taps on standard cell:  Has the technology "
1296 		"LEF file been read?\n");
1297 	return NULL;
1298     }
1299     vdd_ymin =  (int)(roundf(r->y1 * scale));
1300     vdd_ymax =  (int)(roundf(r->y2 * scale));
1301     vdd_xmin =  (int)(roundf(r->x1 * scale));
1302 
1303     for (j = 0; j < fillgate->nodes; j++) {
1304 	testuse = fillgate->use[j];
1305 	if (testuse == PORT_USE_GROUND) {
1306 	    if (!strcmp(fillgate->node[j], GndNet)) {
1307 		groundname = fillgate->node[j];
1308 		break;
1309 	    }
1310 	}
1311     }
1312     if (j == fillgate->nodes) {
1313 	for (j = 0; j < fillgate->nodes; j++) {
1314 	    if (!strcmp(fillgate->node[j], GndNet)) {
1315 		groundname = GndNet;
1316 		lbot = fillgate->taps[i]->layer;
1317 		break;
1318 	    }
1319 	}
1320 	if (j == fillgate->nodes) {
1321 	    fprintf(stderr, "Failed to find ground net pin in cell macro.\n");
1322 	    return NULL;
1323 	}
1324     }
1325     r = fillcells->gate->taps[j];
1326     gnd_ymin =  (int)(roundf(r->y1 * scale));
1327     gnd_ymax =  (int)(roundf(r->y2 * scale));
1328     gnd_xmin =  (int)(roundf(r->x1 * scale));
1329 
1330     /* If the first row is inverted then the ymin/ymax values need to be    */
1331     /* adjusted.							    */
1332 
1333     row = DefLowestRow();   /* Try this first */
1334     if (row) {
1335 	if (row->orient & RS) {
1336 	    gnd_ymax = corearea->siteh - gnd_ymax;
1337 	    gnd_ymin = corearea->siteh - gnd_ymin;
1338 	    vdd_ymax = corearea->siteh - vdd_ymax;
1339 	    vdd_ymin = corearea->siteh - vdd_ymin;
1340 
1341 	    tmp = gnd_ymax;
1342 	    gnd_ymax = gnd_ymin;
1343 	    gnd_ymin = tmp;
1344 
1345 	    tmp = vdd_ymax;
1346 	    vdd_ymax = vdd_ymin;
1347 	    vdd_ymin = tmp;
1348 	}
1349     }
1350     else {
1351 	if (corearea->orient & RS) {
1352 	    gnd_ymax = corearea->siteh - gnd_ymax;
1353 	    gnd_ymin = corearea->siteh - gnd_ymin;
1354 	    vdd_ymax = corearea->siteh - vdd_ymax;
1355 	    vdd_ymin = corearea->siteh - vdd_ymin;
1356 
1357 	    tmp = gnd_ymax;
1358 	    gnd_ymax = gnd_ymin;
1359 	    gnd_ymin = tmp;
1360 
1361 	    tmp = vdd_ymax;
1362 	    vdd_ymax = vdd_ymin;
1363 	    vdd_ymin = tmp;
1364 	}
1365     }
1366 
1367     n = strlen(pattern);
1368 
1369     /* Find the highest metal layer that is oriented vertically */
1370 
1371     ltop = LefGetMaxRouteLayer() - 1;
1372     if (LefGetRouteOrientation(ltop) == 1) ltop--;
1373     if (ltop < 3) {
1374 	int mspace;
1375 
1376 	fprintf(stderr, "Will not generate over-cell power stripes due to lack "
1377 		    "of route layers\n");
1378 	fprintf(stderr, "Generating comb structures instead.\n");
1379 
1380 	/* Generate comb structures in metal1 on either side to connect	*/
1381 	/* power and ground.						*/
1382 
1383 	/* Get wide spacing rule relative to stripe width */
1384 	mspace = (int)(roundf(LefGetRouteWideSpacing(lbot,
1385 			(float)(stripevals->width) / scale) * scale));
1386 
1387 	/* Account for ground or power bus extending beyond the cell	*/
1388 	/* bounding box.  Assumes that the extension is symmetric on	*/
1389 	/* left and right, and the same for power and ground.		*/
1390 
1391 	if (gnd_xmin < 0) mspace -= gnd_xmin;
1392 	else if (vdd_xmin < 0) mspace -= vdd_xmin;
1393 	corew = corearea->sitew;
1394 
1395 	/* Generate power comb on left */
1396 
1397         prail = (PSTRIPE)malloc(sizeof(struct _powerstripe));
1398 	prail->next = rails;
1399 	rails = prail;
1400 
1401 	prail->offset = -mspace - stripevals->width / 2;
1402 	prail->pitch = corearea->urx_exp;
1403 	prail->num = 1;
1404 	if ((n < 1) || (pattern[0] == 'P')) {
1405 	    prail->name = VddNet;
1406 	    y = corearea->lly + (vdd_ymax + vdd_ymin) / 2;
1407 	    hh = (vdd_ymax - vdd_ymin) / 2;
1408 	}
1409 	else {
1410 	    prail->name = GndNet;
1411 	    y = corearea->lly + (gnd_ymax + gnd_ymin) / 2;
1412 	    hh = (gnd_ymax - gnd_ymin) / 2;
1413 	}
1414 
1415 	prail->stripe = (DSEG)malloc(sizeof(struct dseg_));
1416 	prail->stripe->layer = lbot;
1417 	prail->stripe->next = NULL;
1418 	prail->stripe->x1 = -(float)(stripevals->width / 2) / scale;
1419 	prail->stripe->x2 = (float)(stripevals->width / 2) / scale;
1420 	prail->stripe->y1 = (float)(corearea->lly - hh) / scale;
1421 	prail->stripe->y2 = (float)(corearea->ury + hh) / scale;
1422 	prail->posts = NULL;
1423 
1424 	/* Create all posts */
1425 
1426 	for (; y <= corearea->ury; y += 2 * corearea->siteh) {
1427 	    PPOST newpost = (PPOST)malloc(sizeof(powerpost));
1428 	    newpost->strut = (DSEG)malloc(sizeof(struct dseg_));
1429 	    newpost->viagen = NULL;
1430 	    newpost->strut->layer = lbot;
1431 	    newpost->strut->next = NULL;
1432 	    newpost->strut->x1 = 0.0;
1433 	    newpost->strut->x2 = (float)(-prail->offset + corew) / scale;
1434 	    newpost->strut->y1 = (float)(y - hh) / scale;
1435 	    newpost->strut->y2 = (float)(y + hh) / scale;
1436 	    newpost->next = prail->posts;
1437 	    prail->posts = newpost;
1438 	}
1439 	prail->offset += corearea->llx;
1440 
1441 	/* Generate ground comb on right */
1442 
1443         prail = (PSTRIPE)malloc(sizeof(struct _powerstripe));
1444 	prail->next = rails;
1445 	rails = prail;
1446 
1447 	prail->offset = mspace + stripevals->width / 2;
1448 	prail->pitch = corearea->urx_exp;
1449 	prail->num = 1;
1450 	if ((n < 2) || (pattern[1] == 'G')) {
1451 	    prail->name = GndNet;
1452 	    y = corearea->lly + (gnd_ymax + gnd_ymin) / 2;
1453 	    hh = (gnd_ymax - gnd_ymin) / 2;
1454 	}
1455 	else {
1456 	    prail->name = VddNet;
1457 	    y = corearea->lly + (vdd_ymax + vdd_ymin) / 2;
1458 	    hh = (vdd_ymax - vdd_ymin) / 2;
1459 	}
1460 
1461 	prail->stripe = (DSEG)malloc(sizeof(struct dseg_));
1462 	prail->stripe->layer = lbot;
1463 	prail->stripe->next = NULL;
1464 	prail->stripe->x1 = -(float)(stripevals->width / 2) / scale;
1465 	prail->stripe->x2 = (float)(stripevals->width / 2) / scale;
1466 	prail->stripe->y1 = (float)(corearea->lly - hh) / scale;
1467 	prail->stripe->y2 = (float)(corearea->ury + hh) / scale;
1468 	prail->posts = NULL;
1469 
1470 	/* Create all posts */
1471 
1472 	for (; y <= corearea->ury; y += 2 * corearea->siteh) {
1473 	    PPOST newpost = (PPOST)malloc(sizeof(powerpost));
1474 	    newpost->strut = (DSEG)malloc(sizeof(struct dseg_));
1475 	    newpost->viagen = NULL;
1476 	    newpost->strut->layer = lbot;
1477 	    newpost->strut->next = NULL;
1478 	    newpost->strut->x1 = (float)(-prail->offset - corew) / scale;
1479 	    newpost->strut->x2 = 0.0;
1480 	    newpost->strut->y1 = (float)(y - hh) / scale;
1481 	    newpost->strut->y2 = (float)(y + hh) / scale;
1482 	    newpost->next = prail->posts;
1483 	    prail->posts = newpost;
1484 	}
1485 	prail->offset += corearea->urx_exp;
1486 	return rails;
1487     }
1488 
1489     /* Generate vias for posts */
1490     /* NOTE:  This assumes that the power and ground rails are the same	    */
1491     /* height.  If not, need to have two vialist records, one for each rail */
1492 
1493     vialist = (LefList *)malloc((ltop - lbot) * sizeof(LefList));
1494     for (l = lbot; l < ltop; l++) vialist[l] = (LefList)NULL;
1495 
1496     /* First find any VIARULE GENERATE vias;  these are preferred, as they  */
1497     /* have all the right information for generating a new via for the	    */
1498     /* post.								    */
1499 
1500     for (l = lbot; l < ltop; l++) {
1501 	for (lefl = LefInfo; lefl; lefl = lefl->next) {
1502 	    if (lefl->lefClass == CLASS_VIA) {
1503 		if (lefl->info.via.generated) {
1504 
1505 		    /* Check for top and bottom layers matching (l) and (l + 1) */
1506 
1507 		    if ((cutlayer = check_valid_via(lefl, l)) != -1) {
1508 			vialist[l] = LefNewVia(NULL);
1509 			via_make_generated(vialist[l], lefl, l, cutlayer,
1510 				stripevals->width, gnd_ymax - gnd_ymin, scale);
1511 			break;		// Continue to next layer
1512 		    }
1513 		}
1514 	    }
1515 	}
1516     }
1517 
1518     /* Next find any VIAs that have the right layers.  Use this information */
1519     /* to create a new VIA record with the correct size for the post.	    */
1520 
1521     for (l = lbot; l < ltop; l++) {
1522 	if (vialist[l] == NULL) {
1523 	    vvalid = NULL;
1524 	    for (lefl = LefInfo; lefl; lefl = lefl->next) {
1525 		if (lefl->lefClass == CLASS_VIA) {
1526 		    if ((lcut = check_valid_via(lefl, l)) != -1) {
1527 			/* Don't include vias that this routine has created, */
1528 			if (strstr(lefl->lefName, "_post") != NULL) continue;
1529 			if (vvalid == NULL) {
1530 			    vvalid = lefl;
1531 			    vw = LefGetViaWidth(lefl, lcut, 0);
1532 			    vh = LefGetViaWidth(lefl, lcut, 1);
1533 			    cutlayer = lcut;
1534 			}
1535 			/* Find the smallest valid via.  Note that it	*/
1536 			/* is preferred to find a via designed for a	*/
1537 			/* power post, if there is one (to be done).	*/
1538 			else {
1539 			    double tw, th;
1540 			    tw = LefGetViaWidth(lefl, lcut, 0);
1541 			    th = LefGetViaWidth(lefl, lcut, 1);
1542 			    if ((th < vh) || ((th == vh) && (tw < vw))) {
1543 				vvalid = lefl;
1544 				vw = tw;
1545 				vh = th;
1546 				cutlayer = lcut;
1547 			    }
1548 			}
1549 		    }
1550 		}
1551 	    }
1552 	    if (vvalid) {
1553 		vialist[l] = LefNewVia(NULL);
1554 		via_make_generated(vialist[l], vvalid, l, cutlayer,
1555 			stripevals->width, gnd_ymax - gnd_ymin, scale);
1556 	    }
1557 	}
1558     }
1559 
1560     for (l = lbot; l < ltop; l++) {
1561 	if (vialist[l] == NULL) {
1562 	    LefList ll0, ll1;
1563 	    ll0 = LefFindLayerByNum(l);
1564 	    ll1 = LefFindLayerByNum(l + 1);
1565 	    fprintf(stderr, "Error:  Failed to find a valid via record between "
1566 			"metal layers %s and %s\n",
1567 			ll0->lefName, ll1->lefName);
1568 	    return NULL;
1569 	}
1570     }
1571 
1572     /* Construct power stripe records */
1573 
1574     for (p = 0; p < n; p++) {
1575 
1576         prail = (PSTRIPE)malloc(sizeof(struct _powerstripe));
1577 	prail->next = rails;
1578 	rails = prail;
1579 
1580 	prail->offset = stripevals->offset + p * stripevals->pitch;
1581 	prail->pitch = stripevals->pitch * n;
1582 	prail->num = 1 + (corearea->urx_exp - prail->offset) / prail->pitch;
1583 
1584 	/* Note this is not strdup(), so can compare string pointers */
1585 	prail->name = (pattern[p] == 'P') ? VddNet : GndNet;
1586 
1587 	/* Find vertical dimensions of power rails on the standard cells */
1588 	y = corearea->lly;
1589 	if (pattern[p] == 'P') {
1590 	    y += (vdd_ymax + vdd_ymin) / 2;
1591 	    hh = (vdd_ymax - vdd_ymin) / 2;
1592 	}
1593 	else {
1594 	    y += (gnd_ymax + gnd_ymin) / 2;
1595 	    hh = (gnd_ymax - gnd_ymin) / 2;
1596 	}
1597 
1598 	/* Query the extent of the highest via layer and make sure the	*/
1599 	/* power stripe covers it completely.				*/
1600 
1601 	topvia = vialist[ltop - 1];
1602 	syb = topvia->info.via.area.y1;
1603 	syt = topvia->info.via.area.y2;
1604 	for (lr = topvia->info.via.lr; lr; lr = lr->next) {
1605 	    if (lr->y1 < syb) syb = lr->y1;
1606 	    if (lr->y2 > syt) syt = lr->y2;
1607 	}
1608 
1609 	/* First two rails, extend down by one track pitch.  A pin will	*/
1610 	/* be added here.						*/
1611 	if (p < 2) {
1612 	    syb = -LefGetRoutePitch(ltop - 1);
1613 	    if (syb > topvia->info.via.area.y1)
1614 		syb -= LefGetRoutePitch(ltop - 1);
1615 	}
1616 
1617 	prail->stripe = (DSEG)malloc(sizeof(struct dseg_));
1618 	prail->stripe->layer = ltop;
1619 	prail->stripe->next = NULL;
1620 	prail->stripe->x1 = -(float)(stripevals->width / 2) / scale;
1621 	prail->stripe->x2 = (float)(stripevals->width / 2) / scale;
1622 	prail->stripe->y1 = syb + ((float)corearea->lly / scale);
1623 	prail->stripe->y2 = syt + ((float)corearea->ury / scale);
1624 	prail->posts = NULL;
1625 
1626 	/* Create all posts (also horizontally centered at X = 0) */
1627 
1628 	/* To be done:  Check if rows are alternating N and S	*/
1629 	/* or not.  This code assumes that they always are.	*/
1630 
1631 	for (; y <= corearea->ury; y += 2 * corearea->siteh) {
1632 	    for (l = lbot; l < ltop; l++) {
1633 		PPOST newpost = (PPOST)malloc(sizeof(powerpost));
1634 		newpost->strut = (DSEG)malloc(sizeof(struct dseg_));
1635 		newpost->viagen = vialist[l];
1636 		newpost->strut->layer = l;
1637 		newpost->strut->next = NULL;
1638 		newpost->strut->x1 = -(float)(stripevals->width / 2) / scale;
1639 		newpost->strut->x2 = (float)(stripevals->width / 2) / scale;
1640 		newpost->strut->y1 = (float)(y - hh) / scale;
1641 		newpost->strut->y2 = (float)(y + hh) / scale;
1642 		newpost->next = prail->posts;
1643 		prail->posts = newpost;
1644 	    }
1645 	}
1646     }
1647 
1648     /* link via records and prepend to LefInfo */
1649     for (l = lbot; l < ltop - 1; l++)
1650 	vialist[l]->next = vialist[l + 1];
1651 
1652     vialist[l]->next = LefInfo;
1653     LefInfo = vialist[0];
1654 
1655     free(vialist);
1656     return rails;
1657 }
1658 
1659 /*--------------------------------------------------------------*/
1660 /* Convert orient bitfield from GATE structure to character	*/
1661 /* string for a DEF file.					*/
1662 /*--------------------------------------------------------------*/
1663 
gate_to_orient(int orient)1664 char *gate_to_orient(int orient)
1665 {
1666     int oidx;
1667     static char *orients[8] = {"N", "S", "E", "W", "FN", "FS", "FE", "FW"};
1668 
1669     switch (orient & (RN | RS | RE | RW)) {
1670 	case RS:
1671 	    oidx = 1;
1672 	    break;
1673 	case RE:
1674 	    oidx = 2;
1675 	    break;
1676 	case RW:
1677 	    oidx = 3;
1678 	    break;
1679 	default:
1680 	    oidx = 0;
1681 	    break;
1682     }
1683     if (orient & RF) oidx += 4;
1684     return orients[oidx];
1685 }
1686 
1687 /*--------------------------------------------------------------*/
1688 /*--------------------------------------------------------------*/
1689 
1690 void
output_rail(FILE * outfptr,PSTRIPE rail,int x,int first,float scale)1691 output_rail(FILE *outfptr, PSTRIPE rail, int x, int first, float scale)
1692 {
1693     PPOST post;
1694     LefList lefl;
1695     char *otyp;
1696     float fyd, fya, fxd, fxa;
1697     int iyd, iya, ixd, ixa;
1698 
1699     static char *otypes[] = {"+ FIXED", "  NEW"};
1700 
1701     otyp = (first) ? otypes[0] : otypes[1];
1702 
1703     for (post = rail->posts; post; post = post->next) {
1704 	lefl = LefFindLayerByNum(post->strut->layer);
1705 	fyd = post->strut->y2 - post->strut->y1;
1706 	fya = (post->strut->y2 + post->strut->y1) / 2;
1707 	iyd =  (int)(roundf(fyd * scale));
1708 	iya =  (int)(roundf(fya * scale));
1709 	if (post->viagen) {
1710 	    fprintf(outfptr, "\n%s %s %d ( %d %d ) ( * * ) %s",
1711 		    otyp, lefl->lefName, iyd, x, iya, post->viagen->lefName);
1712 	}
1713 	else {
1714 	    fxd = post->strut->x1;
1715 	    ixd = x + (int)(roundf(fxd * scale));
1716 	    fxa = post->strut->x2;
1717 	    ixa = x + (int)(roundf(fxa * scale));
1718 	    fprintf(outfptr, "\n%s %s %d ( %d %d ) ( %d * )",
1719 		    otyp, lefl->lefName, iyd, ixd, iya, ixa);
1720 	}
1721 	otyp = otypes[1];
1722     }
1723     lefl = LefFindLayerByNum(rail->stripe->layer);
1724     fxd = rail->stripe->x2 - rail->stripe->x1;
1725     fya = rail->stripe->y1;
1726     fyd = rail->stripe->y2;
1727     ixd =  (int)(roundf(fxd * scale));
1728     iya =  (int)(roundf(fya * scale));
1729     iyd =  (int)(roundf(fyd * scale));
1730     fprintf(outfptr, "\n%s %s %d ( %d %d ) ( * %d )",
1731 	    otyp, lefl->lefName, ixd, x, iya, iyd);
1732 }
1733 
1734 /*--------------------------------------------------------------*/
1735 /*--------------------------------------------------------------*/
1736 
1737 void
output_rails(FILE * outfptr,PSTRIPE rail,COREBBOX corearea,float scale,int first)1738 output_rails(FILE *outfptr, PSTRIPE rail, COREBBOX corearea, float scale, int first)
1739 {
1740     int i, x;
1741 
1742     x = rail->offset;
1743     for (i = 0; i < rail->num; i++) {
1744 	output_rail(outfptr, rail, x, first, scale);
1745 	first = FALSE;
1746 	x += rail->pitch;
1747 	if (x > corearea->urx_exp) break;
1748     }
1749 }
1750 
1751 /*--------------------------------------------------------------*/
1752 /* write_output ---						*/
1753 /*								*/
1754 /*  write the modified DEF file to the output.			*/
1755 /*--------------------------------------------------------------*/
1756 
1757 void
write_output(char * definname,char * defoutname,float scale,COREBBOX corearea,SINFO stripevals,PSTRIPE rails,char * VddNet,char * GndNet,unsigned char Flags)1758 write_output(char *definname, char *defoutname, float scale,
1759 	COREBBOX corearea, SINFO stripevals, PSTRIPE rails,
1760 	char *VddNet, char *GndNet, unsigned char Flags)
1761 {
1762     FILE *outfptr, *infptr;
1763     static char line[LEF_LINE_MAX + 2];
1764     char *sptr;
1765     int i, copyspecial = 0, numVias, foundrail[2], ltop;
1766     double lh, ly;
1767 
1768     GATE gate, endgate;
1769     NET net;
1770     NODE node;
1771     PPOST post;
1772     LefList lefl, lname, lrec;
1773     DSEG seg;
1774     PSTRIPE rail;
1775 
1776     if (defoutname == NULL)
1777 	outfptr = stdout;
1778     else {
1779 	outfptr = fopen(defoutname, "w");
1780 	if (outfptr == NULL) {
1781 	    fprintf(stderr, "Error:  Failed to open file %s for writing modified output\n",
1782 		    defoutname);
1783 	    return;
1784 	}
1785     }
1786 
1787     if (Flags & VERBOSE) fprintf(stdout, "Writing DEF file output.\n");
1788 
1789     /* Find the number of (new) power rail SPECIALNETS to be written	*/
1790     /* There will normally be one record for power and one for ground	*/
1791     /* unless rails were not written.  Power and ground rails are	*/
1792     /* checked separately for consistency of the output DEF.		*/
1793 
1794     foundrail[0] = foundrail[1] = FALSE;
1795     for (rail = rails; rail; rail = rail->next) {
1796 	if ((foundrail[0] == FALSE) && (rail->name == VddNet)) foundrail[0] = TRUE;
1797 	if ((foundrail[1] == FALSE) && (rail->name == GndNet)) foundrail[1] = TRUE;
1798     }
1799     numSpecial = ((foundrail[0] == TRUE) ? 1 : 0) + ((foundrail[1] == TRUE) ? 1 : 0);
1800 
1801     /* Write DEF header (copy input DEF file verbatim up to COMPONENTS) */
1802 
1803     infptr = fopen(definname, "r");
1804     while (1) {
1805 	if (fgets(line, LEF_LINE_MAX + 1, infptr) == NULL) {
1806 	    fprintf(stderr, "Error:  End of file reached before COMPONENTS.\n");
1807 	    return;
1808 	}
1809 	sptr = line;
1810 	while (isspace(*sptr)) sptr++;
1811 
1812 	/* Assuming a typical DEF file here. . . */
1813 	if (!strncmp(sptr, "COMPONENTS", 10)) break;
1814 
1815 	/* Rewrite DIEAREA, ROWS, and TRACKS */
1816 	else if (!strncmp(sptr, "DIEAREA", 7)) {
1817 	    char *dptr;
1818 	    int dllx, dlly, durx, dury;
1819 
1820 	    dptr = strchr(line, '(');
1821 	    sscanf(dptr + 1, "%d %d", &dllx, &dlly);
1822 	    dptr = strchr(dptr + 1, '(');
1823 	    sscanf(dptr + 1, "%d %d", &durx, &dury);
1824 
1825 	    durx += stripevals->stretch;
1826 
1827 	    fprintf(outfptr, "DIEAREA ( %d %d ) ( %d %d ) ;\n",
1828 			dllx, dlly, durx, dury);
1829 	}
1830 
1831 	else if (!strncmp(sptr, "ROW", 3)) {
1832 	    char *dptr;
1833 	    int radd, xnum, ridx, rowy;
1834 	    ROW row;
1835 	    char namepos[16];
1836 	    radd = stripevals->stretch / corearea->sitew;
1837 	    static char *orientations[] = {"N", "S", "E", "W", "FN", "FS", "FE", "FW"};
1838 
1839 	    dptr = sptr;
1840 	    while (!isspace(*dptr)) dptr++;
1841 	    while (isspace(*dptr)) dptr++;
1842 	    while (!isspace(*dptr)) dptr++;
1843 	    while (isspace(*dptr)) dptr++;
1844 	    while (!isspace(*dptr)) dptr++;
1845 	    while (isspace(*dptr)) dptr++;
1846 	    while (!isspace(*dptr)) dptr++;
1847 	    while (isspace(*dptr)) dptr++;
1848 	    sscanf(dptr, "%d", &rowy);
1849 	    row = DefFindRow(rowy);
1850 
1851 	    xnum = row->xnum + radd;
1852 	    switch (row->orient & (RN | RS | RE | RW)) {
1853 		case RS:
1854 		    ridx = 1;
1855 		    break;
1856 		case RE:
1857 		    ridx = 2;
1858 		    break;
1859 		case RW:
1860 		    ridx = 3;
1861 		    break;
1862 		default:
1863 		    ridx = 0;
1864 	    }
1865 	    if (row->orient & RF) ridx += 4;
1866 
1867 	    fprintf(outfptr, "ROW %s %s %d %d %s DO %d BY %d STEP %d %d ;\n",
1868 		    row->rowname, row->sitename, row->x, row->y,
1869 		    orientations[ridx], xnum, row->ynum,
1870 		    row->xstep, row->ystep);
1871 	}
1872 	else if (!strncmp(sptr, "TRACKS", 6)) {
1873 	    char *dptr;
1874 	    char o;
1875 	    char layer[64];
1876 	    int roffset, rnum, rpitch;
1877 
1878 	    dptr = sptr + 6;
1879 	    while (isspace(*dptr)) dptr++;
1880 	    sscanf(dptr, "%c", &o);
1881 	    while (!isspace(*dptr)) dptr++;
1882 	    while (isspace(*dptr)) dptr++;
1883 	    sscanf(dptr, "%d", &roffset);
1884 	    while (!isspace(*dptr)) dptr++;
1885 	    while (isspace(*dptr)) dptr++;
1886 	    while (!isspace(*dptr)) dptr++;
1887 	    while (isspace(*dptr)) dptr++;
1888 	    sscanf(dptr, "%d", &rnum);
1889 	    while (!isspace(*dptr)) dptr++;
1890 	    while (isspace(*dptr)) dptr++;
1891 	    while (!isspace(*dptr)) dptr++;
1892 	    while (isspace(*dptr)) dptr++;
1893 	    sscanf(dptr, "%d", &rpitch);
1894 	    while (!isspace(*dptr)) dptr++;
1895 	    while (isspace(*dptr)) dptr++;
1896 	    while (!isspace(*dptr)) dptr++;
1897 	    while (isspace(*dptr)) dptr++;
1898 	    sscanf(dptr, "%s", layer);
1899 
1900 	    if (o == 'X') {
1901 		rnum += (int)(stripevals->stretch / rpitch);
1902 		if (stripevals->stretch % rpitch != 0) rnum++;
1903 	    }
1904 	    fprintf(outfptr, "TRACKS %c %d DO %d STEP %d LAYER %s ;\n",
1905 		    o, roffset, rnum, rpitch, layer);
1906 	}
1907 	else
1908 	    fprintf(outfptr, "%s", line);
1909     }
1910 
1911     /* Write generated vias for posts */
1912 
1913     numVias = 0;
1914     for (lefl = LefInfo; lefl; lefl = lefl->next)
1915 	if (strstr(lefl->lefName, "_post") != NULL)
1916 	    numVias++;
1917 
1918     fprintf(outfptr, "VIAS %d ;\n", numVias);
1919     for (lefl = LefInfo; lefl; lefl = lefl->next) {
1920 	int llx, lly, urx, ury;
1921 
1922 	if (strstr(lefl->lefName, "_post") != NULL) {
1923 	    fprintf(outfptr, "- %s\n", lefl->lefName);
1924 	    lname = LefFindLayerByNum(lefl->info.via.area.layer);
1925 	    llx =  (int)(roundf(lefl->info.via.area.x1 * scale));
1926 	    lly =  (int)(roundf(lefl->info.via.area.y1 * scale));
1927 	    urx =  (int)(roundf(lefl->info.via.area.x2 * scale));
1928 	    ury =  (int)(roundf(lefl->info.via.area.y2 * scale));
1929 	    fprintf(outfptr, "+ RECT %s ( %d %d ) ( %d %d )",
1930 		    lname->lefName, llx, lly, urx, ury);
1931 	    if (lefl->info.via.lr) fprintf(outfptr, "\n");
1932 	    for (seg = lefl->info.via.lr; seg; seg = seg->next) {
1933 		lname = LefFindLayerByNum(seg->layer);
1934 		llx =  (int)(roundf(seg->x1 * scale));
1935 		lly =  (int)(roundf(seg->y1 * scale));
1936 		urx =  (int)(roundf(seg->x2 * scale));
1937 		ury =  (int)(roundf(seg->y2 * scale));
1938 		fprintf(outfptr, "+ RECT %s ( %d %d ) ( %d %d )",
1939 			    lname->lefName, llx, lly, urx, ury);
1940 		if (seg->next) fprintf(outfptr, "\n");
1941 	    }
1942 	    fprintf(outfptr, " ;\n");
1943 	}
1944     }
1945     fprintf(outfptr, "END VIAS\n\n");
1946 
1947     for (endgate = Nlgates; endgate->next; endgate = endgate->next);
1948 
1949     if (Numgates > 0) {
1950 
1951 	/* Write instances (COMPONENTS) in the order read */
1952 	fprintf(outfptr, "COMPONENTS %d ;\n", Numgates);
1953 	for (gate = endgate; gate ; gate = gate->last) {
1954 	    int px, py;
1955 	    char *sptr = NULL;
1956 	    if (gate->gatetype == NULL) continue;
1957 
1958 	    // Watch for backslash-escaped instance names.  Even when
1959 	    // converting DEF to DEF, the DEF read routine converts
1960 	    // back to verilog notation, so addspacers needs to convert
1961 	    // once again back to the SPICE-sanitized syntax.
1962 
1963 	    if (*gate->gatename == '\\')
1964 	        if ((sptr = strchr(gate->gatename, ' ')) != NULL)
1965 		    *sptr = '\\';
1966 
1967 	    px =  (int)(roundf(gate->placedX * scale));
1968 	    py =  (int)(roundf(gate->placedY * scale));
1969 	    fprintf(outfptr, "- %s %s + PLACED ( %d %d ) %s ;\n",
1970 		gate->gatename, gate->gatetype->gatename,
1971 		px, py, gate_to_orient(gate->orient));
1972 
1973 	    if (sptr != NULL) *sptr = ' ';
1974 	}
1975 	fprintf(outfptr, "END COMPONENTS\n\n");
1976     }
1977 
1978     if (Numpins > 0) {
1979 	int llx, lly, urx, ury, px, py;
1980         static char *pin_classes[] = {
1981 	    "DEFAULT", "INPUT", "OUTPUT", "OUTPUT TRISTATE", "INOUT", "FEEDTHRU"
1982 	};
1983 	LefList lefl;
1984 
1985 	/* Write instances (PINS) in the order read, plus power pins */
1986 
1987 	fprintf(outfptr, "PINS %d ;\n", Numpins + numSpecial);
1988 
1989 	if (foundrail[0]) {
1990 	    for (rail = rails; rail; rail = rail->next)
1991 		if (rail->name == VddNet) break;
1992 
1993 	    ltop = rail->stripe->layer;
1994 	    lrec = LefFindLayerByNum(ltop);
1995 	    lh = LefGetRoutePitch(ltop - 1) / 4;
1996 	    ly = rail->stripe->y1 + lh;
1997 
1998 	    /* NOTE: The over-simplified "arrangepins" Tcl script expects   */
1999 	    /* LAYER and PLACED records to be on separate lines.  This will */
2000 	    /* eventually be replaced by a C coded executable with a more   */
2001 	    /* rigorous parser, like addspacers uses.			    */
2002 
2003 	    fprintf(outfptr, "- %s + NET %s + DIRECTION INOUT\n", VddNet, VddNet);
2004 	    fprintf(outfptr, "  + LAYER %s ( %d %d ) ( %d %d )\n",
2005 		    lrec->lefName,
2006 		    (int)(roundf(rail->stripe->x1 * scale)),
2007 		    (int)(roundf(-lh * scale)),
2008 		    (int)(roundf(rail->stripe->x2 * scale)),
2009 		    (int)(roundf(lh * scale)));
2010 	    fprintf(outfptr, "  + PLACED ( %d %d ) N ;\n",
2011 		    rail->offset, (int)(roundf(ly * scale)));
2012 	}
2013 	if (foundrail[1]) {
2014 	    for (rail = rails; rail; rail = rail->next)
2015 		if (rail->name == GndNet) break;
2016 
2017 	    ltop = rail->stripe->layer;
2018 	    lrec = LefFindLayerByNum(ltop);
2019 	    lh = LefGetRoutePitch(ltop - 1) / 4;
2020 	    ly = rail->stripe->y1 + lh;
2021 
2022 	    fprintf(outfptr, "- %s + NET %s + DIRECTION INOUT\n", GndNet, GndNet);
2023 	    fprintf(outfptr, "  + LAYER %s ( %d %d ) ( %d %d )\n",
2024 		    lrec->lefName,
2025 		    (int)(roundf(rail->stripe->x1 * scale)),
2026 		    (int)(roundf(-lh * scale)),
2027 		    (int)(roundf(rail->stripe->x2 * scale)),
2028 		    (int)(roundf(lh * scale)));
2029 	    fprintf(outfptr, "  + PLACED ( %d %d ) N ;\n",
2030 		    rail->offset, (int)(roundf(ly * scale)));
2031 	}
2032 
2033 	for (gate = endgate; gate ; gate = gate->last) {
2034 	    int dir;
2035 
2036 	    if (gate->gatetype != NULL) continue;
2037 
2038 	    fprintf(outfptr, "- %s + NET %s",
2039 		    gate->gatename, gate->node[0]);
2040 
2041 	    if (gate->direction[0] != 0)
2042 		fprintf(outfptr, " + DIRECTION %s",
2043 			pin_classes[gate->direction[0]]);
2044 
2045 	    fprintf(outfptr, "\n");
2046 
2047 	    lefl = LefFindLayerByNum(gate->taps[0]->layer);
2048 	    urx = (int)(roundf((gate->taps[0]->x2 - gate->taps[0]->x1) * scale) / 2.0);
2049 	    ury = (int)(roundf((gate->taps[0]->y2 - gate->taps[0]->y1) * scale) / 2.0);
2050 	    llx = -urx;
2051 	    lly = -ury;
2052 	    px =  (int)(roundf(gate->placedX * scale));
2053 	    py =  (int)(roundf(gate->placedY * scale));
2054 
2055 	    fprintf(outfptr, "  + LAYER %s ( %d %d ) ( %d %d )\n",
2056 			lefl->lefName, llx, lly, urx, ury);
2057 	    fprintf(outfptr, "  + PLACED ( %d %d ) %s ;\n",
2058 			px, py, gate_to_orient(gate->orient));
2059 	}
2060 	fprintf(outfptr, "END PINS\n\n");
2061     }
2062 
2063     while (1) {
2064 	if (fgets(line, LEF_LINE_MAX + 1, infptr) == NULL) {
2065 	    fprintf(stderr, "Error:  End of file reached before NETS.\n");
2066 	    return;
2067 	}
2068 	sptr = line;
2069 	while (isspace(*sptr)) sptr++;
2070 
2071 	/* Assuming a typical DEF file here. . . */
2072 	if (!strncmp(sptr, "NETS", 4)) break;
2073 
2074     }
2075     fprintf(outfptr, "%s", line);
2076     while (1) {
2077 	if (fgets(line, LEF_LINE_MAX + 1, infptr) == NULL) {
2078 	    fprintf(stderr, "Error:  End of file reached before END NETS.\n");
2079 	    return;
2080 	}
2081 	sptr = line;
2082 	while (isspace(*sptr)) sptr++;
2083 
2084 	/* Assuming a typical DEF file here. . . */
2085 	if (!strncmp(sptr, "SPECIALNETS", 11)) {
2086 	    sscanf(sptr + 11, "%d", &copyspecial);
2087 	    break;
2088 	}
2089 	else if (!strncmp(sptr, "END DESIGN", 10)) {
2090 	    break;
2091 	}
2092 	fprintf(outfptr, "%s", line);
2093     }
2094 
2095     /* Rewrite SPECIALNETS line with updated number */
2096 
2097     if (copyspecial + numSpecial > 0)
2098 	fprintf(outfptr, "SPECIALNETS %d ;\n", numSpecial + copyspecial);
2099 
2100     if (numSpecial > 0) {
2101 	/* Write power bus stripes (SPECIALNETS) */
2102 	int i, first = TRUE;
2103 	char *railnames[2] = {GndNet, VddNet};
2104 
2105 	for (i = 0; i < 2; i++) {
2106 	    fprintf(outfptr, "- %s", railnames[i]);
2107 	    for (rail = rails; rail; rail = rail->next) {
2108 		if (rail->name == railnames[i]) {
2109 		    output_rails(outfptr, rail, corearea, scale, first);
2110 		    first = FALSE;
2111 		}
2112 	    }
2113 	    fprintf(outfptr, " ;\n");
2114 	    first = TRUE;
2115 	}
2116     }
2117 
2118     /* If there were previously no SPECIALNETS then add the ending line */
2119     if (numSpecial > 0 && copyspecial == 0)
2120 	fprintf(outfptr, "END SPECIALNETS\n\n");
2121 
2122     /* Copy the remainder of the file verbatim */
2123 
2124     while (1) {
2125 	if (fgets(line, LEF_LINE_MAX + 1, infptr) == NULL) break;
2126 	sptr = line;
2127 	while (isspace(*sptr)) sptr++;
2128 
2129 	if (!strncmp(sptr, "END DESIGN", 10)) {
2130 	    break;
2131 	}
2132 	fprintf(outfptr, "%s", line);
2133     }
2134     fprintf(outfptr, "END DESIGN\n");
2135     fclose(infptr);
2136 
2137     if (defoutname != NULL) fclose(outfptr);
2138     fflush(stdout);
2139 }
2140 
2141 /*--------------------------------------------------------------*/
2142 /* helpmessage - tell user how to use the program               */
2143 /*                                                              */
2144 /*--------------------------------------------------------------*/
2145 
helpmessage(FILE * outf)2146 void helpmessage(FILE *outf)
2147 {
2148     fprintf(outf, "addspacers [-options] <netlist>\n");
2149     fprintf(outf, "\n");
2150     fprintf(outf, "addspacers adds fill cells and power buses to a layout.\n");
2151     fprintf(outf, "Output on stdout unless redirected with -o option.\n");
2152     fprintf(outf, "\n");
2153     fprintf(outf, "options:\n");
2154     fprintf(outf, "  -o <path>  Output file path and name\n");
2155     fprintf(outf, "  -l <path>  Path to standard cell LEF file (for macro list)\n");
2156     fprintf(outf, "  -p <name>  Name of power net\n");
2157     fprintf(outf, "  -g <name>  Name of ground net\n");
2158     fprintf(outf, "  -f <name>  Name of fill cell (or prefix)\n");
2159     fprintf(outf, "  -w <width> Power bus stripe width\n");
2160     fprintf(outf, "  -P <pitch> Power bus stripe pitch\n");
2161     fprintf(outf, "  -s <pattern> Power bus stripe pattern (default \"PG\") \n");
2162     fprintf(outf, "  -n		Do not stretch layout under power buses.\n");
2163     fprintf(outf, "  -O		Handle obstruction areas in separate .obs file\n");
2164     fprintf(outf, "\n");
2165     fprintf(outf, "  -v		Verbose output\n");
2166     fprintf(outf, "  -h         Print this message\n");
2167 
2168 } /* helpmessage() */
2169 
2170