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