1 //----------------------------------------------------------------
2 // vlog2Verilog
3 //----------------------------------------------------------------
4 // Convert between verilog styles.
5 // Options include bit-blasting vectors and adding power
6 // supply connections.
7 //
8 // Revision 0, 2018-11-29: First release by R. Timothy Edwards.
9 //
10 // This program is written in ISO C99.
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h> /* For getopt() */
16 #include <math.h>
17 #include <ctype.h>
18 #include <float.h>
19
20 #include "hash.h"
21 #include "readverilog.h"
22 #include "readlef.h"
23
24 int write_output(struct cellrec *, unsigned char, char *);
25 void helpmessage(FILE *outf);
26 void cleanup_string(char *);
27 int is_pwr_name(char *);
28
29 char *VddNet = NULL;
30 char *GndNet = NULL;
31 char *VddTap = NULL;
32 char *GndTap = NULL;
33 char *AntennaCell = NULL;
34
35 struct hashtable Lefhash;
36
37 /* Define option flags */
38
39 #define IMPLICIT_POWER (unsigned char)0x01
40 #define MAINTAIN_CASE (unsigned char)0x02
41 #define BIT_BLAST (unsigned char)0x04
42 #define NONAME_POWER (unsigned char)0x08
43 #define ADD_ANTENNA (unsigned char)0x10
44
45 /*--------------------------------------------------------------*/
46
main(int argc,char * argv[])47 int main (int argc, char *argv[])
48 {
49 int i, result;
50 unsigned char Flags;
51
52 char *vloginname = NULL;
53 char *vlogoutname = NULL;
54 char *cptr;
55 struct cellrec *topcell;
56
57 Flags = (unsigned char)IMPLICIT_POWER;
58
59 VddNet = strdup("VDD");
60 GndNet = strdup("VSS");
61
62 InitializeHashTable(&Lefhash, SMALLHASHSIZE);
63
64 while ((i = getopt(argc, argv, "pbchnHv:g:l:o:a:")) != EOF) {
65 switch( i ) {
66 case 'p':
67 Flags &= ~IMPLICIT_POWER;
68 break;
69 case 'b':
70 Flags |= BIT_BLAST;
71 break;
72 case 'c':
73 Flags |= MAINTAIN_CASE;
74 break;
75 case 'a':
76 Flags |= ADD_ANTENNA;
77 if (AntennaCell != NULL) free(AntennaCell);
78 AntennaCell = strdup(optarg);
79 break;
80 case 'n':
81 Flags |= NONAME_POWER;
82 break;
83 case 'h':
84 case 'H':
85 helpmessage(stdout);
86 exit(0);
87 break;
88 case 'l':
89 LefRead(optarg); /* Can be called multiple times */
90 break;
91 case 'v':
92 free(VddNet);
93 VddNet = strdup(optarg);
94 if ((cptr = strchr(VddNet, ',')) != NULL) {
95 *cptr = '\0';
96 VddTap = strdup(cptr + 1);
97 cleanup_string(VddTap);
98 }
99 cleanup_string(VddNet);
100 break;
101 case 'o':
102 vlogoutname = strdup(optarg);
103 break;
104 case 'g':
105 free(GndNet);
106 GndNet = strdup(optarg);
107 if ((cptr = strchr(GndNet, ',')) != NULL) {
108 *cptr = '\0';
109 GndTap = strdup(cptr + 1);
110 cleanup_string(GndTap);
111 }
112 cleanup_string(GndNet);
113 break;
114 default:
115 fprintf(stderr,"Bad switch \"%c\"\n", (char)i);
116 helpmessage(stderr);
117 return 1;
118 }
119 }
120
121 if (optind < argc) {
122 vloginname = strdup(argv[optind]);
123 optind++;
124 }
125 else {
126 fprintf(stderr, "Couldn't find a filename as input\n");
127 helpmessage(stderr);
128 return 1;
129 }
130 optind++;
131
132 /* If any LEF files were read, hash the GateInfo list */
133 if (GateInfo != NULL) {
134 GATE gate;
135 for (gate = GateInfo; gate; gate = gate->next) {
136 HashPtrInstall(gate->gatename, gate, &Lefhash);
137 }
138 }
139
140 topcell = ReadVerilog(vloginname);
141 result = write_output(topcell, Flags, vlogoutname);
142 return result;
143 }
144
145 /*--------------------------------------------------------------*/
146 /* Name compare for VddNet and GndNet. Remove any trailing "!" */
147 /* (global reference) from the net name. Note that for cells */
148 /* requiring tap cells there may be multiple power and ground */
149 /* names, comma-separated. Match any in the list. */
150 /*--------------------------------------------------------------*/
151
is_pwr_name(char * text)152 int is_pwr_name(char *text)
153 {
154 int n = strlen(text);
155
156 if (*(text + n - 1) == '!') *(text + n - 1) = '\0';
157
158 if (!strcmp(text, VddNet)) return 1;
159 if (!strcmp(text, GndNet)) return 1;
160 if ((VddTap != NULL) && !strcmp(text, VddTap)) return 1;
161 if ((GndTap != NULL) && !strcmp(text, GndTap)) return 1;
162 return 0;
163 }
164
165 /*--------------------------------------------------------------*/
166 /* String input cleanup (mainly strip quoted text) */
167 /*--------------------------------------------------------------*/
168
cleanup_string(char * text)169 void cleanup_string(char *text)
170 {
171 int i;
172 char *sptr, *wptr;
173
174 /* Remove quotes from quoted strings */
175
176 sptr = strchr(text, '"');
177 if (sptr != NULL) {
178 i = 0;
179 while (sptr[i + 1] != '"') {
180 sptr[i] = sptr[i + 1];
181 i++;
182 }
183 sptr[i] = '\0';
184 }
185
186 /* Remove any trailing "!" used as a global identifier */
187 if ((sptr > text) && (*(sptr - 1) == '!')) {
188 *(sptr - 1) = '\0';
189 }
190 }
191
192 /*--------------------------------------------------------------------------*/
193 /* Recursion callback function for each item in the cellrec nets hash table */
194 /*--------------------------------------------------------------------------*/
195
output_wires(struct hashlist * p,void * cptr)196 struct nlist *output_wires(struct hashlist *p, void *cptr)
197 {
198 struct netrec *net;
199 FILE *outf = (FILE *)cptr;
200
201 net = (struct netrec *)(p->ptr);
202
203 /* Ignore the power and ground nets; these have already been output */
204 /* This also extends to any net in the form <digit><single quote> */
205
206 if (p->name[0] == '\'') return NULL;
207 if (isdigit(p->name[0])) {
208 char c, *dptr;
209
210 dptr = p->name;
211 while (isdigit(*dptr)) dptr++;
212 if (*dptr == '\0') return NULL;
213 else if (*dptr == '\'') {
214 c = *(dptr + 1);
215 if (c == 'b' || c == 'h' || c == 'd' || c == 'o')
216 return NULL;
217 }
218 }
219 else if (is_pwr_name(p->name)) return NULL;
220
221 fprintf(outf, "wire ");
222 if (net->start >= 0 && net->end >= 0) {
223 fprintf(outf, "[%d:%d] ", net->start, net->end);
224 }
225 fprintf(outf, "%s ;\n", p->name);
226 return NULL;
227 }
228
229 /*----------------------------------------------------------------------*/
230 /* Convert a verilog number into a binary string. The target string */
231 /* "bitstring" is assumed to be at least (bits + 1) bytes in length. */
232 /* "c" is a conversion type ('h', 'o', or 'd'). */
233 /*----------------------------------------------------------------------*/
234 /* hexidecimal to binary */
235
hex2binary(char * uval,int bits)236 char *hex2binary(char *uval, int bits)
237 {
238 int first, dval, hexc;
239 char *bitstring = (char *)malloc(1 + bits);
240 char *hptr, *bptr, *hstring;
241 char binhex[5];
242
243 first = bits % 4;
244 hexc = ((first == 0) ? 0 : 1) + (bits / 4); /* Number of hex characters */
245
246 hstring = (char *)malloc(hexc + 1);
247 strncpy(hstring, uval, hexc);
248 *(hstring + hexc) = '\0';
249 for (hptr = hstring; *hptr != '\0'; hptr++) {
250
251 /* Catch 'x', 'X', etc., and convert to zero. */
252 /* Keep 'z'/'Z' as this must be handled differently */
253
254 if ((*hptr == 'z') || (*hptr == 'Z')) *hptr = 'Z';
255 else if ((*hptr == 'x') || (*hptr == 'X')) *hptr = '0';
256 }
257
258 hptr = hstring;
259 bptr = bitstring;
260 while (*hptr != '\0') {
261 switch(*hptr) {
262 case 'Z':
263 strcpy(binhex, "ZZZZ");
264 break;
265 case '0':
266 strcpy(binhex, "0000");
267 break;
268 case '1':
269 strcpy(binhex, "0001");
270 break;
271 case '2':
272 strcpy(binhex, "0010");
273 break;
274 case '3':
275 strcpy(binhex, "0011");
276 break;
277 case '4':
278 strcpy(binhex, "0100");
279 break;
280 case '5':
281 strcpy(binhex, "0101");
282 break;
283 case '6':
284 strcpy(binhex, "0110");
285 break;
286 case '7':
287 strcpy(binhex, "0111");
288 break;
289 case '8':
290 strcpy(binhex, "1000");
291 break;
292 case '9':
293 strcpy(binhex, "1001");
294 break;
295 case 'a':
296 strcpy(binhex, "1010");
297 break;
298 case 'b':
299 strcpy(binhex, "1011");
300 break;
301 case 'c':
302 strcpy(binhex, "1100");
303 break;
304 case 'd':
305 strcpy(binhex, "1101");
306 break;
307 case 'e':
308 strcpy(binhex, "1110");
309 break;
310 case 'f':
311 strcpy(binhex, "1111");
312 break;
313 }
314 if (first > 0) {
315 strncpy(bptr, binhex + (4 - first), first);
316 *(bptr + first) = '\0';
317 bptr += first;
318 first = 0;
319 }
320 else {
321 strcpy(bptr, binhex);
322 bptr += 4;
323 }
324 hptr++;
325 }
326 return bitstring;
327 }
328
329 /* octal to binary */
330
oct2binary(char * uval,int bits)331 char *oct2binary(char *uval, int bits)
332 {
333 int first, dval, octc;
334 char *bitstring = (char *)malloc(1 + bits);
335 char *optr, *bptr, *ostring;
336 char binoct[4];
337
338 first = bits % 3;
339 octc = ((first == 0) ? 0 : 1) + (bits / 3); /* Number of octal characters */
340 ostring = (char *)malloc(1 + octc);
341
342 ostring = (char *)malloc(octc + 1);
343 strncpy(ostring, uval, octc);
344 *(ostring + octc) = '\0';
345 for (optr = ostring; *optr != '\0'; optr++) {
346
347 /* Catch 'x', 'X', etc., and convert to zero. */
348 /* Keep 'z'/'Z' as this must be handled differently */
349
350 if ((*optr == 'z') || (*optr == 'Z')) *optr = 'Z';
351 else if ((*optr == 'x') || (*optr == 'X')) *optr = '0';
352 }
353
354 optr = ostring;
355 bptr = bitstring;
356 while (*optr != '\0') {
357 switch(*optr) {
358 case 'Z':
359 strcpy(binoct, "ZZZ");
360 break;
361 case '0':
362 strcpy(binoct, "000");
363 break;
364 case '1':
365 strcpy(binoct, "001");
366 break;
367 case '2':
368 strcpy(binoct, "010");
369 break;
370 case '3':
371 strcpy(binoct, "011");
372 break;
373 case '4':
374 strcpy(binoct, "100");
375 break;
376 case '5':
377 strcpy(binoct, "101");
378 break;
379 case '6':
380 strcpy(binoct, "110");
381 break;
382 case '7':
383 strcpy(binoct, "11");
384 break;
385 }
386 if (first > 0) {
387 strncpy(bptr, binoct + (3 - first), first);
388 *(bptr + first) = '\0';
389 bptr += first;
390 first = 0;
391 }
392 else {
393 strcpy(bptr, binoct);
394 bptr += 3;
395 }
396 optr++;
397 }
398 return bitstring;
399 }
400
401 /* decimal to binary */
402
dec2binary(char * uval,int bits)403 char *dec2binary(char *uval, int bits)
404 {
405 int first, dval, hexc;
406 char *bitstring = (char *)malloc(1 + bits);
407 char *hptr, *bptr, *hstring, *nval;
408 char binhex[5];
409
410 first = bits % 4;
411 hexc = ((first == 0) ? 0 : 1) + bits >> 2; /* Number of hex characters */
412 hstring = (char *)malloc(1 + hexc);
413
414 /* Scan integer value then convert to hex */
415 sscanf(uval, "%d", &dval);
416 sprintf(hstring, "%0*x", hexc, dval);
417
418 hptr = hstring;
419 bptr = bitstring;
420 while (*hptr != '\0') {
421 switch(*hptr) {
422 case '0':
423 strcpy(binhex, "0000");
424 break;
425 case '1':
426 strcpy(binhex, "0001");
427 break;
428 case '2':
429 strcpy(binhex, "0010");
430 break;
431 case '3':
432 strcpy(binhex, "0011");
433 break;
434 case '4':
435 strcpy(binhex, "0100");
436 break;
437 case '5':
438 strcpy(binhex, "0101");
439 break;
440 case '6':
441 strcpy(binhex, "0110");
442 break;
443 case '7':
444 strcpy(binhex, "0111");
445 break;
446 case '8':
447 strcpy(binhex, "1000");
448 break;
449 case '9':
450 strcpy(binhex, "1001");
451 break;
452 case 'a':
453 strcpy(binhex, "1010");
454 break;
455 case 'b':
456 strcpy(binhex, "1011");
457 break;
458 case 'c':
459 strcpy(binhex, "1100");
460 break;
461 case 'd':
462 strcpy(binhex, "1101");
463 break;
464 case 'e':
465 strcpy(binhex, "1110");
466 break;
467 case 'f':
468 strcpy(binhex, "1111");
469 break;
470 }
471 if (first > 0) {
472 strncpy(bptr, binhex + (4 - first), first);
473 bptr += first;
474 first = 0;
475 }
476 else {
477 strcpy(bptr, binhex);
478 bptr += 4;
479 }
480 hptr++;
481 }
482 return bitstring;
483 }
484
485 /*----------------------------------------------------------------------*/
486 /* Recursion callback function for each item in the cellrec properties */
487 /* hash table */
488 /*----------------------------------------------------------------------*/
489
output_props(struct hashlist * p,void * cptr)490 struct nlist *output_props(struct hashlist *p, void *cptr)
491 {
492 char *propval = (char *)(p->ptr);
493 FILE *outf = (FILE *)cptr;
494
495 fprintf(outf, ".%s(%s),\n", p->name, propval);
496 return NULL;
497 }
498
499 /*--------------------------------------------------------------*/
500 /* Find the idx'th component of a net name. This pulls the */
501 /* single wire name out of an indexed or concatenated array. */
502 /* */
503 /* Note that this routine does not handle nested braces. */
504 /*--------------------------------------------------------------*/
505
GetIndexedNet(char * netname,int ridx,struct cellrec * topcell)506 char *GetIndexedNet(char *netname, int ridx, struct cellrec *topcell)
507 {
508 int i, alen, idx;
509 struct netrec wb;
510 char *sptr, *pptr, savc, *bptr;
511 static char *subname = NULL;
512 if (subname == NULL) subname = (char *)malloc(1);
513
514 if (*netname == '{') {
515 sptr = netname + 1;
516 i = 0;
517 while (i <= ridx) {
518 /* Advance to next comma or close-brace */
519 pptr = strchr(sptr, ',');
520 if (pptr == NULL) pptr = strchr(sptr, '}');
521 if (pptr == NULL) pptr = sptr + strlen(sptr) - 1;
522
523 savc = *pptr;
524 *pptr = '\0';
525
526 /* Does the array component at sptr have array bounds? */
527 GetBus(sptr, &wb, &topcell->nets);
528 if (wb.start != -1) {
529 alen = (wb.start - wb.end);
530 if (alen < 0) alen = -alen;
531 if (i + alen < ridx)
532 i += alen;
533 else {
534 if (wb.start < wb.end) idx = wb.start + (ridx - i);
535 else idx = wb.start - (ridx - i);
536 bptr = strrchr(sptr, '[');
537 if (bptr != NULL) *bptr = '\0';
538 subname = (char *)realloc(subname, strlen(sptr) + 10);
539 sprintf(subname, "%s[%d]", sptr, idx);
540 i = ridx;
541 if (bptr != NULL) *bptr = '[';
542 }
543 }
544 else {
545 if (i == ridx) {
546 subname = (char *)realloc(subname, strlen(sptr) + 1);
547 sprintf(subname, "%s", sptr);
548 }
549 i++;
550 }
551 *pptr = savc;
552 }
553 }
554 else {
555 GetBus(netname, &wb, &topcell->nets);
556 idx = (wb.start > wb.end) ? (wb.start - ridx) : (wb.start + ridx);
557 bptr = strrchr(netname, '[');
558 if (bptr != NULL) *bptr = '\0';
559
560 subname = (char *)realloc(subname, strlen(netname) + 10);
561 sprintf(subname, "%s[%d]", netname, idx);
562 if (bptr != NULL) *bptr = '[';
563 }
564 return subname;
565 }
566
567 /*--------------------------------------------------------------*/
568 /* write_output */
569 /* */
570 /* ARGS: */
571 /* RETURNS: 1 to OS */
572 /* SIDE EFFECTS: */
573 /*--------------------------------------------------------------*/
574
write_output(struct cellrec * topcell,unsigned char Flags,char * outname)575 int write_output(struct cellrec *topcell, unsigned char Flags, char *outname)
576 {
577 FILE *outfptr = stdout;
578 int result = 0;
579 int nunconn = 0;
580 int arrayidx = -1;
581
582 GATE gate = (GATE)NULL;
583
584 struct netrec *net;
585 struct portrec *port;
586 struct instance *inst;
587
588 if (outname != NULL) {
589 outfptr = fopen(outname, "w");
590 if (outfptr == NULL) {
591 fprintf(stderr, "Error: Cannot open file %s for writing.\n", outname);
592 return 1;
593 }
594 }
595
596 /* Write output module header */
597 fprintf(outfptr, "/* Verilog module written by vlog2Verilog (qflow) */\n");
598
599 if (Flags & IMPLICIT_POWER)
600 fprintf(outfptr, "/* With explicit power connections */\n");
601 if (!(Flags & MAINTAIN_CASE))
602 fprintf(outfptr, "/* With case-insensitive names (SPICE-compatible) */\n");
603 if (Flags & BIT_BLAST)
604 fprintf(outfptr, "/* With bit-blasted vectors */\n");
605 if (Flags & NONAME_POWER)
606 fprintf(outfptr, "/* With power connections converted to binary 1, 0 */\n");
607 fprintf(outfptr, "\n");
608
609 fprintf(outfptr, "module %s(\n", topcell->name);
610
611 if (Flags & IMPLICIT_POWER) {
612 fprintf(outfptr, " inout %s,\n", VddNet);
613 fprintf(outfptr, " inout %s", GndNet);
614 if (topcell->portlist) fprintf(outfptr, ",");
615 fprintf(outfptr, "\n");
616 }
617
618 for (port = topcell->portlist; port; port = port->next) {
619 if (port->name == NULL) continue;
620 switch(port->direction) {
621 case PORT_INPUT:
622 fprintf(outfptr, " input ");
623 break;
624 case PORT_OUTPUT:
625 fprintf(outfptr, " output ");
626 break;
627 case PORT_INOUT:
628 fprintf(outfptr, " inout ");
629 break;
630 }
631 net = HashLookup(port->name, &topcell->nets);
632 if (net && net->start >= 0 && net->end >= 0) {
633 fprintf(outfptr, "[%d:%d] ", net->start, net->end);
634 }
635 fprintf(outfptr, "%s", port->name);
636 if (port->next) fprintf(outfptr, ",");
637 fprintf(outfptr, "\n");
638 }
639 fprintf(outfptr, ");\n\n");
640
641 /* Declare all wires */
642
643 if (!(Flags & IMPLICIT_POWER) && !(Flags & NONAME_POWER)) {
644 fprintf(outfptr, "wire %s = 1'b1;\n", VddNet);
645 fprintf(outfptr, "wire %s = 1'b0;\n\n", GndNet);
646 }
647
648 RecurseHashTablePointer(&topcell->nets, output_wires, outfptr);
649 fprintf(outfptr, "\n");
650
651 /* Write instances in the order of the input file */
652
653 for (inst = topcell->instlist; inst; ) {
654 int nprops = RecurseHashTable(&inst->propdict, CountHashTableEntries);
655 fprintf(outfptr, "%s ", inst->cellname);
656 if (nprops > 0) {
657 fprintf(outfptr, "#(\n");
658 RecurseHashTablePointer(&inst->propdict, output_props, outfptr);
659 fprintf(outfptr, ") ");
660 }
661 if (!(inst->cellname)) {
662 fprintf(outfptr, "vlog2Verilog: No cell for instance %s\n", inst->instname);
663 result = 1; // Set error result but continue output.
664 }
665 if (inst->arraystart == -1)
666 fprintf(outfptr, "%s", inst->instname);
667 else {
668 if (Flags & BIT_BLAST) {
669 if (arrayidx == -1) arrayidx = inst->arraystart;
670 fprintf(outfptr, "%s[%d]", inst->instname, arrayidx);
671 }
672 else if (inst->arraystart == inst->arrayend) {
673 // NOTE: This case is probably coming from incorrect handling
674 // in DEF2Verilog which needs to be fixed at the source.
675 fprintf(outfptr, "\%s[%d] ", inst->instname, inst->arraystart);
676 }
677 else {
678 fprintf(outfptr, "%s [%d:%d]", inst->instname,
679 inst->arraystart, inst->arrayend);
680 }
681 }
682 fprintf(outfptr, " (\n");
683
684 // If there is a gate record read from LEF, keep a pointer to it.
685 if (GateInfo != NULL)
686 gate = (GATE)HashLookup(inst->cellname, &Lefhash);
687
688 if (Flags & IMPLICIT_POWER) {
689
690 /* If any LEF files were read, then get the power and */
691 /* ground net names from the LEF file definition. */
692
693 if (gate) {
694 int n;
695 u_char found = 0, need = 2;
696 if (VddTap != NULL) need++;
697 if (GndTap != NULL) need++;
698 for (n = 0; n < gate->nodes; n++) {
699 if (gate->use[n] == PORT_USE_POWER) {
700 if (found > 0) fprintf(outfptr, ",\n");
701 fprintf(outfptr, " .%s(%s)", gate->node[n], VddNet);
702 found++;
703 }
704 else if (gate->use[n] == PORT_USE_GROUND) {
705 if (found > 0) fprintf(outfptr, ",\n");
706 fprintf(outfptr, " .%s(%s)", gate->node[n], GndNet);
707 found++;
708 }
709 if (found == need) break;
710 }
711 if (found < need) {
712 /* Handle the annoying case in which LEF files do not */
713 /* contain pin entries for the taps. The tap names */
714 /* passed to vlog2Verilog in the command line will be */
715 /* accepted as Truth. */
716 if (GndTap != NULL) {
717 if (found > 0) fprintf(outfptr, ",\n");
718 fprintf(outfptr, " .%s(%s)", GndTap, GndNet);
719 found++;
720 }
721 if (VddTap != NULL) {
722 if (found > 0) fprintf(outfptr, ",\n");
723 fprintf(outfptr, " .%s(%s)", VddTap, VddNet);
724 }
725 }
726 }
727 else {
728 /* Fall back on VddNet and GndNet names */
729 fprintf(outfptr, " .%s(%s),\n", GndNet, GndNet);
730 if (GndTap != NULL)
731 fprintf(outfptr, " .%s(%s),\n", GndTap, GndNet);
732 fprintf(outfptr, " .%s(%s)", VddNet, VddNet);
733 if (VddTap != NULL)
734 fprintf(outfptr, ",\n .%s(%s)", VddTap, VddNet);
735 }
736 if (inst->portlist) fprintf(outfptr, ",");
737 fprintf(outfptr, "\n");
738 }
739
740 /* Write each port and net connection */
741 for (port = inst->portlist; port; port = port->next) {
742
743 /* If writing explicit power net names, then watch */
744 /* for power connections encoded as binary, and */
745 /* convert them to the power bus names. */
746
747 if ((Flags & IMPLICIT_POWER) || (!(Flags & NONAME_POWER))) {
748 int brepeat = 0;
749 char is_array = FALSE, saveptr;
750 char *sptr = port->net, *nptr;
751 char *expand = (char *)malloc(1);
752
753 *expand = '\0';
754 if (*sptr == '{') {
755 is_array = TRUE;
756 sptr++;
757 expand = (char *)realloc(expand, 2);
758 strcpy(expand, "{");
759 }
760 while ((*sptr != '}') && (*sptr != '\0')) {
761 int nest = 0;
762
763 nptr = sptr + 1;
764 while ((*nptr != '\0') && (*nptr != ',')) {
765 if (*nptr == '{') nest++;
766 if (*nptr == '}') {
767 if (nest == 0) break;
768 else nest--;
769 }
770 nptr++;
771 }
772 saveptr = *nptr;
773 *nptr = '\0';
774
775 if (isdigit(*sptr) || (*sptr == '\'')) {
776 char *bptr = sptr;
777 if (sscanf(bptr, "%d", &brepeat) == 0) brepeat = -1;
778 while (isdigit(*bptr)) bptr++;
779
780 /* Is digit followed by "'" (fixed values 1 or 0)? */
781
782 if (*bptr == '\'') {
783 char *bitstring;
784 bptr++;
785
786 /* Important note: Need to check if 'x' is */
787 /* on an output, in which case it should be */
788 /* treated like 'z' (unconnected). */
789
790 /* Ports in verilog instances have no */
791 /* direction information so it is necessary */
792 /* to pull the information from the LEF */
793 /* record of the cell. */
794
795 if (gate) {
796 int n;
797 for (n = 0; n < gate->nodes; n++) {
798 if (!strcmp(gate->node[n], port->name)) {
799 switch (gate->direction[n]) {
800 case PORT_CLASS_INPUT:
801 port->direction = PORT_INPUT;
802 break;
803 case PORT_CLASS_OUTPUT:
804 port->direction = PORT_OUTPUT;
805 break;
806 default:
807 port->direction = PORT_INOUT;
808 break;
809 }
810 break;
811 }
812 }
813 }
814
815 if (port->direction != PORT_INPUT) {
816 char *xptr;
817 for (xptr = bptr; *xptr != '\0'; xptr++) {
818 if ((*xptr == 'X') || (*xptr == 'x'))
819 *xptr = 'z';
820 }
821 }
822
823 switch(*bptr) {
824 case 'd':
825 bitstring = dec2binary(bptr + 1, brepeat);
826 break;
827 case 'h':
828 bitstring = hex2binary(bptr + 1, brepeat);
829 break;
830 case 'o':
831 bitstring = oct2binary(bptr + 1, brepeat);
832 break;
833 default:
834 bitstring = strdup(bptr + 1);
835 break;
836 }
837
838 if (brepeat < 0) brepeat = strlen(bitstring);
839
840 if ((brepeat > 1) && (is_array == FALSE)) {
841 is_array = TRUE;
842 expand = (char *)realloc(expand, strlen(expand) + 2);
843 strcat(expand, "{");
844 }
845
846 bptr = bitstring;
847 while (*bptr != '\0') {
848 if (*bptr == '1') {
849 expand = (char *)realloc(expand,
850 strlen(expand) +
851 strlen(VddNet) + 2);
852 strcat(expand, VddNet);
853 }
854 else if (tolower(*bptr) == 'z') {
855 char unconnect[20];
856 /* Unconnected node: Make a new node name. */
857 /* This is a single bit, so it can be */
858 /* implicitly declared. */
859 sprintf(unconnect, "\\$_unconn_%d_ ", nunconn++);
860 expand = (char *)realloc(expand,
861 strlen(expand) + strlen(unconnect)
862 + 1);
863 strcat(expand, unconnect);
864 }
865 else { /* Note: If 'X', then ground it */
866 expand = (char *)realloc(expand,
867 strlen(expand) +
868 strlen(GndNet) + 2);
869 strcat(expand, GndNet);
870 }
871 brepeat--;
872 if (brepeat > 0)
873 strcat(expand, ",");
874 bptr++;
875 if (brepeat <= 0) break;
876 }
877 if (bptr == bitstring) {
878 fprintf(stderr, "Warning: Cannot parse \"%s\"\n", sptr);
879 }
880 while (brepeat > 0) {
881 if ((bptr > bitstring) && (*(bptr - 1) == '1')) {
882 expand = (char *)realloc(expand,
883 strlen(expand) +
884 strlen(VddNet) + 2);
885 strcat(expand, VddNet);
886 }
887 else { /* Note: If 'X', then ground it */
888 expand = (char *)realloc(expand,
889 strlen(expand) +
890 strlen(GndNet) + 2);
891 strcat(expand, GndNet);
892 }
893 brepeat--;
894 if (brepeat > 0)
895 strcat(expand, ",");
896 }
897 free(bitstring);
898 }
899
900 /* Otherwise add to "expand" verbatim */
901 else {
902 expand = (char *)realloc(expand, strlen(expand) +
903 strlen(sptr) + 1);
904 strcat(expand, sptr);
905 }
906 }
907 else {
908 /* Normal net name, add to "expand" */
909 expand = (char *)realloc(expand, strlen(expand) +
910 strlen(sptr) + 1);
911 strcat(expand, sptr);
912 }
913 if (saveptr == ',') {
914 expand = (char *)realloc(expand, strlen(expand) + 2);
915 strcat(expand, ",");
916 }
917 *nptr = saveptr;
918 sptr = nptr;
919 if (saveptr != '\0') sptr++;
920 }
921
922 if (is_array) {
923 expand = (char *)realloc(expand, strlen(expand) + 2);
924 strcat(expand, "}");
925 }
926
927 /* Replace port->net */
928
929 free(port->net);
930 port->net = expand;
931 }
932 fprintf(outfptr, " .%s(", port->name);
933 if ((Flags & BIT_BLAST) && (arrayidx != -1)) {
934 /* Find the index from the start and pull that item from port->net */
935 int ridx;
936 ridx = arrayidx - inst->arraystart;
937 if (ridx < 0) ridx = -ridx;
938 fprintf(outfptr, "%s", GetIndexedNet(port->net, ridx, topcell));
939 }
940 else
941 fprintf(outfptr, "%s", port->net);
942 fprintf(outfptr, ")");
943 if (port->next) fprintf(outfptr, ",");
944 fprintf(outfptr, "\n");
945 }
946 fprintf(outfptr, ");\n\n");
947
948 /* For bit-blasted output, output each element of an array separately. */
949 if (Flags & BIT_BLAST) {
950 if (arrayidx == inst->arrayend) {
951 inst = inst->next;
952 arrayidx = -1;
953 }
954 else if (arrayidx < inst->arrayend)
955 arrayidx++;
956 else if (arrayidx > inst->arrayend)
957 arrayidx--;
958 }
959 else
960 inst = inst->next;
961 }
962
963 if (Flags & ADD_ANTENNA) {
964 char *antennapin = NULL;
965 GATE gate, acell = NULL;
966 double asize;
967
968 /* Find the cell name that matches the antenna cell */
969 /* Can't use the hash table here because name may be a */
970 /* prefix. If more than one cell matches by prefix, */
971 /* then use the cell with the smallest area. */
972
973 for (gate = GateInfo; gate; gate = gate->next) {
974 if (!strncmp(gate->gatename, AntennaCell, strlen(AntennaCell))) {
975 if (!strcmp(gate->gatename, AntennaCell)) {
976 acell = gate;
977 break;
978 }
979 else if (acell == NULL) {
980 acell = gate;
981 }
982 else {
983 if (gate->width < acell->width) {
984 acell = gate;
985 }
986 }
987 }
988 }
989
990 if (acell) {
991 int i;
992 /* Find the node that isn't a power pin */
993 for (i = 0; i < acell->nodes; i++) {
994 if (acell->use[i] != PORT_USE_POWER &&
995 acell->use[i] != PORT_USE_GROUND) {
996 antennapin = acell->node[i];
997 break;
998 }
999 }
1000 }
1001
1002 if (antennapin) {
1003 int antcnt = 0;
1004
1005 /* Add antenna cells to all module inputs */
1006
1007 for (port = topcell->portlist; port; port = port->next) {
1008 if (port->name == NULL) continue;
1009 switch(port->direction) {
1010 case PORT_INPUT:
1011 fprintf(outfptr, "%s antenna_%d ", acell->gatename, antcnt);
1012
1013 net = HashLookup(port->name, &topcell->nets);
1014 if (net && net->start >= 0 && net->end >= 0) {
1015 fprintf(outfptr, "[%d:%d] ", net->start, net->end);
1016 }
1017
1018 fprintf(outfptr, "(\n");
1019 fprintf(outfptr, " .%s(%s)\n", antennapin, port->name);
1020 fprintf(outfptr, ");\n\n");
1021 antcnt++;
1022 break;
1023 }
1024 }
1025 }
1026 }
1027
1028 /* End the module */
1029 fprintf(outfptr, "endmodule\n");
1030
1031 if (outname != NULL) fclose(outfptr);
1032
1033 fflush(stdout);
1034 return result;
1035 }
1036
1037 /*--------------------------------------------------------------*/
1038 /* C helpmessage - tell user how to use the program */
1039 /* */
1040 /* ARGS: */
1041 /* RETURNS: 1 to OS */
1042 /* SIDE EFFECTS: */
1043 /*--------------------------------------------------------------*/
1044
helpmessage(FILE * outf)1045 void helpmessage(FILE *outf)
1046 {
1047 fprintf(outf, "vlog2Verilog [-options] <netlist>\n");
1048 fprintf(outf, "\n");
1049 fprintf(outf, "vlog2Verilog converts a netlist in one verilog style to\n");
1050 fprintf(outf, "another. LEF files may be given as inputs to determine\n");
1051 fprintf(outf, "power and ground net names for cells.\n");
1052 fprintf(outf, "\n");
1053 fprintf(outf, "options:\n");
1054 fprintf(outf, "\n");
1055 fprintf(outf, " -h Print this message\n");
1056 fprintf(outf, " -o <path> Set output filename (otherwise output is on stdout).\n");
1057 fprintf(outf, " -p Don't add power nodes to instances\n");
1058 fprintf(outf, " (only nodes present in the instance used)\n");
1059 fprintf(outf, " -b Remove vectors (bit-blasted)\n");
1060 fprintf(outf, " -c Case-insensitive output (SPICE compatible) \n");
1061 fprintf(outf, " -n Convert power nets to binary 1 and 0\n");
1062 fprintf(outf, " -a <name> Add antenna cells to module input pins.\n");
1063 fprintf(outf, " -l <path> Read LEF file from <path>\n");
1064 fprintf(outf, " -v <name> Use <name> for power net (default \"Vdd\")\n");
1065 fprintf(outf, " -g <name> Use <name> for ground net (default \"Gnd\")\n");
1066
1067 } /* helpmessage() */
1068
1069