1 //----------------------------------------------------------------
2 // vlog2Def
3 //----------------------------------------------------------------
4 // Convert from verilog netlist to a pre-placement DEF file
5 //----------------------------------------------------------------
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <unistd.h> /* for getopt() */
11 #include <math.h> /* For sqrt() and ceil() */
12
13 #include "hash.h"
14 #include "readverilog.h"
15 #include "readlef.h"
16
17 int write_output(struct cellrec *, int hasmacros, float aspect, float density,
18 int units, GATE coresite, char *outname);
19 void helpmessage(FILE *outf);
20
21 /* Linked list for nets */
22
23 typedef struct _linkedNet *linkedNetPtr;
24
25 typedef struct _linkedNet {
26 char *instname;
27 char *pinname;
28 linkedNetPtr next;
29 } linkedNet;
30
31 /* Hash table of LEF macros */
32 struct hashtable LEFhash;
33
34 /*--------------------------------------------------------------*/
35
main(int argc,char * argv[])36 int main (int argc, char *argv[])
37 {
38 int i, result = 0, hasmacros = FALSE;
39 int units = 100;
40 float aspect = 1.0;
41 float density = 1.0;
42 struct cellrec *topcell;
43 GATE coresite = NULL;
44 char *defoutname = NULL;
45
46 InitializeHashTable(&LEFhash, SMALLHASHSIZE);
47
48 while ((i = getopt(argc, argv, "hHl:a:d:u:o:")) != EOF) {
49 switch (i) {
50 case 'h':
51 case 'H':
52 helpmessage(stdout);
53 return 0;
54 case 'l':
55 result = LefRead(optarg); /* Can be called multiple times */
56 if (result == 0) {
57 helpmessage(stderr);
58 return 1;
59 }
60 break;
61 case 'o':
62 defoutname = strdup(optarg);
63 break;
64 case 'a':
65 if (sscanf(optarg, "%f", &aspect) != 1) {
66 fprintf(stderr, "Could not read aspect value from \"-a %s\"\n",
67 optarg);
68 helpmessage(stderr);
69 return 1;
70 }
71 break;
72 case 'd':
73 if (sscanf(optarg, "%f", &density) != 1) {
74 fprintf(stderr, "Could not read density value from \"-d %s\"\n",
75 optarg);
76 helpmessage(stderr);
77 return 1;
78 }
79 if (density < 0.0 || density > 1.0) {
80 fprintf(stderr, "Illegal density value \"-d %s\"\n", optarg);
81 helpmessage(stderr);
82 return 1;
83 }
84 break;
85 case 'u':
86 if (sscanf(optarg, "%d", &units) != 1) {
87 fprintf(stderr, "Could not read units value from \"-u %s\"\n",
88 optarg);
89 helpmessage(stderr);
90 return 1;
91 }
92 break;
93 default:
94 fprintf(stderr, "Bad option switch \"%c\"\n", (char)i);
95 helpmessage(stderr);
96 return 1;
97 }
98 }
99
100 if (optind >= argc) {
101 fprintf(stderr, "Couldn't find a filename as input\n");
102 helpmessage(stderr);
103 return 1;
104 }
105
106 /* If any LEF files were read, hash the GateInfo list */
107 if (GateInfo != NULL) {
108 GATE gate;
109 for (gate = GateInfo; gate; gate = gate->next) {
110 HashPtrInstall(gate->gatename, gate, &LEFhash);
111 if (!strncmp(gate->gatename, "site_", 5))
112 if (gate->gateclass == MACRO_CLASS_CORE)
113 coresite = gate;
114 }
115 hasmacros = TRUE;
116 }
117
118 topcell = ReadVerilog(argv[optind]);
119 result = write_output(topcell, hasmacros, aspect, density,
120 units, coresite, defoutname);
121 return result;
122 }
123
124 /*--------------------------------------------------------------*/
125 /* output_nets: */
126 /* Recursion callback function for each item in Nodehash */
127 /*--------------------------------------------------------------*/
128
output_nets(struct hashlist * p,void * cptr)129 struct nlist *output_nets(struct hashlist *p, void *cptr)
130 {
131 struct netrec *net;
132 char *sptr = NULL;
133 FILE *outf = (FILE *)cptr;
134 linkedNetPtr nlink, nsrch;
135
136 nlink = (linkedNetPtr)(p->ptr);
137
138 // Verilog backslash-escaped names are decidedly not SPICE
139 // compatible, so replace the mandatory trailing space character
140 // with another backslash.
141
142 if (*p->name == '\\') {
143 sptr = strchr(p->name, ' ');
144 if (sptr != NULL) *sptr = '\\';
145 }
146
147 fprintf(outf, "- %s\n", p->name);
148
149 for (nsrch = nlink; nsrch; nsrch = nsrch->next) {
150 fprintf(outf, " ( %s %s )", nsrch->instname, nsrch->pinname);
151 if (nsrch->next == NULL)
152 fprintf(outf, " ;");
153 fprintf(outf, "\n");
154 }
155
156 if (sptr != NULL) *sptr = ' ';
157 return NULL;
158 }
159
160 /*--------------------------------------------------------------*/
161 /* port_output_specs */
162 /* */
163 /* Write information to an entry in the DEF PINS section */
164 /*--------------------------------------------------------------*/
165
port_output_specs(FILE * outfptr,struct portrec * port,LefList * routelayer,int units)166 void port_output_specs(FILE *outfptr, struct portrec *port,
167 LefList *routelayer, int units)
168 {
169 char *layername;
170 int x, y, ll, ur, w, hw;
171 LefList pinlayer;
172
173 /* This string array much match the port definitions in readverilog.h */
174 static char *portdirs[] = {"", "INPUT", "OUTPUT", "INOUT"};
175
176 x = y = 0; /* To be done (need constraints?) */
177
178 /* To be done: Layer depends on position and orientation */
179 pinlayer = routelayer[2];
180
181 layername = pinlayer->lefName;
182 w = (int)(0.5 + pinlayer->info.route.width * (float)units);
183 hw = w >> 1;
184 ll = -hw;
185 ur = w - hw;
186
187 if (port->direction > PORT_NONE)
188 fprintf(outfptr, "\n + DIRECTION %s", portdirs[port->direction]);
189 fprintf(outfptr, "\n + LAYER %s ( %d %d ) ( %d %d )", layername,
190 ll, ll, ur, ur);
191 fprintf(outfptr, "\n + PLACED ( %d %d ) N ;\n", x, y);
192 }
193
194 /*--------------------------------------------------------------*/
195 /* write_output */
196 /* */
197 /* ARGS: */
198 /* RETURNS: 1 to OS */
199 /* SIDE EFFECTS: */
200 /*--------------------------------------------------------------*/
201
write_output(struct cellrec * topcell,int hasmacros,float aspect,float density,int units,GATE coresite,char * outname)202 int write_output(struct cellrec *topcell, int hasmacros, float aspect,
203 float density, int units, GATE coresite, char *outname)
204 {
205 FILE *outfptr = stdout;
206 int ncomp, npin, nnet, start, end, i, result = 0;
207 int totalwidth, totalheight, rowwidth, rowheight, numrows;
208 int sitewidth, siteheight, numsites;
209 char portnet[512];
210
211 struct netrec *net;
212 struct portrec *port;
213 struct instance *inst;
214
215 struct hashtable Nodehash;
216
217 /* Static string "PIN" for ports */
218 static char pinname[] = "PIN";
219
220 linkedNetPtr nlink, nsrch;
221 LefList slef;
222 LefList routelayer[3];
223
224 if (topcell == NULL) {
225 fprintf(stderr, "No top-level cell data; cannot continue.\n");
226 return 1;
227 }
228
229 /* Open the output file (unless name is NULL, in which case use stdout) */
230 if (outname != NULL) {
231 outfptr = fopen(outname, "w");
232 if (outfptr == NULL) {
233 fprintf(stderr, "Error: Cannot open file %s for writing.\n", outname);
234 return 1;
235 }
236 }
237
238 /* Hash the nets */
239
240 InitializeHashTable(&Nodehash, LARGEHASHSIZE);
241 nnet = 0;
242 for (port = topcell->portlist; port; port = port->next) {
243 if ((net = BusHashLookup(port->name, &topcell->nets)) != NULL) {
244 start = net->start;
245 end = net->end;
246 }
247 else start = end = -1;
248
249 if (start > end) {
250 int tmp;
251 tmp = start;
252 start = end;
253 end = tmp;
254 }
255 for (i = start; i <= end; i++) {
256 nlink = (linkedNetPtr)malloc(sizeof(linkedNet));
257 nlink->instname = pinname;
258
259 if (start == -1)
260 nlink->pinname = port->name;
261 else {
262 sprintf(portnet, "%s[%d]", port->name, i);
263 nlink->pinname = strdup(portnet);
264 }
265 nlink->next = NULL;
266 if ((nsrch = HashLookup(nlink->pinname, &Nodehash)) != NULL) {
267 while (nsrch->next) nsrch = nsrch->next;
268 nsrch->next = nlink;
269 }
270 else {
271 HashPtrInstall(nlink->pinname, nlink, &Nodehash);
272 nnet++;
273 }
274 }
275 }
276 totalwidth = 0;
277 for (inst = topcell->instlist; inst; inst = inst->next) {
278 int j;
279 GATE gate;
280 gate = HashLookup(inst->cellname, &LEFhash);
281
282 for (port = inst->portlist; port; port = port->next) {
283
284 char *netsptr;
285
286 /* Code for handling vectors mostly copied from vlog2Cel.c. */
287 /* Note, however, that this program is given a synthesized */
288 /* netlist and there are no instance arrays. If that is */
289 /* ever not true, then this code needs to be expanded to */
290 /* include handling of instance arrays. */
291
292 /* Determine and handle the four cases of a port and a net */
293 /* being an array or a single signal. */
294
295 int is_port_bus = FALSE;
296 int is_net_bus = FALSE;
297
298 /* Verilog backslash-escaped names have spaces that */
299 /* break pretty much every other format, so replace */
300 /* the space with the (much more sensible) second */
301 /* backslash. This can be detected and changed */
302 /* back by programs converting the syntax back into */
303 /* verilog. */
304
305 netsptr = port->net;
306 if (*port->net == '\\') {
307 netsptr = strchr(port->net, ' ');
308 if (netsptr != NULL) *netsptr = '\\';
309 }
310
311 /* Find the port name in the gate pin list */
312 for (j = 0; j < gate->nodes; j++) {
313 if (!strcmp(port->name, gate->node[j])) break;
314 }
315 if (j == gate->nodes) {
316 /* Is this a bus? */
317 for (j = 0; j < gate->nodes; j++) {
318 char *delim = strrchr(gate->node[j], '[');
319 if (delim != NULL) {
320 *delim = '\0';
321 if (!strcmp(port->name, gate->node[j]))
322 is_port_bus = TRUE;
323 *delim = '[';
324 if (is_port_bus) break;
325 }
326 }
327 }
328
329 /* Check if the net itself is an array */
330 net = HashLookup(port->net, &topcell->nets);
331 if (net && (net->start != -1)) {
332 char *sptr, *dptr, *cptr;
333
334 is_net_bus = TRUE;
335
336 /* However, if net name is a 1-bit bus subnet, then */
337 /* it is not considered to be a bus. Note that */
338 /* brackets inside a verilog backslash-escaped name */
339 /* are not array indicators. */
340
341 dptr = strchr(netsptr, '[');
342 if (dptr) {
343 cptr = strchr(dptr + 1, ':');
344 if (!cptr) {
345 is_net_bus = FALSE;
346 }
347 }
348 }
349 else if (!net && port->net[0] == '{') {
350 /* net is a signal bundle */
351 is_net_bus = TRUE;
352 }
353
354 if (j == gate->nodes) {
355 fprintf(stderr, "Error: Pin \"%s\" not found in LEF macro \"%s\"!\n",
356 port->name, gate->gatename);
357 }
358 else if (is_net_bus == FALSE) {
359
360 nlink = (linkedNetPtr)malloc(sizeof(linkedNet));
361 nlink->instname = inst->instname;
362 nlink->pinname = port->name;
363 nlink->next = NULL;
364
365 if ((nsrch = HashLookup(port->net, &Nodehash)) != NULL) {
366 while (nsrch->next) nsrch = nsrch->next;
367 nsrch->next = nlink;
368 }
369 else {
370 HashPtrInstall(port->net, nlink, &Nodehash);
371 nnet++;
372 }
373 }
374 else { // is_net_bus == TRUE
375
376 char *apin, *anet, *dptr, *cptr;
377 int a, pidx, armax, armin;
378
379 armax = armin = 0;
380 for (j = 0; j < gate->nodes; j++) {
381 char *delim, *sptr;
382
383 sptr = gate->node[j];
384 if (*sptr == '\\') sptr = strchr(sptr, ' ');
385 if (sptr == NULL) sptr = gate->node[j];
386 delim = strrchr(sptr, '[');
387 if (delim != NULL) {
388 *delim = '\0';
389 if (!strcmp(port->name, gate->node[j])) {
390 if (sscanf(delim + 1, "%d", &pidx) == 1) {
391 if (pidx > armax) armax = pidx;
392 if (pidx < armin) armin = pidx;
393 }
394 }
395 *delim = '[';
396 }
397 }
398
399 /* To do: Need to check if array is high-to-low or low-to-high */
400 /* Presently assuming arrays are always defined high-to-low */
401
402 apin = (char *)malloc(strlen(port->name) + 15);
403 for (a = armax; a >= armin; a--) {
404 if (is_port_bus)
405 sprintf(apin, "%s[%d]", port->name, a);
406 else
407 sprintf(apin, "%s", port->name);
408
409 /* If net is not delimited by {...} then it is also */
410 /* an array. Otherwise, find the nth element in */
411 /* the brace-enclosed set. */
412
413 /* To do: if any component of the array is a vector */
414 /* then we need to count bits in that vector. */
415
416 if (*port->net == '{') {
417 int aidx;
418 char *sptr, ssave;
419 char *pptr = port->net + 1;
420 for (aidx = 0; aidx < (armax - a); aidx++) {
421 sptr = pptr;
422 while (*sptr != ',' && *sptr != '}') sptr++;
423 pptr = sptr + 1;
424 }
425 sptr = pptr;
426 if (*sptr != '\0') {
427 while (*sptr != ',' && *sptr != '}') sptr++;
428 ssave = *sptr;
429 *sptr = '\0';
430 anet = (char *)malloc(strlen(pptr) + 1);
431 sprintf(anet, "%s", pptr);
432 *sptr = ssave;
433 }
434 else {
435 anet = NULL; /* Must handle this error! */
436 }
437 }
438 else if (((dptr = strrchr(netsptr, '[')) != NULL) &&
439 ((cptr = strrchr(netsptr, ':')) != NULL)) {
440 int fhigh, flow, fidx;
441 sscanf(dptr + 1, "%d", &fhigh);
442 sscanf(cptr + 1, "%d", &flow);
443 if (fhigh > flow) fidx = fhigh - (armax - a);
444 else fidx = flow + (armax - a);
445 anet = (char *)malloc(strlen(port->net) + 15);
446 *dptr = '\0';
447 sprintf(anet, "%s[%d]", port->net, fidx);
448 *dptr = '[';
449 }
450 else {
451 anet = (char *)malloc(strlen(port->net) + 15);
452 sprintf(anet, "%s[%d]", port->net, a);
453 }
454
455 /* Find the corresponding port bit */
456 for (j = 0; j < gate->nodes; j++) {
457 if (anet == NULL) break;
458 if (!strcmp(apin, gate->node[j])) {
459
460 nlink = (linkedNetPtr)malloc(sizeof(linkedNet));
461 nlink->instname = inst->instname;
462 nlink->pinname = gate->node[j];
463 nlink->next = NULL;
464
465 if ((nsrch = HashLookup(anet, &Nodehash)) != NULL) {
466 while (nsrch->next) nsrch = nsrch->next;
467 nsrch->next = nlink;
468 }
469 else {
470 HashPtrInstall(anet, nlink, &Nodehash);
471 nnet++;
472 }
473 break;
474 }
475 }
476 free(anet);
477 if (j == gate->nodes) {
478 fprintf(stderr, "Error: Failed to find port %s in cell %s"
479 " port list!\n", port->name, inst->cellname);
480 }
481 }
482 free(apin);
483 }
484 }
485
486 if (hasmacros) {
487 if (gate) {
488 /* Make sure this is a core cell */
489 if (gate->gateclass == MACRO_CLASS_CORE) {
490 totalwidth += (int)(gate->width * (float)units);
491 rowheight = (int)(gate->height * (float)units);
492 }
493 /* To do: Handle non-core cell records */
494 /* (specifically PAD and BLOCK). */
495 }
496 }
497 }
498
499 /* For pin placement, find the 2nd and 3rd route layer LEF names. */
500 /* NOTE: This only ensures that the output is valid LEF; it does */
501 /* not do anything about applying pin constraints. */
502
503 for (i = 0; i < 3; i++)
504 routelayer[i] = (LefList)NULL;
505
506 for (slef = LefInfo; slef; slef = slef->next)
507 if (slef->lefClass == CLASS_ROUTE)
508 if ((slef->type < 3) && (slef->type >= 0))
509 routelayer[slef->type] = slef;
510
511 /* Write output DEF header */
512 fprintf(outfptr, "VERSION 5.6 ;\n");
513 /* fprintf(outfptr, "NAMESCASESENSITIVE ON ;\n"); */
514 fprintf(outfptr, "DIVIDERCHAR \"/\" ;\n");
515 fprintf(outfptr, "BUSBITCHARS \"[]\" ;\n");
516 fprintf(outfptr, "DESIGN %s ;\n", topcell->name);
517 fprintf(outfptr, "UNITS DISTANCE MICRONS %d ;\n", units);
518 fprintf(outfptr, "\n");
519
520 /* Calculate pre-placement die area, rows, and tracks, and output the same, */
521 /* depending on what has been read in from LEF files. */
522
523 if (hasmacros) {
524 /* NOTE: Use a prorated density that is slightly lower than the target */
525 /* or else the placement can fail due to fewer sites available then */
526 /* cell area to place, after accounting for density. */
527
528 int efftotalwidth = (int)ceilf((float)totalwidth / (density * 0.95));
529
530 numrows = (int)ceilf(sqrtf(efftotalwidth / (aspect * rowheight)));
531 rowwidth = (int)ceilf(efftotalwidth / numrows);
532 totalheight = (int)ceilf(rowheight * numrows);
533 sitewidth = (int)ceilf(coresite->width * units);
534 siteheight = (int)ceilf(coresite->height * units);
535
536 /* Diagnostic */
537 fprintf(stdout, "Diagnostic:\n");
538 fprintf(stdout, "Total width of all cells = %gum\n", (float)totalwidth / (float)units);
539 fprintf(stdout, "Effective total width after density planning = %gum\n", (float)efftotalwidth / (float)units);
540 fprintf(stdout, "Site size = (%gum, %gum)\n", (float)sitewidth / (float)units, siteheight / (float)units);
541 fprintf(stdout, "Row height = %gum\n", (float)rowheight / (float)units);
542 fprintf(stdout, "Row width = %gum\n", (float)rowwidth / (float)units);
543 fprintf(stdout, "Total height = %gum\n", (float)totalheight / (float)units);
544
545 /* To do: compute additional area for pins */
546
547 fprintf(outfptr, "DIEAREA ( 0 0 ) ( %d %d ) ;\n", rowwidth, totalheight);
548 fprintf(outfptr, "\n");
549
550 /* Compute site placement and generate ROW statements */
551
552 numsites = (int)ceilf((float)rowwidth / (float)sitewidth);
553 for (i = 0; i < numrows; i++) {
554 fprintf(outfptr, "ROW ROW_%d %s 0 %d %c DO %d BY 1 STEP %d 0 ;\n",
555 i + 1, coresite->gatename + 5, i * siteheight,
556 ((i % 2) == 0) ? 'N' : 'S', numsites, sitewidth);
557 }
558 fprintf(outfptr, "\n");
559 }
560
561 /* Write components in the order of the input file */
562
563 ncomp = 0;
564 for (inst = topcell->instlist; inst; inst = inst->next) {
565 ncomp++;
566 if (inst->arraystart != -1) {
567 int arrayw = inst->arraystart - inst->arrayend;
568 ncomp += (arrayw < 0) ? -arrayw : arrayw;
569 }
570 }
571 fprintf(outfptr, "COMPONENTS %d ;\n", ncomp);
572
573 for (inst = topcell->instlist; inst; inst = inst->next) {
574 if (inst->arraystart != -1) {
575 int ahigh, alow, j;
576 if (inst->arraystart > inst->arrayend) {
577 ahigh = inst->arraystart;
578 alow = inst->arrayend;
579 }
580 else {
581 ahigh = inst->arrayend;
582 alow = inst->arraystart;
583 }
584 for (j = ahigh; j >= alow; j--) {
585 fprintf(outfptr, "- %s[%d] %s ;\n", inst->instname, j, inst->cellname);
586 }
587 }
588 else
589 fprintf(outfptr, "- %s %s ;\n", inst->instname, inst->cellname);
590 }
591 fprintf(outfptr, "END COMPONENTS\n\n");
592
593 npin = 0;
594 for (port = topcell->portlist; port; port = port->next) {
595 if ((net = BusHashLookup(port->name, &topcell->nets)) != NULL) {
596 int btot = net->start - net->end;
597 if (btot < 0) btot = -btot;
598 npin += btot + 1;
599 }
600 else
601 npin++;
602 }
603 fprintf(outfptr, "PINS %d ;\n", npin);
604
605 for (port = topcell->portlist; port; port = port->next) {
606 if ((net = BusHashLookup(port->name, &topcell->nets)) != NULL) {
607 if (net->start == -1) {
608 fprintf(outfptr, "- %s + NET %s", port->name, port->name);
609 port_output_specs(outfptr, port, routelayer, units);
610 }
611 else if (net->start > net->end) {
612 for (i = net->start; i >= net->end; i--) {
613 fprintf(outfptr, "- %s[%d] + NET %s[%d]", port->name, i,
614 port->name, i);
615 port_output_specs(outfptr, port, routelayer, units);
616 }
617 }
618 else {
619 for (i = net->start; i <= net->end; i++) {
620 fprintf(outfptr, "- %s[%d] + NET %s[%d]", port->name, i,
621 port->name, i);
622 port_output_specs(outfptr, port, routelayer, units);
623 }
624 }
625 }
626 else {
627 fprintf(outfptr, "- %s + NET %s", port->name, port->name);
628 port_output_specs(outfptr, port, routelayer, units);
629 }
630 }
631
632 fprintf(outfptr, "END PINS\n\n");
633
634 fprintf(outfptr, "NETS %d ;\n", nnet);
635 RecurseHashTablePointer(&Nodehash, output_nets, outfptr);
636 fprintf(outfptr, "END NETS\n\n");
637
638 /* End the design */
639 fprintf(outfptr, "END DESIGN\n");
640
641 if (outname != NULL) fclose(outfptr);
642
643 fflush(stdout);
644 return result;
645
646 } /* write_output */
647
648 /*--------------------------------------------------------------*/
649 /* C helpmessage - tell user how to use the program */
650 /* */
651 /* ARGS: */
652 /* RETURNS: 1 to OS */
653 /* SIDE EFFECTS: */
654 /*--------------------------------------------------------------*/
655
helpmessage(FILE * outf)656 void helpmessage(FILE *outf)
657 {
658 fprintf(outf,"vlog2Def <netlist>\n");
659 fprintf(outf,"\n");
660 fprintf(outf,"vlog2Def converts a verilog netlist to a pre-placement DEF file.\n");
661 fprintf(outf,"\n");
662 fprintf(outf,"options:\n");
663 fprintf(outf,"\n");
664 fprintf(outf," -h Print this message\n");
665 fprintf(outf," -o <path> Set output filename (otherwise output is on stdout).\n");
666 fprintf(outf," -l <path> Read LEF file from <path> (may be called multiple"
667 " times)\n");
668 fprintf(outf," -a <value> Set aspect ratio to <value> (default 1.0)\n");
669 fprintf(outf," -d <value> Set density to <value> (default 1.0)\n");
670 fprintf(outf," -u <value> Set units-per-micron to <value) (default 100)\n");
671
672 } /* helpmessage() */
673
674