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