1 /*----------------------------------------------------------------------*/
2 /* readverilog.c -- Input for Verilog format (structural verilog only)	*/
3 /*									*/
4 /* Adapted from verilog.c in netgen-1.5					*/
5 /*----------------------------------------------------------------------*/
6 
7 /*----------------------------------------------------------------------*/
8 /* The verilog input is limited to "structural verilog", that is,	*/
9 /* verilog code that only defines inputs, outputs, local nodes (via the	*/
10 /* "wire" statement), and instanced modules.  All modules are read down	*/
11 /* to the point where either a module (1) does not conform to the	*/
12 /* requirements above, or (2) has no module definition, in which case	*/
13 /* it is treated as a "black box" subcircuit and therefore becomes a	*/
14 /* low-level device.  Because in verilog syntax all instances of a	*/
15 /* module repeat both the module pin names and the local connections,	*/
16 /* placeholders can be built without the need to redefine pins later,	*/
17 /* as must be done for formats like SPICE that don't declare pin names	*/
18 /* in an instance call.							*/
19 /*----------------------------------------------------------------------*/
20 
21 /*----------------------------------------------------------------------*/
22 /* Note that use of 1'b0 or 1'b1 and similar variants is prohibited;	*/
23 /* the structural netlist should either declare VSS and/or VDD as	*/
24 /* inputs, or use tie-high and tie-low standard cells.			*/
25 /*----------------------------------------------------------------------*/
26 
27 /*----------------------------------------------------------------------*/
28 /* Most verilog syntax has been captured below.  Still to do:  Handle	*/
29 /* wires that are created on the fly using {...} notation, including	*/
30 /* the {n{...}} concatenation method.  Currently this syntax is only	*/
31 /* handled in nets connected to instance pins.				*/
32 /*----------------------------------------------------------------------*/
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <math.h>
39 #include <sys/types.h>
40 #include <pwd.h>
41 
42 #include "hash.h"
43 #include "readverilog.h"
44 
45 /*------------------------------------------------------*/
46 /* Global variables					*/
47 /*------------------------------------------------------*/
48 
49 struct filestack *OpenFiles = NULL;
50 int linesize = 0;	/* Amount of memory allocated for line */
51 int vlinenum = 0;
52 char *nexttok;
53 char *linetok;
54 char *line = NULL;	/* The line read in */
55 FILE *infile = NULL;
56 
57 struct hashtable verilogparams;
58 struct hashtable verilogdefs;
59 struct hashtable verilogvectors;
60 
61 char dictinit = FALSE;
62 
63 /*------------------------------------------------------*/
64 /* Structure for stacking nested `if[n]def		*/
65 /*------------------------------------------------------*/
66 
67 struct ifstack {
68     int invert;
69     char *kl;
70     struct ifstack *next;
71 };
72 
73 struct ifstack *condstack = NULL;
74 
75 /*------------------------------------------------------*/
76 /* Stack handling (push and pop)			*/
77 /*------------------------------------------------------*/
78 
PushStack(struct cellrec * cell,struct cellstack ** top)79 void PushStack(struct cellrec *cell, struct cellstack **top)
80 {
81    struct cellstack *newstack;
82 
83    newstack = (struct cellstack *)calloc(1, sizeof(struct cellstack));
84    newstack->cell = cell;
85    newstack->next = *top;
86    *top = newstack;
87 }
88 
89 /*------------------------------------------------------*/
90 
PopStack(struct cellstack ** top)91 struct cellrec *PopStack(struct cellstack **top)
92 {
93    struct cellstack *stackptr;
94    struct cellrec *cellptr;
95 
96    stackptr = *top;
97    cellptr = stackptr->cell;
98    if (!stackptr) return NULL;
99    *top = stackptr->next;
100    free(stackptr);
101 
102    return cellptr;
103 }
104 
105 /*----------------------------------------------------------------------*/
106 /* Routine that can be called to pre-install a definition into the	*/
107 /* verilogdefs hash table.						*/
108 /*----------------------------------------------------------------------*/
109 
VerilogDefine(char * key,char * value)110 void VerilogDefine(char *key, char *value)
111 {
112     if (dictinit == FALSE) {
113 	InitializeHashTable(&verilogdefs, TINYHASHSIZE);
114 	dictinit = TRUE;
115     }
116     HashPtrInstall(key, strdup(value), &verilogdefs);
117 }
118 
119 /*----------------------------------------------------------------------*/
120 /* Function similar to strtok() for token parsing.  The difference is   */
121 /* that it takes two sets of delimiters.  The first is whitespace       */
122 /* delimiters, which separate tokens.  The second is functional         */
123 /* delimiters, which separate tokens and have additional meaning, such  */
124 /* as parentheses, commas, semicolons, etc.  The parser needs to know   */
125 /* when such tokens occur in the string, so they are returned as        */
126 /* individual tokens.                                                   */
127 /*                                                                      */
128 /* Definition of delim2:  String of single delimiter characters.  The   */
129 /* special character "X" (which is never a delimiter in practice) is    */
130 /* used to separate single-character delimiters from two-character      */
131 /* delimiters (this presumably could be further extended as needed).    */
132 /* so ",;()" would be a valid delimiter set, but to include C-style     */
133 /* comments and verilog-style parameter lists, one would need           */
134 /* ",;()X/**///#(".                                                     */
135 /*----------------------------------------------------------------------*/
136 
strdtok(char * pstring,char * delim1,char * delim2)137 char *strdtok(char *pstring, char *delim1, char *delim2)
138 {
139     static char *stoken = NULL;
140     static char *sstring = NULL;
141     char *s, *s2;
142     char first = FALSE;
143     int twofer;
144 
145     if (pstring != NULL) {
146 	/* Allocate enough memory to hold the string;  tokens will be put here */
147 	if (sstring != NULL) free(sstring);
148 	sstring = (char *)malloc(strlen(pstring) + 1);
149 	stoken = pstring;
150 	first = TRUE;
151     }
152 
153     /* Skip over "delim1" delimiters at the string beginning */
154     for (; *stoken; stoken++) {
155         for (s2 = delim1; *s2; s2++)
156             if (*stoken == *s2)
157                 break;
158         if (*s2 == '\0') break;
159     }
160 
161     if (*stoken == '\0') return NULL;   /* Finished parsing */
162 
163     /* "stoken" is now set.  Now find the end of the current token */
164     /* Check string from position stoken.  If a character in "delim2" is found, */
165     /* save the character in "lastdelim", null the byte at that position, and   */
166     /* return the token.  If a character in "delim1" is found, do the same but  */
167     /* continue checking characters as long as there are contiguous "delim1"    */
168     /* characters.  If the series ends in a character from "delim2", then treat */
169     /* as for "delim2" above.  If not, then set "lastdelim" to a null byte and  */
170     /* return the token.                                                        */
171 
172     s = stoken;
173 
174     /* Special verilog rule:  If a name begins with '\', then all characters	*/
175     /* are a valid part of the name until a space character is reached.	  The	*/
176     /* space character becomes part of the verilog name.  The remainder of the	*/
177     /* name is parsed according to the rules of "delim2".			*/
178 
179     if (*s == '\\') {
180 	while (*s != '\0') {
181 	    if (*s == ' ') {
182 		s++;
183 		break;
184 	    }
185 	    s++;
186 	}
187     }
188 
189     for (; *s; s++) {
190 	twofer = TRUE;
191 	for (s2 = delim2; s2 && *s2; s2++) {
192 	    if (*s2 == 'X') {
193 		twofer = FALSE;
194 		continue;
195 	    }
196 	    if (twofer) {
197 		if ((*s == *s2) && (*(s + 1) == *(s2 + 1))) {
198 		    if (s == stoken) {
199 			strncpy(sstring, stoken, 2);
200 			*(sstring + 2) = '\0';
201 			stoken = s + 2;
202 		    }
203 		    else {
204 			strncpy(sstring, stoken, (int)(s - stoken));
205 			*(sstring + (s - stoken)) = '\0';
206 			stoken = s;
207 		    }
208 		    return sstring;
209 		}
210 		s2++;
211 		if (*s2 == '\0') break;
212 	    }
213 	    else if (*s == *s2) {
214 		if (s == stoken) {
215 		    strncpy(sstring, stoken, 1);
216 		    *(sstring + 1) = '\0';
217 		    stoken = s + 1;
218 		}
219 		else {
220 		    strncpy(sstring, stoken, (int)(s - stoken));
221 		    *(sstring + (s - stoken)) = '\0';
222 		    stoken = s;
223 		}
224 		return sstring;
225 	    }
226 	}
227 	for (s2 = delim1; *s2; s2++) {
228 	    if (*s == *s2) {
229 		strncpy(sstring, stoken, (int)(s - stoken));
230 		*(sstring + (s - stoken)) = '\0';
231 		stoken = s;
232 		return sstring;
233 	    }
234 	}
235     }
236     strcpy(sstring, stoken);    /* Just copy to the end */
237     stoken = s;
238     return sstring;
239 }
240 
241 /*----------------------------------------------------------------------*/
242 /* File opening, closing, and stack handling				*/
243 /* Return 0 on success, -1 on error.					*/
244 /*----------------------------------------------------------------------*/
245 
OpenParseFile(char * name)246 int OpenParseFile(char *name)
247 {
248     /* Push filestack */
249 
250     FILE *locfile = NULL;
251     struct filestack *newfile;
252 
253     locfile = fopen(name, "r");
254     vlinenum = 0;
255     /* reset the token scanner */
256     nexttok = NULL;
257 
258     if (locfile != NULL) {
259 	if (infile != NULL) {
260 	    newfile = (struct filestack *)malloc(sizeof(struct filestack));
261 	    newfile->file = infile;
262 	    newfile->next = OpenFiles;
263 	    OpenFiles = newfile;
264 	}
265 	infile = locfile;
266     }
267     return (locfile == NULL) ? -1 : 0;
268 }
269 
270 /*----------------------------------------------------------------------*/
271 
EndParseFile(void)272 int EndParseFile(void)
273 {
274     return feof(infile);
275 }
276 
277 /*----------------------------------------------------------------------*/
278 
CloseParseFile(void)279 int CloseParseFile(void)
280 {
281     struct filestack *lastfile;
282     int rval;
283     rval = fclose(infile);
284     infile = (FILE *)NULL;
285 
286     /* Pop filestack if not empty */
287     lastfile = OpenFiles;
288     if (lastfile != NULL) {
289 	OpenFiles = lastfile->next;
290 	infile = lastfile->file;
291 	free(lastfile);
292     }
293     return rval;
294 }
295 
296 /*----------------------------------------------------------------------*/
297 
InputParseError(FILE * f)298 void InputParseError(FILE *f)
299 {
300     char *ch;
301 
302     fprintf(f, "line number %d = '", vlinenum);
303     for (ch = line; *ch != '\0'; ch++) {
304 	if (isprint(*ch)) fprintf(f, "%c", *ch);
305 	else if (*ch != '\n') fprintf(f, "<<%d>>", (int)(*ch));
306     }
307     fprintf(f, "'\n");
308 }
309 
310 /*----------------------------------------------------------------------*/
311 /* Tokenizer routines							*/
312 /*----------------------------------------------------------------------*/
313 
314 #define WHITESPACE_DELIMITER " \t\n\r"
315 
316 /*----------------------------------------------------------------------*/
317 /* TrimQuoted() ---                                                     */
318 /* Remove spaces from inside single- or double-quoted strings.          */
319 /* Exclude bit values (e.g., "1'b0")					*/
320 /*----------------------------------------------------------------------*/
321 
TrimQuoted(char * line)322 void TrimQuoted(char *line)
323 {
324     char *qstart, *qend, *lptr;
325     int slen;
326     int changed;
327 
328     /* Single-quoted entries */
329     changed = TRUE;
330     lptr = line;
331     while (changed)
332     {
333 	changed = FALSE;
334 	qstart = strchr(lptr, '\'');
335 	if (qstart && (qstart > lptr)) {
336 	    if (isdigit(*(qstart - 1))) {
337 		lptr = qstart + 1;
338 		changed = TRUE;
339 		continue;
340 	    }
341 	}
342 	if (qstart)
343 	{
344 	    qend = strrchr(qstart + 1, '\'');
345 	    if (qend && (qend > qstart)) {
346 		slen = strlen(lptr);
347 		for (lptr = qstart + 1; lptr < qend; lptr++) {
348 		    if (*lptr == ' ') {
349 			memmove(lptr, lptr + 1, slen);
350 			qend--;
351 			changed = TRUE;
352 		    }
353 		}
354 		lptr++;
355 	    }
356 	}
357     }
358 
359     /* Double-quoted entries */
360     changed = TRUE;
361     lptr = line;
362     while (changed)
363     {
364 	changed = FALSE;
365 	qstart = strchr(lptr, '\"');
366 	if (qstart)
367 	{
368 	    qend = strchr(qstart + 1, '\"');
369 	    if (qend && (qend > qstart)) {
370 		for (lptr = qstart + 1; lptr < qend; lptr++) {
371 		    slen = strlen(lptr);
372 		    if (*lptr == ' ') {
373 			memmove(lptr, lptr + 1, slen);
374 			qend--;
375 			changed = TRUE;
376 		    }
377 		}
378 		lptr++;
379 	    }
380 	}
381     }
382 }
383 
384 /*----------------------------------------------------------------------*/
385 /* GetNextLineNoNewline()                                               */
386 /*                                                                      */
387 /* Fetch the next line, and grab the first token from the next line.    */
388 /* If there is no next token (next line is empty, and ends with a       */
389 /* newline), then place NULL in nexttok.                                */
390 /*                                                                      */
391 /*----------------------------------------------------------------------*/
392 
GetNextLineNoNewline(char * delimiter)393 int GetNextLineNoNewline(char *delimiter)
394 {
395     char *newbuf;
396     int testc;
397     int nested = 0;
398     char *s, *t, *w, e, *kl;
399     int len, dlen, vlen, addin;
400     unsigned char found;
401 
402     if (feof(infile)) return -1;
403 
404     while (1) {		/* May loop indefinitely in an `if[n]def conditional */
405 
406 	// This is more reliable than feof() ...
407 	testc = getc(infile);
408 	if (testc == -1) return -1;
409 	ungetc(testc, infile);
410 
411 	if (linesize == 0) {
412 	    /* Allocate memory for line */
413 	    linesize = 500;
414 	    line = (char *)malloc(linesize);
415 	    linetok = (char *)malloc(linesize);
416 	}
417 	fgets(line, linesize, infile);
418 	while (strlen(line) == linesize - 1) {
419 	    newbuf = (char *)malloc(linesize + 500);
420 	    strcpy(newbuf, line);
421 	    free(line);
422 	    line = newbuf;
423 	    fgets(line + linesize - 1, 501, infile);
424 	    linesize += 500;
425 	    free(linetok);
426 	    linetok = (char *)malloc(linesize * sizeof(char));
427 	}
428 
429 	/* Check for substitutions.  Make sure linetok is large enough 	*/
430 	/* to hold the entire line after substitutions.			*/
431 
432 	found = FALSE;
433 	addin = 0;
434 	for (s = line; *s != '\0'; s++) {
435 	    if (*s == '`') {
436 		w = s + 1;
437 		while (isalnum(*w)) w++;
438 		e = *w;
439 		*w = '\0';
440 		kl = (char *)HashLookup(s + 1, &verilogdefs);
441 		if (kl != NULL) {
442 		    dlen = strlen(s);
443 		    vlen = strlen(kl);
444 		    addin += vlen - dlen + 1;
445 		    found = TRUE;
446 		}
447 		*w = e;
448 	    }
449 	}
450 	if (found) {
451 	    len = strlen(line);
452 	    if (len + addin > linesize) {
453 		while (len + addin > linesize) linesize += 500;
454 		free(linetok);
455 		linetok = (char *)malloc(linesize);
456 	    }
457 	}
458 
459 	/* Make definition substitutions */
460 
461 	t = linetok;
462 	for (s = line; *s != '\0'; s++) {
463 	    if (*s == '`') {
464 		w = s + 1;
465 		while (isalnum(*w)) w++;
466 		e = *w;
467 		*w = '\0';
468 		kl = (char *)HashLookup(s + 1, &verilogdefs);
469 		if (kl != NULL) {
470 		    strcpy(t, kl);
471 		    t += strlen(t);
472 		    s = w - 1;
473 		}
474 		else *t++ = *s;
475 		*w = e;
476 	    }
477 	    else *t++ = *s;
478 	}
479 	*t = '\0';
480 
481 	TrimQuoted(linetok);
482 	vlinenum++;
483 
484 	nexttok = strdtok(linetok, WHITESPACE_DELIMITER, delimiter);
485 	if (nexttok == NULL) return 0;
486 
487 	/* Handle `ifdef, `ifndef, `elsif, `else, and `endif */
488 
489 	/* If currently skipping through a section, handle conditionals differently */
490 	if (condstack) {
491 	    if (((condstack->invert == 0) && (condstack->kl == NULL))
492 			|| ((condstack->invert == 1) && (condstack->kl != NULL))) {
493 		if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef")) {
494 		    nested++;
495 		    continue;
496 		}
497 		else if (nested > 0) {
498 		    if (match(nexttok, "`endif")) nested--;
499 		    continue;
500 		}
501 		else if (nexttok[0] != '`') continue;
502 	    }
503 	}
504 
505 	/* Handle conditionals (not being skipped over) */
506 
507 	if (match(nexttok, "`endif")) {
508 	    if (condstack == NULL) {
509 		fprintf(stderr, "Error:  `endif without corresponding `if[n]def\n");
510 	    }
511 	    else {
512 		struct ifstack *iftop = condstack;
513 		condstack = condstack->next;
514 		free(iftop);
515 	    }
516 	}
517 
518 	/* `if[n]def may be nested. */
519 
520 	else if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef") ||
521 			match(nexttok, "`elsif") || match(nexttok, "`else")) {
522 
523 	    /* Every `ifdef or `ifndef increases condstack by 1 */
524 	    if (nexttok[1] == 'i') {
525 		struct ifstack *newif = (struct ifstack *)malloc(sizeof(struct ifstack));
526 		newif->next = condstack;
527 		condstack = newif;
528 	    }
529 	    if (condstack == NULL) {
530 		fprintf(stderr, "Error:  %s without `if[n]def\n", nexttok);
531 		break;
532 	    }
533 	    else {
534 		if (match(nexttok, "`else")) {
535 		    /* Invert the sense of the if[n]def scope */
536 		    condstack->invert = (condstack->invert == 1) ? 0 : 1;
537 		}
538 		else if (match(nexttok, "`elsif")) {
539 		    nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter);
540 		    if (nexttok == NULL) {
541 			fprintf(stderr, "Error:  `elsif with no conditional.\n");
542 			return 0;
543 		    }
544 		    /* Keep the same scope but redefine the parameter */
545 		    condstack->invert = 0;
546 		    condstack->kl = (char *)HashLookup(nexttok, &verilogdefs);
547 		}
548 		else {
549 		    condstack->invert = (nexttok[3] == 'n') ? 1 : 0;
550 		    nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter);
551 		    if (nexttok == NULL) {
552 			fprintf(stderr, "Error:  %s with no conditional.\n", nexttok);
553 			return 0;
554 		    }
555 		    condstack->kl = (char *)HashLookup(nexttok, &verilogdefs);
556 		}
557 	    }
558 	}
559 	else if (condstack) {
560 	    if (((condstack->invert == 0) && (condstack->kl == NULL))
561 			|| ((condstack->invert == 1) && (condstack->kl != NULL)))
562 		continue;
563 	    else
564 		break;
565 	}
566 	else
567 	    break;
568     }
569     return 0;
570 }
571 
572 /*----------------------------------------------------------------------*/
573 /* Get the next line of input from file "infile", and find the first    */
574 /* valid token.                                                         */
575 /*----------------------------------------------------------------------*/
576 
GetNextLine(char * delimiter)577 void GetNextLine(char *delimiter)
578 {
579     do {
580 	if (GetNextLineNoNewline(delimiter) == -1) return;
581     } while (nexttok == NULL);
582 }
583 
584 /*----------------------------------------------------------------------*/
585 /* skip to the end of the current line                                  */
586 /*----------------------------------------------------------------------*/
587 
SkipNewLine(char * delimiter)588 void SkipNewLine(char *delimiter)
589 {
590     while (nexttok != NULL)
591 	nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter);
592 }
593 
594 /*----------------------------------------------------------------------*/
595 /* if nexttok is already NULL, force scanner to read new line           */
596 /*----------------------------------------------------------------------*/
597 
SkipTok(char * delimiter)598 void SkipTok(char *delimiter)
599 {
600     if (nexttok != NULL &&
601 		(nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter)))
602 	return;
603     GetNextLine(delimiter);
604 }
605 
606 /*----------------------------------------------------------------------*/
607 /* like SkipTok, but will not fetch a new line when the buffer is empty */
608 /* must be preceeded by at least one call to SkipTok()                  */
609 /*----------------------------------------------------------------------*/
610 
SkipTokNoNewline(char * delimiter)611 void SkipTokNoNewline(char *delimiter)
612 {
613     nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter);
614 }
615 
616 /*----------------------------------------------------------------------*/
617 /* Skip to the next token, ignoring any C-style comments.               */
618 /*----------------------------------------------------------------------*/
619 
SkipTokComments(char * delimiter)620 void SkipTokComments(char *delimiter)
621 {
622     SkipTok(delimiter);
623     while (nexttok) {
624 	if (!strcmp(nexttok, "//")) {
625 	    SkipNewLine(delimiter);
626 	    SkipTok(delimiter);
627 	}
628 	else if (!strcmp(nexttok, "/*")) {
629 	    while (nexttok && strcmp(nexttok, "*/"))
630 		SkipTok(delimiter);
631 	    if (nexttok) SkipTok(delimiter);
632 	}
633 	else if (!strcmp(nexttok, "(*")) {
634 	    while (nexttok && strcmp(nexttok, "*)"))
635 		SkipTok(delimiter);
636 	    if (nexttok) SkipTok(delimiter);
637 	}
638 	else break;
639     }
640 }
641 
642 /*----------------------------------------------------------------------*/
643 /* Free a bus structure in the hash table during cleanup		*/
644 /*----------------------------------------------------------------------*/
645 
freenet(struct hashlist * p)646 int freenet (struct hashlist *p)
647 {
648     struct netrec *wb;
649 
650     wb = (struct netrec *)(p->ptr);
651     free(wb);
652     return 1;
653 }
654 
655 /*----------------------------------------------------------------------*/
656 /* Create a new net (or bus) structure					*/
657 /*----------------------------------------------------------------------*/
658 
NewNet()659 struct netrec *NewNet()
660 {
661     struct netrec *wb;
662 
663     wb = (struct netrec *)calloc(1, sizeof(struct netrec));
664     if (wb == NULL) fprintf(stderr, "NewNet: Core allocation error\n");
665     return (wb);
666 }
667 
668 /*----------------------------------------------------------------------*/
669 /* BusHashLookup --							*/
670 /* Run HashLookup() on a string, first removing any bus delimiters.	*/
671 /*----------------------------------------------------------------------*/
672 
BusHashLookup(char * s,struct hashtable * table)673 void *BusHashLookup(char *s, struct hashtable *table)
674 {
675     void *rval;
676     char *dptr = NULL;
677     char *sptr = s;
678 
679     if (*sptr == '\\') {
680 	sptr = strchr(s, ' ');
681 	if (sptr == NULL) sptr = s;
682     }
683     if ((dptr = strchr(sptr, '[')) != NULL) *dptr = '\0';
684 
685     rval = HashLookup(s, table);
686     if (dptr) *dptr = '[';
687     return rval;
688 }
689 
690 /*----------------------------------------------------------------------*/
691 /* BusHashPtrInstall --							*/
692 /* Run HashPtrInstall() on a string, first removing any bus delimiters.	*/
693 /*----------------------------------------------------------------------*/
694 
BusHashPtrInstall(char * name,void * ptr,struct hashtable * table)695 struct hashlist *BusHashPtrInstall(char *name, void *ptr,
696                                 struct hashtable *table)
697 {
698     struct hashlist *rval;
699     char *dptr = NULL;
700     char *sptr = name;
701 
702     if (*sptr == '\\') {
703 	sptr = strchr(name, ' ');
704 	if (sptr == NULL) sptr = name;
705     }
706     if ((dptr = strchr(sptr, '[')) != NULL) *dptr = '\0';
707 
708     rval = HashPtrInstall(name, ptr, table);
709     if (dptr) *dptr = '[';
710     return rval;
711 }
712 
713 /*------------------------------------------------------------------------------*/
714 /* Get bus indexes from the notation name[a:b].  If there is only "name"	*/
715 /* then look up the name in the bus hash list and return the index bounds.	*/
716 /* Return 0 on success, 1 on syntax error, and -1 if signal is not a bus.	*/
717 /*										*/
718 /* Note that this routine relies on the delimiter characters including		*/
719 /* "[", ":", and "]" when calling NextTok.					*/
720 /*------------------------------------------------------------------------------*/
721 
GetBusTok(struct netrec * wb,struct hashtable * nets)722 int GetBusTok(struct netrec *wb, struct hashtable *nets)
723 {
724     int result, start, end;
725     char *kl;
726 
727     if (wb == NULL) return 0;
728     else {
729         wb->start = -1;
730         wb->end = -1;
731     }
732 
733     if (!strcmp(nexttok, "[")) {
734 	SkipTokComments(VLOG_DELIMITERS);
735 
736 	// Check for parameter names and substitute values if found.
737 	result = sscanf(nexttok, "%d", &start);
738 	if (result != 1) {
739 	    char *aptr = NULL;
740 	    char addin;
741 
742 	    // Check for "+/-(n)" at the end of a parameter name
743 	    aptr = strrchr(nexttok, '+');
744 	    if (aptr == NULL) aptr = strrchr(nexttok, '-');
745 	    if (aptr != NULL) {
746 		addin = *aptr;
747 		*aptr = '\0';
748 	    }
749 
750 	    // Is name in the parameter list?
751 	    kl = (char *)HashLookup(nexttok, &verilogparams);
752 	    if (kl == NULL) {
753 		fprintf(stdout, "Array value %s is not a number or a "
754 				"parameter (line %d).\n", nexttok, vlinenum);
755 		return 1;
756 	    }
757 	    else {
758 		result = sscanf(kl, "%d", &start);
759 		if (result != 1) {
760 		    fprintf(stdout, "Parameter %s has value %s that cannot be parsed"
761 				" as an integer (line %d).\n", nexttok, kl, vlinenum);
762 		    return 1;
763 		}
764 	    }
765 	    if (aptr != NULL) {
766 		int addval;
767 		*aptr = addin;
768 		if (sscanf(aptr + 1, "%d", &addval) != 1) {
769 		    fprintf(stdout, "Unable to parse parameter increment \"%s\" "
770 			    "(line %d).\n", aptr, vlinenum);
771 		    return 1;
772 		}
773 		start += (addin == '+') ? addval : -addval;
774 	    }
775 	}
776 
777 	SkipTokComments(VLOG_DELIMITERS);
778 	if (!strcmp(nexttok, "]")) {
779 	    result = 1;
780 	    end = start;	// Single bit
781 	}
782 	else if (strcmp(nexttok, ":")) {
783 	    fprintf(stdout, "Badly formed array notation:  Expected colon, "
784 			"found %s (line %d)\n", nexttok, vlinenum);
785 	    return 1;
786 	}
787 	else {
788 	    SkipTokComments(VLOG_DELIMITERS);
789 
790 	    // Check for parameter names and substitute values if found.
791 	    result = sscanf(nexttok, "%d", &end);
792 	    if (result != 1) {
793 		char *aptr = NULL;
794 		char addin;
795 
796 		// Check for "+/-(n)" at the end of a parameter name
797 		aptr = strrchr(nexttok, '+');
798 		if (aptr == NULL) aptr = strrchr(nexttok, '-');
799 		if (aptr != NULL) {
800 		    addin = *aptr;
801 		    *aptr = '\0';
802 		}
803 
804 		// Is name in the parameter list?
805 	        kl = (char *)HashLookup(nexttok, &verilogparams);
806 		if (kl == NULL) {
807 		    fprintf(stdout, "Array value %s is not a number or a "
808 				"parameter (line %d).\n", nexttok, vlinenum);
809 		    return 1;
810 		}
811 		else {
812 		    result = sscanf(kl, "%d", &end);
813 		    if (result != 1) {
814 		        fprintf(stdout, "Parameter %s has value %s that cannot"
815 				" be parsed as an integer (line %d).\n",
816 				nexttok, kl, vlinenum);
817 			return 1;
818 		    }
819 		}
820 		if (aptr != NULL) {
821 		    int addval;
822 		    *aptr = addin;
823 		    if (sscanf(aptr + 1, "%d", &addval) != 1) {
824 			fprintf(stdout, "Unable to parse parameter increment \"%s\" "
825 				"(line %d).\n", aptr, vlinenum);
826 			return 1;
827 		    }
828 		    end += (addin == '+') ? addval : -addval;
829 		}
830 	    }
831 	}
832 	wb->start = start;
833 	wb->end = end;
834 
835 	while (strcmp(nexttok, "]")) {
836 	    SkipTokComments(VLOG_DELIMITERS);
837 	    if (nexttok == NULL) {
838 		fprintf(stdout, "End of file reached while reading array bounds.\n");
839 		return 1;
840 	    }
841 	    else if (!strcmp(nexttok, ";")) {
842 		// Better than reading to end-of-file, give up on end-of-statement
843 		fprintf(stdout, "End of statement reached while reading "
844 				"array bounds (line %d).\n", vlinenum);
845 		return 1;
846 	    }
847 	}
848 	/* Move token forward to bus name */
849 	SkipTokComments(VLOG_DELIMITERS);
850     }
851     else if (nets) {
852 	struct netrec *hbus;
853 	hbus = (struct netrec *)BusHashLookup(nexttok, nets);
854 	if (hbus != NULL) {
855 	    wb->start = hbus->start;
856 	    wb->end = hbus->end;
857 	}
858 	else
859 	    return -1;
860     }
861     return 0;
862 }
863 
864 /*----------------------------------------------------------------------*/
865 /* GetBus() is similar to GetBusTok() (see above), but it parses from	*/
866 /* a string instead of the input tokenizer.				*/
867 /*----------------------------------------------------------------------*/
868 
GetBus(char * astr,struct netrec * wb,struct hashtable * nets)869 int GetBus(char *astr, struct netrec *wb, struct hashtable *nets)
870 {
871     char *colonptr, *brackstart, *brackend, *sstr;
872     int result, start, end;
873 
874     if (wb == NULL) return 0;
875     else {
876         wb->start = -1;
877         wb->end = -1;
878     }
879     sstr = astr;
880 
881     // Skip to the end of verilog names bounded by '\' and ' '
882     if (*sstr == '\\')
883 	while (*sstr && *sstr != ' ') sstr++;
884 
885     brackstart = strchr(sstr, '[');
886     if (brackstart != NULL) {
887 	brackend = strchr(sstr, ']');
888 	if (brackend == NULL) {
889 	    fprintf(stdout, "Badly formed array notation \"%s\" (line %d)\n", astr,
890 			vlinenum);
891 	    return 1;
892 	}
893 	*brackend = '\0';
894 	colonptr = strchr(sstr, ':');
895 	if (colonptr) *colonptr = '\0';
896 	result = sscanf(brackstart + 1, "%d", &start);
897 	if (colonptr) *colonptr = ':';
898 	if (result != 1) {
899 	    fprintf(stdout, "Badly formed array notation \"%s\" (line %d)\n", astr,
900 			vlinenum);
901 	    *brackend = ']';
902 	    return 1;
903 	}
904 	if (colonptr)
905 	    result = sscanf(colonptr + 1, "%d", &end);
906 	else {
907 	    result = 1;
908 	    end = start;        // Single bit
909 	}
910 	*brackend = ']';
911 	if (result != 1) {
912 	    fprintf(stdout, "Badly formed array notation \"%s\" (line %d)\n", astr,
913 			vlinenum);
914 	    return 1;
915 	}
916 	wb->start = start;
917 	wb->end = end;
918     }
919     else if (nets) {
920 	struct netrec *hbus;
921 	hbus = (struct netrec *)BusHashLookup(astr, nets);
922 	if (hbus != NULL) {
923 	    wb->start = hbus->start;
924 	    wb->end = hbus->end;
925 	}
926 	else
927 	    return -1;
928     }
929     return 0;
930 }
931 
932 /*------------------------------------------------------*/
933 /* Add net to cell database				*/
934 /*------------------------------------------------------*/
935 
Net(struct cellrec * cell,char * netname)936 struct netrec *Net(struct cellrec *cell, char *netname)
937 {
938     struct netrec *newnet;
939 
940     newnet = NewNet();
941     newnet->start = -1;
942     newnet->end = -1;
943 
944     /* Install net in net hash */
945     BusHashPtrInstall(netname, newnet, &cell->nets);
946 
947     return newnet;
948 }
949 
950 /*------------------------------------------------------*/
951 /* Add port to instance record				*/
952 /*------------------------------------------------------*/
953 
InstPort(struct instance * inst,char * portname,char * netname)954 struct portrec *InstPort(struct instance *inst, char *portname, char *netname)
955 {
956     struct portrec *portsrch, *newport;
957 
958     newport = (struct portrec *)malloc(sizeof(struct portrec));
959     newport->name = strdup(portname);
960     newport->direction = PORT_NONE;
961     if (netname)
962 	newport->net = strdup(netname);
963     else
964 	newport->net = NULL;
965     newport->next = NULL;
966 
967     /* Go to end of the port list */
968     if (inst->portlist == NULL) {
969 	inst->portlist = newport;
970     }
971     else {
972 	for (portsrch = inst->portlist; portsrch->next; portsrch = portsrch->next);
973  	portsrch->next = newport;
974     }
975     return newport;
976 }
977 
978 /*------------------------------------------------------*/
979 /* Add port to cell database				*/
980 /*------------------------------------------------------*/
981 
Port(struct cellrec * cell,char * portname,struct netrec * net,int port_type)982 void Port(struct cellrec *cell, char *portname, struct netrec *net, int port_type)
983 {
984     struct portrec *portsrch, *newport;
985     struct netrec *newnet;
986 
987     newport = (struct portrec *)malloc(sizeof(struct portrec));
988     if (portname)
989 	newport->name = strdup(portname);
990     else
991 	newport->name = NULL;
992     newport->direction = port_type;
993     newport->net = NULL;
994     newport->next = NULL;
995 
996     /* Go to end of the port list */
997     if (cell->portlist == NULL) {
998 	cell->portlist = newport;
999     }
1000     else {
1001 	for (portsrch = cell->portlist; portsrch->next; portsrch = portsrch->next);
1002  	portsrch->next = newport;
1003     }
1004 
1005     /* Register the port name as a net in the cell */
1006     if (portname)
1007     {
1008 	newnet = Net(cell, portname);
1009 	if (net) {
1010 	    newnet->start = net->start;
1011 	    newnet->end = net->end;
1012 	}
1013     }
1014 }
1015 
1016 /*------------------------------------------------------*/
1017 /* Create a new cell					*/
1018 /*------------------------------------------------------*/
1019 
Cell(char * cellname)1020 struct cellrec *Cell(char *cellname)
1021 {
1022     struct cellrec *new_cell;
1023 
1024     new_cell = (struct cellrec *)malloc(sizeof(struct cellrec));
1025     new_cell->name = strdup(cellname);
1026     new_cell->portlist = NULL;
1027     new_cell->instlist = NULL;
1028     new_cell->lastinst = NULL;
1029 
1030     InitializeHashTable(&new_cell->nets, LARGEHASHSIZE);
1031     InitializeHashTable(&new_cell->propdict, TINYHASHSIZE);
1032 
1033     return new_cell;
1034 }
1035 
1036 /*------------------------------------------------------*/
1037 /* Add instance to cell database			*/
1038 /*------------------------------------------------------*/
1039 
Instance(struct cellrec * cell,char * cellname,int prepend)1040 struct instance *Instance(struct cellrec *cell, char *cellname, int prepend)
1041 {
1042     struct instance *newinst, *instsrch;
1043 
1044     /* Create new instance record */
1045     newinst = (struct instance *)malloc(sizeof(struct instance));
1046 
1047     newinst->instname = NULL;
1048     newinst->cellname = strdup(cellname);
1049     newinst->portlist = NULL;
1050     newinst->next = NULL;
1051 
1052     InitializeHashTable(&newinst->propdict, TINYHASHSIZE);
1053 
1054     if (cell->instlist == NULL) {
1055 	cell->instlist = newinst;
1056     }
1057     else {
1058 	if (prepend == TRUE) {
1059 	    newinst->next = cell->instlist;
1060 	    cell->instlist = newinst;
1061 	}
1062 	else {
1063 	    instsrch = (cell->lastinst != NULL) ?
1064 			cell->lastinst : cell->instlist;
1065 
1066 	    /* Go to end of the instance list */
1067 	    for (; instsrch->next; instsrch = instsrch->next);
1068 
1069 	    cell->lastinst = instsrch;
1070  	    instsrch->next = newinst;
1071 	}
1072     }
1073     return newinst;
1074 }
1075 
AppendInstance(struct cellrec * cell,char * cellname)1076 struct instance *AppendInstance(struct cellrec *cell, char *cellname)
1077 {
1078     return Instance(cell, cellname, FALSE);
1079 }
1080 
PrependInstance(struct cellrec * cell,char * cellname)1081 struct instance *PrependInstance(struct cellrec *cell, char *cellname)
1082 {
1083     return Instance(cell, cellname, TRUE);
1084 }
1085 
1086 /*------------------------------------------------------*/
1087 /* Read a verilog structural netlist			*/
1088 /*------------------------------------------------------*/
1089 
ReadVerilogFile(char * fname,struct cellstack ** CellStackPtr,int blackbox)1090 void ReadVerilogFile(char *fname, struct cellstack **CellStackPtr,
1091 			int blackbox)
1092 {
1093     int i;
1094     int warnings = 0, hasports, inlined_decls = 0, localcount = 1;
1095     int port_type = PORT_NONE;
1096     char in_module, in_param;
1097     char *eqptr;
1098     char pkey[256];
1099 
1100     struct cellrec *top = NULL;
1101 
1102     in_module = (char)0;
1103     in_param = (char)0;
1104 
1105     while (!EndParseFile()) {
1106 
1107 	SkipTokComments(VLOG_DELIMITERS); /* get the next token */
1108 
1109 	/* Diagnostic */
1110 	/* if (nexttok) fprintf(stdout, "Token is \"%s\"\n", nexttok); */
1111 
1112 	if ((EndParseFile()) && (nexttok == NULL)) break;
1113 	else if (nexttok == NULL)
1114 	    break;
1115 
1116 	/* Ignore end-of-statement markers */
1117 	else if (!strcmp(nexttok, ";"))
1118 	    continue;
1119 
1120 	/* Ignore primitive definitions */
1121 	else if (!strcmp(nexttok, "primitive")) {
1122 	    while (1) {
1123 		SkipNewLine(VLOG_DELIMITERS);
1124 		SkipTokComments(VLOG_DELIMITERS);
1125 		if (EndParseFile()) break;
1126 		if (!strcmp(nexttok, "endprimitive")) {
1127 		    in_module = 0;
1128 		    break;
1129 		}
1130 	    }
1131 	}
1132 
1133 	else if (!strcmp(nexttok, "module")) {
1134 	    struct netrec wb;
1135 
1136 	    SkipTokNoNewline(VLOG_DELIMITERS);
1137 	    if (nexttok == NULL) {
1138 		fprintf(stderr, "Badly formed \"module\" line (line %d)\n", vlinenum);
1139 		goto skip_endmodule;
1140 	    }
1141 
1142 	    if (in_module == (char)1) {
1143 		fprintf(stderr, "Missing \"endmodule\" statement on "
1144 				"subcircuit (line %d).\n", vlinenum);
1145 		InputParseError(stderr);
1146 	    }
1147 	    in_module = (char)1;
1148 	    hasports = (char)0;
1149 	    inlined_decls = (char)0;
1150 
1151 	    /* If there is an existing module, then push it */
1152 	    if (top != NULL) PushStack(top, CellStackPtr);
1153 
1154 	    /* Create new cell */
1155 	    top = Cell(nexttok);
1156 
1157 	    /* Need to support both types of I/O lists:  Those	*/
1158 	    /* that declare names only in the module list and	*/
1159 	    /* follow with input/output and vector size		*/
1160 	    /* declarations as individual statements in the	*/
1161 	    /* module definition, and those which declare	*/
1162 	    /* everything inside the pin list.			*/
1163 
1164             SkipTokComments(VLOG_DELIMITERS);
1165 
1166 	    // Check for parameters within #( ... )
1167 
1168 	    if (!strcmp(nexttok, "#(")) {
1169 		SkipTokComments(VLOG_DELIMITERS);
1170 		in_param = (char)1;
1171 	    }
1172 	    else if (!strcmp(nexttok, "(")) {
1173 		SkipTokComments(VLOG_DELIMITERS);
1174 	    }
1175 
1176 	    wb.start = wb.end = -1;
1177             while ((nexttok != NULL) && strcmp(nexttok, ";")) {
1178 		if (in_param) {
1179 		    if (!strcmp(nexttok, ")")) {
1180 			in_param = (char)0;
1181 			SkipTokComments(VLOG_DELIMITERS);
1182 			if (strcmp(nexttok, "(")) {
1183 			    fprintf(stderr, "Badly formed module block parameter"
1184 						" list (line %d).\n", vlinenum);
1185 			    goto skip_endmodule;
1186 			}
1187 		    }
1188 		    else if (!strcmp(nexttok, "=")) {
1189 
1190 			// The parameter value is the next token.
1191 			SkipTokComments(VLOG_DELIMITERS); /* get the next token */
1192 			HashPtrInstall(pkey, strdup(nexttok), &top->propdict);
1193 		    }
1194 		    else {
1195 			/* Assume this is a keyword and save it */
1196 			strcpy(pkey, nexttok);
1197 		    }
1198 		}
1199 		else if (strcmp(nexttok, ",")) {
1200 		    if (!strcmp(nexttok, ")")) break;
1201 		    // Ignore input, output, and inout keywords, and handle buses.
1202 
1203 		    if (inlined_decls == (char)0) {
1204 			if (!strcmp(nexttok, "input") || !strcmp(nexttok, "output")
1205 				|| !strcmp(nexttok, "inout"))
1206 			    inlined_decls = (char)1;
1207 		    }
1208 
1209 		    if (inlined_decls == (char)1) {
1210 			if (!strcmp(nexttok, "input"))
1211 			    port_type = PORT_INPUT;
1212 			else if (!strcmp(nexttok, "output"))
1213 			    port_type = PORT_OUTPUT;
1214 			else if (!strcmp(nexttok, "inout"))
1215 			    port_type = PORT_INOUT;
1216 			else if (strcmp(nexttok, "real") && strcmp(nexttok, "logic")
1217 					&& strcmp(nexttok, "wire")
1218 					&& strcmp(nexttok, "integer")) {
1219 			    if (!strcmp(nexttok, "[")) {
1220 				if (GetBusTok(&wb, &top->nets) != 0) {
1221 				    // Didn't parse as a bus, so wing it
1222 				    Port(top, nexttok, NULL, port_type);
1223 				}
1224 				else
1225 				    Port(top, nexttok, &wb, port_type);
1226 			    }
1227 			    else
1228 				Port(top, nexttok, NULL, port_type);
1229 
1230 			    hasports = 1;
1231 			}
1232 		    }
1233 		}
1234 		SkipTokComments(VLOG_DELIMITERS);
1235 		if (nexttok == NULL) break;
1236 	    }
1237 	    if (inlined_decls == 1) {
1238 		if (hasports == 0)
1239 		    // If the cell defines no ports, then create a proxy
1240 		    Port(top, (char *)NULL, NULL, PORT_NONE);
1241 
1242 		/* In the blackbox case, don't read the cell contents */
1243 		if (blackbox) goto skip_endmodule;
1244 	    }
1245 	}
1246 	else if (!strcmp(nexttok, "input") || !strcmp(nexttok, "output")
1247 			|| !strcmp(nexttok, "inout")) {
1248 	    struct netrec wb;
1249 
1250 	    if (!strcmp(nexttok, "input")) port_type = PORT_INPUT;
1251 	    else if (!strcmp(nexttok, "output")) port_type = PORT_OUTPUT;
1252 	    else if (!strcmp(nexttok, "inout")) port_type = PORT_INOUT;
1253 	    else port_type = PORT_NONE;
1254 
1255 	    // Parsing of ports as statements not in the module pin list.
1256 	    wb.start = wb.end = -1;
1257 	    while (1) {
1258 		SkipTokComments(VLOG_DELIMITERS);
1259 		if (EndParseFile()) break;
1260 
1261 		if (!strcmp(nexttok, ";")) {
1262 		    // End of statement
1263 		    break;
1264 		}
1265 		else if (!strcmp(nexttok, "[")) {
1266 		    if (GetBusTok(&wb, &top->nets) != 0) {
1267 			// Didn't parse as a bus, so wing it
1268 			Port(top, nexttok, NULL, port_type);
1269 		    }
1270 		    else
1271 			Port(top, nexttok, &wb, port_type);
1272 		}
1273 		else if (strcmp(nexttok, ",")) {
1274 		    /* Comma-separated list;  use same bus limits */
1275 		    Port(top, nexttok, &wb, port_type);
1276 		}
1277 		hasports = 1;
1278 	    }
1279 	}
1280 	else if (!strcmp(nexttok, "endmodule")) {
1281 
1282 	    if (in_module == (char)0) {
1283 		fprintf(stderr, "\"endmodule\" occurred outside of a "
1284 				"module (line %d)!\n", vlinenum);
1285 	        InputParseError(stderr);
1286 	    }
1287 	    in_module = (char)0;
1288 	    SkipNewLine(VLOG_DELIMITERS);
1289 	}
1290 	else if (!strcmp(nexttok, "`include")) {
1291 	    char *iname, *iptr, *quotptr, *pathend, *userpath = NULL;
1292 
1293 	    SkipTokNoNewline(VLOG_DELIMITERS);
1294 	    if (nexttok == NULL) continue;	/* Ignore if no filename */
1295 
1296 	    // Any file included in another Verilog file needs to be
1297 	    // interpreted relative to the path of the parent Verilog file,
1298 	    // unless it's an absolute pathname.
1299 
1300 	    pathend = strrchr(fname, '/');
1301 	    iptr = nexttok;
1302 	    while (*iptr == '\'' || *iptr == '\"') iptr++;
1303 	    if ((pathend != NULL) && (*iptr != '/') && (*iptr != '~')) {
1304 		*pathend = '\0';
1305 		iname = (char *)malloc(strlen(fname) + strlen(iptr) + 2);
1306 		sprintf(iname, "%s/%s", fname, iptr);
1307 		*pathend = '/';
1308 	    }
1309 	    else if ((*iptr == '~') && (*(iptr + 1) == '/')) {
1310 		/* For ~/<path>, substitute tilde from $HOME */
1311 		userpath = getenv("HOME");
1312 		iname = (char *)malloc(strlen(userpath) + strlen(iptr));
1313 		sprintf(iname, "%s%s", userpath, iptr + 1);
1314 	    }
1315 	    else if (*iptr == '~') {
1316 		/* For ~<user>/<path>, substitute tilde from getpwnam() */
1317 		struct passwd *passwd;
1318 		char *pathstart;
1319 		pathstart = strchr(iptr, '/');
1320 		if (pathstart) *pathstart = '\0';
1321 		passwd = getpwnam(iptr + 1);
1322 		if (passwd != NULL) {
1323 		    userpath = passwd->pw_dir;
1324 		    if (pathstart) {
1325 			*pathstart = '/';
1326 			iname = (char *)malloc(strlen(userpath) + strlen(pathstart) + 1);
1327 			sprintf(iname, "%s%s", userpath, pathstart);
1328 		    }
1329 		    else {
1330 			/* Almost certainly an error, but make the substitution anyway */
1331 			iname = strdup(userpath);
1332 		    }
1333 		}
1334 		else {
1335 		    /* Probably an error, but copy the filename verbatim */
1336 		    iname = strdup(iptr);
1337 		}
1338 	    }
1339 	    else
1340 		iname = strdup(iptr);
1341 
1342 	    // Eliminate any single or double quotes around the filename
1343 	    iptr = iname;
1344 	    quotptr = iptr;
1345 	    while (*quotptr != '\'' && *quotptr != '\"' &&
1346 			*quotptr != '\0' && *quotptr != '\n') quotptr++;
1347 	    if (*quotptr == '\'' || *quotptr == '\"') *quotptr = '\0';
1348 
1349 	    IncludeVerilog(iptr, CellStackPtr, blackbox);
1350 	    free(iname);
1351 	    SkipNewLine(VLOG_DELIMITERS);
1352 	}
1353 	else if (!strcmp(nexttok, "`define")) {
1354 	    char *key;
1355 
1356 	    /* Parse for definitions used in expressions.  Save	*/
1357 	    /* definitions in the "verilogdefs" hash table.	*/
1358 
1359 	    SkipTokNoNewline(VLOG_DELIMITERS);
1360 	    if ((nexttok == NULL) || (nexttok[0] == '\0')) break;
1361 
1362 	    key = strdup(nexttok);
1363 
1364 	    SkipTokNoNewline(VLOG_DELIMITERS);
1365 	    if ((nexttok == NULL) || (nexttok[0] == '\0'))
1366 		/* Let "`define X" be equivalent to "`define X 1". */
1367 		HashPtrInstall(key, strdup("1"), &verilogdefs);
1368 	    else
1369 		HashPtrInstall(key, strdup(nexttok), &verilogdefs);
1370 	}
1371 	else if (!strcmp(nexttok, "parameter") || !strcmp(nexttok, "localparam")) {
1372 	    char *paramkey = NULL;
1373 	    char *paramval = NULL;
1374 
1375 	    // Pick up key = value pairs and store in current cell.  Look only
1376 	    // at the keyword before "=".  Then set the definition as everything
1377 	    // remaining in the line, excluding comments, until the end-of-statement
1378 
1379 	    while (nexttok != NULL)
1380 	    {
1381 		/* Parse for parameters used in expressions.  Save	*/
1382 		/* parameters in the "verilogparams" hash table.	*/
1383 
1384 		SkipTok(VLOG_DELIMITERS);
1385 		if ((nexttok == NULL) || (nexttok[0] == '\0')) break;
1386 		if (!strcmp(nexttok, "=")) {
1387 		    /* Pick up remainder of statement */
1388 		    while (nexttok != NULL) {
1389 			SkipTokNoNewline("X///**/X;,");
1390 			if (nexttok == NULL) break;
1391 			if (!strcmp(nexttok, ";") || !strcmp(nexttok, ",")) break;
1392 			if (paramval == NULL) paramval = strdup(nexttok);
1393 			else {
1394 			    char *paramlast;
1395 			    /* Append nexttok to paramval */
1396 			    paramlast = paramval;
1397 			    paramval = (char *)malloc(strlen(paramlast) +
1398 					strlen(nexttok) + 2);
1399 			    sprintf(paramval, "%s %s", paramlast, nexttok);
1400 			    free(paramlast);
1401 			}
1402 		    }
1403 		    HashPtrInstall(paramkey, paramval, &verilogparams);
1404 		    free(paramval);
1405 		    paramval = NULL;
1406 		    if ((nexttok == NULL) || !strcmp(nexttok, ";")) break;
1407 		}
1408 		else {
1409 		    if (paramkey != NULL) free(paramkey);
1410 		    paramkey = strdup(nexttok);
1411 		}
1412 	    }
1413 	    if (paramval != NULL) free(paramval);
1414 	    if (paramkey != NULL) free(paramkey);
1415 	}
1416 	else if (!strcmp(nexttok, "real") || !strcmp(nexttok, "integer")) {
1417 	    fprintf(stdout, "Ignoring '%s' in module '%s' (line %d)\n",
1418 		    nexttok, top->name, vlinenum);
1419 	    while (strcmp(nexttok, ";")) SkipTok("X///**/X,;");
1420 	    continue;
1421 	}
1422 	else if (!strcmp(nexttok, "wire") ||
1423 		 !strcmp(nexttok, "assign")) {	/* wire = node */
1424 	    struct netrec wb, *nb = NULL;
1425 	    char *eptr, *wirename;
1426 	    char is_assignment = FALSE;
1427 	    char is_lhs_bundle = FALSE, is_rhs_bundle = FALSE;
1428 	    char is_wire = (strcmp(nexttok, "wire")) ? FALSE : TRUE;
1429 
1430 	    // Several allowed uses of "assign":
1431 	    // "assign a = b" joins two nets.
1432 	    // "assign a = {b, c, ...}" creates a signal bundle from components.
1433 	    // "assign {a, b ...} = {c, d, ...}" creates a bundle from another bundle.
1434 	    // "assign" using any boolean arithmetic is not structural verilog.
1435 
1436 	    SkipTokNoNewline(VLOG_DELIMITERS);
1437 	    if (!strcmp(nexttok, "real"))
1438 		SkipTokNoNewline(VLOG_DELIMITERS);
1439 	    else if (!strcmp(nexttok, "logic"))
1440 		SkipTokNoNewline(VLOG_DELIMITERS);
1441 
1442 	    while (nexttok != NULL) {
1443 		if (!strcmp(nexttok, "=")) {
1444 		    is_assignment = TRUE;
1445 		}
1446 		else if (!strcmp(nexttok, "{")) {
1447 		    /* To be done:  allow nested bundles */
1448 		    if (is_assignment == FALSE) is_lhs_bundle = TRUE;
1449 		    else is_rhs_bundle = TRUE;
1450 		}
1451 		else if (!strcmp(nexttok, "}")) {
1452 		    if (is_assignment == FALSE) is_lhs_bundle = FALSE;
1453 		    else is_rhs_bundle = FALSE;
1454 		}
1455 		else if (!strcmp(nexttok, ",")) {
1456 		    /* Do nothing;  moving to the next wire or bundle component */
1457 		}
1458 		else if (GetBusTok(&wb, &top->nets) == 0) {
1459 		    if (is_wire) {
1460 			/* Handle bus notation (wires only) */
1461 			if ((nb = BusHashLookup(nexttok, &top->nets)) == NULL)
1462 			    nb = Net(top, nexttok);
1463 			if (nb->start == -1) {
1464 			    nb->start = wb.start;
1465 			    nb->end = wb.end;
1466 			}
1467 			else {
1468 			    if (nb->start < wb.start) nb->start = wb.start;
1469 			    if (nb->end > wb.end) nb->end = wb.end;
1470 			}
1471 		    }
1472 		    else {
1473 			/* "assign" to a bus subnet.  This will be ignored  */
1474 			/* until this tool handles bus joining.  If the	    */
1475 			/* assignment is made on an undeclared wire, then   */
1476 			/* adjust the wire bounds.			    */
1477 			if (nb && (nb->start == -1)) {
1478 			    nb->start = wb.start;
1479 			    nb->end = wb.end;
1480 			}
1481 		    }
1482 		}
1483 		else {
1484 		    if (is_assignment) {
1485 			char *qptr;
1486 			int idum;
1487 
1488 			if (BusHashLookup(nexttok, &top->nets) != NULL) {
1489 			    /* Join nets */
1490 			    /* (WIP) */
1491 			}
1492 			else if ((qptr = strchr(nexttok, '\'')) != NULL) {
1493 			    *qptr = '\0';
1494 			    if (sscanf(nexttok, "%d", &idum) == 1) {
1495 				if ((strchr(qptr + 1, 'x') == NULL) &&
1496 					(strchr(qptr + 1, 'X') == NULL) &&
1497 					(strchr(qptr + 1, 'z') == NULL) &&
1498 					(strchr(qptr + 1, 'Z') == NULL)) {
1499 				    // Power/Ground denoted by, e.g., "vdd = 1'b1".
1500 				    // Only need to record the net, no further action
1501 				    // needed.
1502 				}
1503 				else {
1504 				    fprintf(stdout, "Assignment is not a net "
1505 					    "(line %d).\n", vlinenum);
1506 				    fprintf(stdout, "Module '%s' is not structural "
1507 					    "verilog,  making black-box.\n", top->name);
1508 				    goto skip_endmodule;
1509 				}
1510 			    }
1511 			    *qptr = '\'';
1512 			}
1513 			else {
1514 			    fprintf(stdout, "Assignment is not a net (line %d).\n",
1515 					vlinenum);
1516 			    fprintf(stdout, "Module '%s' is not structural verilog,"
1517 					" making black-box.\n", top->name);
1518 			    goto skip_endmodule;
1519 			}
1520 			is_assignment = FALSE;
1521 		    }
1522 		    else if (BusHashLookup(nexttok, &top->nets) == NULL)
1523 			Net(top, nexttok);
1524 		}
1525 		do {
1526 		    SkipTokNoNewline(VLOG_DELIMITERS);
1527 		} while (nexttok && !strcmp(nexttok, ";"));
1528 	    }
1529 	}
1530 	else if (!strcmp(nexttok, "endmodule")) {
1531 	    // No action---new module is started with next 'module' statement,
1532 	    // if any.
1533 	    SkipNewLine(VLOG_DELIMITERS);
1534 	}
1535 	else if (nexttok[0] == '`') {
1536 	    // Ignore any other directive starting with a backtick
1537 	    SkipNewLine(VLOG_DELIMITERS);
1538 	}
1539 	else if (!strcmp(nexttok, "reg") || !strcmp(nexttok, "always") ||
1540 		!strcmp(nexttok, "specify") || !strcmp(nexttok, "initial")) {
1541 	    fprintf(stdout, "Behavioral keyword '%s' found in source.\n", nexttok);
1542 	    fprintf(stdout, "Module '%s' is not structural verilog, making "
1543 			"black-box.\n", top->name);
1544 	    goto skip_endmodule;
1545 	}
1546 	else {	/* module instances */
1547 	    char ignore;
1548 	    int itype, arraymax, arraymin;
1549 	    struct instance *thisinst;
1550 
1551 	    thisinst = AppendInstance(top, nexttok);
1552 
1553 	    SkipTokComments(VLOG_DELIMITERS);
1554 
1555 nextinst:
1556 	    ignore = FALSE;
1557 
1558 	    // Next token must be '#(' (parameters) or an instance name
1559 
1560 	    if (!strcmp(nexttok, "#(")) {
1561 
1562 		// Read the parameter list
1563 		SkipTokComments(VLOG_DELIMITERS);
1564 
1565 		while (nexttok != NULL) {
1566 		    char *paramname;
1567 
1568 		    if (!strcmp(nexttok, ")")) {
1569 			SkipTokComments(VLOG_DELIMITERS);
1570 			break;
1571 		    }
1572 		    else if (!strcmp(nexttok, ",")) {
1573 			SkipTokComments(VLOG_DELIMITERS);
1574 			continue;
1575 		    }
1576 
1577 		    // We need to look for parameters of the type ".name(value)"
1578 
1579 		    else if (nexttok[0] == '.') {
1580 			paramname = strdup(nexttok + 1);
1581 			SkipTokComments(VLOG_DELIMITERS);
1582 			if (strcmp(nexttok, "(")) {
1583 			    fprintf(stdout, "Error: Expecting parameter value, "
1584 					"got %s (line %d).\n", nexttok, vlinenum);
1585 			}
1586 			SkipTokComments(VLOG_DELIMITERS);
1587 			if (!strcmp(nexttok, ")")) {
1588 			    fprintf(stdout, "Error: Parameter with no value found"
1589 					" (line %d).\n", vlinenum);
1590 			}
1591 			else {
1592 			    HashPtrInstall(paramname, strdup(nexttok),
1593 					&thisinst->propdict);
1594 			    SkipTokComments(VLOG_DELIMITERS);
1595 			    if (strcmp(nexttok, ")")) {
1596 				fprintf(stdout, "Error: Expecting end of parameter "
1597 					"value, got %s (line %d).\n", nexttok,
1598 					vlinenum);
1599 			    }
1600 			}
1601 			free(paramname);
1602 		    }
1603 		    SkipTokComments(VLOG_DELIMITERS);
1604 		}
1605 		if (!nexttok) {
1606 		    fprintf(stdout, "Error: Still reading module, but got "
1607 				"end-of-file.\n");
1608 		    goto skip_endmodule;
1609 		}
1610 	    }
1611 
1612 	    thisinst->instname = strdup(nexttok);
1613 
1614 	    /* fprintf(stdout, "Diagnostic:  new instance is %s\n",	*/
1615 	    /*			thisinst->instname);			*/
1616 	    SkipTokComments(VLOG_DELIMITERS);
1617 
1618 	    thisinst->arraystart = thisinst->arrayend = -1;
1619 	    if (!strcmp(nexttok, "[")) {
1620 		// Handle instance array notation.
1621 		struct netrec wb;
1622 		if (GetBusTok(&wb, NULL) == 0) {
1623 		    thisinst->arraystart = wb.start;
1624 		    thisinst->arrayend = wb.end;
1625 		}
1626 	    }
1627 
1628 	    if (!strcmp(nexttok, "(")) {
1629 		char savetok = (char)0;
1630 		struct portrec *new_port;
1631 		struct netrec *nb, wb;
1632 		char in_line = FALSE, *in_line_net = NULL;
1633 		char *ncomp, *nptr;
1634 
1635 		// Read the pin list
1636 		while (nexttok != NULL) {
1637 		    SkipTokComments(VLOG_DELIMITERS);
1638 		    // NOTE: Deal with `ifdef et al. properly.  Ignoring for now.
1639 		    while (nexttok[0] == '`') {
1640 			SkipNewLine(VLOG_DELIMITERS);
1641 			SkipTokComments(VLOG_DELIMITERS);
1642 		    }
1643 		    if (!strcmp(nexttok, ")")) break;
1644 		    else if (!strcmp(nexttok, ",")) continue;
1645 
1646 		    // We need to look for pins of the type ".name(value)"
1647 
1648 		    if (nexttok[0] != '.') {
1649 			fprintf(stdout, "Ignoring subcircuit with no pin names "
1650 				"at \"%s\" (line %d)\n",
1651 				nexttok, vlinenum);
1652 			while (nexttok != NULL) {
1653 			    SkipTokComments(VLOG_DELIMITERS);
1654 			    if (match(nexttok, ";")) break;
1655 			}
1656 			ignore = TRUE;
1657 			break;
1658 		    }
1659 		    else {
1660 			new_port = InstPort(thisinst, strdup(nexttok + 1), NULL);
1661 			SkipTokComments(VLOG_DELIMITERS);
1662 			if (strcmp(nexttok, "(")) {
1663 			    fprintf(stdout, "Badly formed subcircuit pin line "
1664 					"at \"%s\" (line %d)\n", nexttok, vlinenum);
1665 			    SkipNewLine(VLOG_DELIMITERS);
1666 			}
1667 			SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
1668 			if (!strcmp(nexttok, ")")) {
1669 			    char localnet[100];
1670 			    // Empty parens, so create a new local node
1671 			    savetok = (char)1;
1672 			    sprintf(localnet, "_noconnect_%d_", localcount++);
1673 			    new_port->net = strdup(localnet);
1674 			}
1675 			else {
1676 
1677 			    if (!strcmp(nexttok, "{")) {
1678 				char *in_line_net = (char *)malloc(1);
1679 				*in_line_net = '\0';
1680 				/* In-line array---Read to "}" */
1681 				while (nexttok) {
1682 				    in_line_net = (char *)realloc(in_line_net,
1683 						strlen(in_line_net) +
1684 						strlen(nexttok) + 1);
1685 				    strcat(in_line_net, nexttok);
1686 				    if (!strcmp(nexttok, "}")) break;
1687 				    SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
1688 				}
1689 				if (!nexttok) {
1690 				    fprintf(stderr, "Unterminated net in pin %s "
1691 						"(line %d)\n", in_line_net,
1692 						vlinenum);
1693 				}
1694 				new_port->net = in_line_net;
1695 			    }
1696 			    else
1697 				new_port->net = strdup(nexttok);
1698 
1699 			    /* Read array information along with name;	*/
1700 			    /* will be parsed later 			*/
1701 
1702 			    SkipTokComments(VLOG_DELIMITERS);
1703 			    if (!strcmp(nexttok, "[")) {
1704 				/* Check for space between name and array identifier */
1705 				SkipTokComments(VLOG_PIN_NAME_DELIMITERS);
1706 				if (strcmp(nexttok, ")")) {
1707 				    char *expnet;
1708 				    expnet = (char *)malloc(strlen(new_port->net)
1709 						+ strlen(nexttok) + 3);
1710 				    sprintf(expnet, "%s [%s", new_port->net, nexttok);
1711 				    free(new_port->net);
1712 				    new_port->net = expnet;
1713 				}
1714 				SkipTokComments(VLOG_DELIMITERS);
1715 			    }
1716 			    if (strcmp(nexttok, ")")) {
1717 				fprintf(stdout, "Badly formed subcircuit pin line "
1718 					"at \"%s\" (line %d)\n", nexttok, vlinenum);
1719 				SkipNewLine(VLOG_DELIMITERS);
1720 			    }
1721 			}
1722 
1723 			/* Register wire if it has not been already, and if it	*/
1724 			/* has been registered, check if this wire increases	*/
1725 			/* the net bounds.  If the net name is an in-line	*/
1726 			/* vector, then process each component separately.	*/
1727 
1728 			ncomp = new_port->net;
1729 			while (isdigit(*ncomp)) ncomp++;
1730 			if (*ncomp == '{') ncomp++;
1731 			while (isspace(*ncomp)) ncomp++;
1732 			while (*ncomp != '\0') {
1733 			    int is_esc = FALSE;
1734 			    char saveptr;
1735 
1736 			    /* NOTE:  This follows same rules in strdtok() */
1737 			    nptr = ncomp;
1738 			    if (*nptr == '\\') is_esc = TRUE;
1739 			    while (*nptr != ',' && *nptr != '}' && *nptr != '\0') {
1740 				if (*nptr == ' ') {
1741 				    if (is_esc == TRUE)
1742 					is_esc = FALSE;
1743 				    else
1744 					break;
1745 				}
1746 				nptr++;
1747 			    }
1748 			    saveptr = *nptr;
1749 			    *nptr = '\0';
1750 
1751 			    /* Parse ncomp as a net or bus */
1752 			    if ((nb = BusHashLookup(ncomp, &top->nets)) == NULL)
1753 				nb = Net(top, ncomp);
1754 
1755 			    GetBus(ncomp, &wb, &top->nets);
1756 			    if (nb->start == -1) {
1757 				nb->start = wb.start;
1758 				nb->end = wb.end;
1759 			    }
1760 			    else {
1761 				if (nb->start < wb.start) nb->start = wb.start;
1762 				if (nb->end > wb.end) nb->end = wb.end;
1763 			    }
1764 
1765 			    *nptr = saveptr;
1766 			    if (*new_port->net != '{')
1767 				break;
1768 
1769 			    ncomp = nptr + 1;
1770 			    /* Skip over any whitespace at the end of a name */
1771 			    while ((*ncomp != '\0') && (*ncomp == ' '))
1772 				ncomp++;
1773 			    while ((*ncomp != '\0') && (*nptr == ',' || *nptr == '}'))
1774 				ncomp++;
1775 			}
1776 		    }
1777 		}
1778 	    }
1779 	    else {
1780 		fprintf(stdout, "Expected to find instance pin block but got "
1781 				"\"%s\" (line %d)\n", nexttok, vlinenum);
1782 	    }
1783 	    if (ignore == TRUE) continue;	/* moving along. . . */
1784 
1785 	    /* Verilog allows multiple instances of a single cell type to be	*/
1786 	    /* chained together in a comma-separated list.			*/
1787 
1788 	    SkipTokComments(VLOG_DELIMITERS);
1789 	    if (!strcmp(nexttok, ",")) {
1790 		goto nextinst;
1791 	    }
1792 
1793 	    /* Otherwise, instance must end with a semicolon */
1794 
1795 	    else if (strcmp(nexttok, ";")) {
1796 		fprintf(stdout, "Expected to find end of instance but got "
1797 				"\"%s\" (line %d)\n", nexttok, vlinenum);
1798 	    }
1799 	}
1800 	continue;
1801 
1802 skip_endmodule:
1803 	/* There was an error, so skip to the end of the	*/
1804 	/* subcircuit definition				*/
1805 
1806 	while (1) {
1807 	    SkipNewLine(VLOG_DELIMITERS);
1808 	    SkipTokComments(VLOG_DELIMITERS);
1809 	    if (EndParseFile()) break;
1810 	    if (!strcmp(nexttok, "endmodule")) {
1811 		in_module = 0;
1812 		break;
1813 	    }
1814 	}
1815 	continue;
1816 
1817 baddevice:
1818 	fprintf(stderr, "Badly formed line in input (line %d).\n", vlinenum);
1819     }
1820 
1821     /* Watch for bad ending syntax */
1822 
1823     if (in_module == (char)1) {
1824 	fprintf(stderr, "Missing \"endmodule\" statement in module.\n");
1825 	InputParseError(stderr);
1826     }
1827 
1828     /* Make sure topmost cell is on stack before returning */
1829     PushStack(top, CellStackPtr);
1830 
1831     if (warnings)
1832 	fprintf(stderr, "File %s read with %d warning%s.\n", fname,
1833 		warnings, (warnings == 1) ? "" : "s");
1834 }
1835 
1836 /*----------------------------------------------*/
1837 /* Free memory associated with a cell		*/
1838 /*----------------------------------------------*/
1839 
1840 /*----------------------------------------------*/
1841 /* Free memory associated with property hash	*/
1842 /*----------------------------------------------*/
1843 
freeprop(struct hashlist * p)1844 int freeprop(struct hashlist *p)
1845 {
1846     char *propval;
1847 
1848     propval = (char *)(p->ptr);
1849     free(propval);
1850     return 1;
1851 }
1852 
1853 /*----------------------------------------------*/
1854 /* Top-level verilog module file read routine	*/
1855 /*----------------------------------------------*/
1856 
ReadVerilogTop(char * fname,int blackbox)1857 struct cellrec *ReadVerilogTop(char *fname, int blackbox)
1858 {
1859     struct cellstack *CellStackPtr = NULL;
1860     struct cellrec *top;
1861 
1862     if ((OpenParseFile(fname)) < 0) {
1863 	fprintf(stderr, "Error in Verilog file read: No file %s\n", fname);
1864 	return NULL;
1865     }
1866 
1867     if (dictinit == FALSE) {
1868 	/* verilogdefs may be pre-initialized by calling VerilogDefine() */
1869 	InitializeHashTable(&verilogdefs, TINYHASHSIZE);
1870 	dictinit = TRUE;
1871     }
1872     InitializeHashTable(&verilogparams, TINYHASHSIZE);
1873     InitializeHashTable(&verilogvectors, TINYHASHSIZE);
1874 
1875     ReadVerilogFile(fname, &CellStackPtr, blackbox);
1876     CloseParseFile();
1877 
1878     RecurseHashTable(&verilogparams, freeprop);
1879     HashKill(&verilogparams);
1880     RecurseHashTable(&verilogdefs, freeprop);
1881     HashKill(&verilogdefs);
1882 
1883     if (CellStackPtr == NULL) return NULL;
1884 
1885     top = CellStackPtr->cell;
1886     free(CellStackPtr);
1887     return top;
1888 }
1889 
1890 /*--------------------------------------*/
1891 /* Wrappers for ReadVerilogTop()	*/
1892 /*--------------------------------------*/
1893 
ReadVerilog(char * fname)1894 struct cellrec *ReadVerilog(char *fname)
1895 {
1896     return ReadVerilogTop(fname, 0);
1897 }
1898 
1899 /*--------------------------------------*/
1900 /* Verilog file include routine		*/
1901 /*--------------------------------------*/
1902 
IncludeVerilog(char * fname,struct cellstack ** CellStackPtr,int blackbox)1903 void IncludeVerilog(char *fname, struct cellstack **CellStackPtr, int blackbox)
1904 {
1905     int filenum = -1;
1906     char name[256];
1907 
1908     name[0] = '\0';
1909 
1910     /* If fname does not begin with "/", then assume that it is	*/
1911     /* in the same relative path as its parent.			*/
1912 
1913     if (fname[0] != '/') {
1914 	char *ppath;
1915 	if (*CellStackPtr && ((*CellStackPtr)->cell != NULL)) {
1916 	    strcpy(name, (*CellStackPtr)->cell->name);
1917 	    ppath = strrchr(name, '/');
1918 	    if (ppath != NULL)
1919 		strcpy(ppath + 1, fname);
1920 	    else
1921 		strcpy(name, fname);
1922 	    filenum = OpenParseFile(name);
1923 	}
1924     }
1925 
1926     /* If we failed the path relative to the parent, then try 	*/
1927     /* the filename alone (relative to the path where netgen	*/
1928     /* was executed).						*/
1929 
1930     if (filenum < 0) {
1931 	if ((filenum = OpenParseFile(fname)) < 0) {
1932 	    if (filenum < 0) {
1933 		fprintf(stderr,"Error in Verilog file include: No file %s\n",
1934 			    (*name == '\0') ? fname : name);
1935 		return;
1936 	    }
1937 	}
1938     }
1939     ReadVerilogFile(fname, CellStackPtr, blackbox);
1940     CloseParseFile();
1941 }
1942 
1943 /*------------------------------------------------------*/
1944 /* Free the cellrec structure created by ReadVerilog()	*/
1945 /*------------------------------------------------------*/
1946 
FreeVerilog(struct cellrec * topcell)1947 void FreeVerilog(struct cellrec *topcell)
1948 {
1949     struct portrec *port, *dport;
1950     struct instance *inst, *dinst;
1951 
1952     port = topcell->portlist;
1953     while (port) {
1954 	if (port->name) free(port->name);
1955 	if (port->net) free(port->net);
1956 	dport = port->next;
1957 	free(port);
1958 	port = dport;
1959     }
1960     inst = topcell->instlist;
1961     while (inst) {
1962 	if (inst->instname) free(inst->instname);
1963 	if (inst->cellname) free(inst->cellname);
1964 	port = inst->portlist;
1965 	while (port) {
1966 	    if (port->name) free(port->name);
1967 	    if (port->net) free(port->net);
1968 	    dport = port->next;
1969 	    free(port);
1970 	    port = dport;
1971 	}
1972         RecurseHashTable(&inst->propdict, freeprop);
1973         HashKill(&inst->propdict);
1974 	dinst = inst->next;
1975 	free(inst);
1976 	inst = dinst;
1977     }
1978 
1979     /* Delete nets hashtable */
1980     RecurseHashTable(&topcell->nets, freenet);
1981     HashKill(&topcell->nets);
1982 
1983     /* Delete properties hashtable. */
1984     RecurseHashTable(&topcell->propdict, freeprop);
1985     HashKill(&topcell->propdict);
1986 }
1987 
1988 
1989 // readverilog.c
1990