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", ©special);
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