A fairly large refactoring of the conditional handling code in the

verilog parser.  The parser should now be able to handle any
conditionals anywhere in the verilog code.  Also a bug was found
in the code that handles "a = b" assignments, and corrected.
This commit is contained in:
Tim Edwards 2019-09-09 11:26:31 -04:00
parent 3dc70148d1
commit ea4083893c
3 changed files with 218 additions and 143 deletions

View File

@ -47,6 +47,18 @@ static FILE *outfile;
static int Graph = 0; static int Graph = 0;
int File; int File;
/*------------------------------------------------------*/
/* Structure for stacking nested `if[n]def in verilog */
/*------------------------------------------------------*/
struct ifstack {
int invert;
struct property *kl;
struct ifstack *next;
};
struct ifstack *condstack = NULL;
extern char *SetExtension(char *buffer, char *path, char *extension) extern char *SetExtension(char *buffer, char *path, char *extension)
/* add 'extension' to 'path' (overwriting previous extension, if any), /* add 'extension' to 'path' (overwriting previous extension, if any),
write it into buffer (if buffer is null, malloc a buffer). write it into buffer (if buffer is null, malloc a buffer).
@ -253,7 +265,6 @@ void TrimQuoted(char *line)
} }
} }
} }
} }
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
@ -267,112 +278,202 @@ void TrimQuoted(char *line)
int GetNextLineNoNewline(char *delimiter) int GetNextLineNoNewline(char *delimiter)
{ {
char *newbuf; char *newbuf;
int testc; int testc;
int nested = 0;
if (feof(infile)) return -1; if (feof(infile)) return -1;
// This is more reliable than feof() ... while (1) { /* May loop indefinitely in an `if[n]def conditional */
testc = getc(infile);
if (testc == -1) return -1;
ungetc(testc, infile);
if (linesize == 0) { // This is more reliable than feof() ...
/* Allocate memory for line */ testc = getc(infile);
linesize = 500; if (testc == -1) return -1;
line = (char *)MALLOC(linesize); ungetc(testc, infile);
linetok = (char *)MALLOC(linesize);
}
fgets(line, linesize, infile);
while (strlen(line) == linesize - 1) {
newbuf = (char *)MALLOC(linesize + 500);
strcpy(newbuf, line);
FREE(line);
line = newbuf;
fgets(line + linesize - 1, 501, infile);
linesize += 500;
FREE(linetok);
linetok = (char *)MALLOC(linesize);
}
/* Check for substitutions (verilog only). Make sure linetok is */ if (linesize == 0) {
/* large enough to hold the entire line after substitutions. */ /* Allocate memory for line */
linesize = 500;
line = (char *)MALLOC(linesize);
linetok = (char *)MALLOC(linesize);
}
fgets(line, linesize, infile);
while (strlen(line) == linesize - 1) {
newbuf = (char *)MALLOC(linesize + 500);
strcpy(newbuf, line);
FREE(line);
line = newbuf;
fgets(line + linesize - 1, 501, infile);
linesize += 500;
FREE(linetok);
linetok = (char *)MALLOC(linesize);
}
if (definitions != NULL) { /* Check for substitutions (verilog only). Make sure linetok is */
char *s, *w, e; /* large enough to hold the entire line after substitutions. */
struct property *kl;
int len, dlen, vlen, addin = 0;
unsigned char found = FALSE;
for (s = line; *s != '\0'; s++) { if (definitions != NULL) {
if (*s == '`') { char *s, *w, e;
w = s + 1; struct property *kl;
while (isalnum(*w)) w++; int len, dlen, vlen, addin = 0;
e = *w; unsigned char found = FALSE;
*w = '\0';
kl = (struct property *)HashLookup(s + 1, definitions);
if (kl != NULL) {
dlen = strlen(s);
if (kl->type == PROP_STRING) {
vlen = strlen(kl->pdefault.string);
}
else vlen = 12; /* Leave room for numeric conversion */
addin += vlen - dlen + 1;
found = TRUE;
}
*w = e;
}
}
if (found) {
len = strlen(line);
if (len + addin > linesize) {
while (len + addin > linesize) linesize += 500;
FREE(linetok);
linetok = (char *)MALLOC(linesize);
}
}
}
/* Make definition substitutions (verilog only) */ for (s = line; *s != '\0'; s++) {
if (*s == '`') {
w = s + 1;
while (isalnum(*w)) w++;
e = *w;
*w = '\0';
kl = (struct property *)HashLookup(s + 1, definitions);
if (kl != NULL) {
dlen = strlen(s);
if (kl->type == PROP_STRING) {
vlen = strlen(kl->pdefault.string);
}
else vlen = 12; /* Leave room for numeric conversion */
addin += vlen - dlen + 1;
found = TRUE;
}
*w = e;
}
}
if (found) {
len = strlen(line);
if (len + addin > linesize) {
while (len + addin > linesize) linesize += 500;
FREE(linetok);
linetok = (char *)MALLOC(linesize);
}
}
}
if (definitions != NULL) { /* Make definition substitutions (verilog only) */
char *s, *t, *w, e;
struct property *kl;
int len, dlen, vlen, addin = 0;
t = linetok; if (definitions != NULL) {
for (s = line; *s != '\0'; s++) { char *s, *t, *w, e;
if (*s == '`') { struct property *kl;
w = s + 1;
while (isalnum(*w)) w++;
e = *w;
*w = '\0';
kl = (struct property *)HashLookup(s + 1, definitions);
if (kl != NULL) {
if (kl->type == PROP_STRING)
strcpy(t, kl->pdefault.string);
else if (kl->type == PROP_INTEGER)
sprintf(t, "%d", kl->pdefault.ival);
else if (kl->type == PROP_DOUBLE)
sprintf(t, "%g", kl->pdefault.dval);
t += strlen(t);
s = w - 1;
}
else *t++ = *s;
*w = e;
}
else *t++ = *s;
}
*t = '\0';
}
else
strcpy(linetok, line);
TrimQuoted(linetok); t = linetok;
linenum++; for (s = line; *s != '\0'; s++) {
if (*s == '`') {
w = s + 1;
while (isalnum(*w)) w++;
e = *w;
*w = '\0';
kl = (struct property *)HashLookup(s + 1, definitions);
if (kl != NULL) {
if (kl->type == PROP_STRING)
strcpy(t, kl->pdefault.string);
else if (kl->type == PROP_INTEGER)
sprintf(t, "%d", kl->pdefault.ival);
else if (kl->type == PROP_DOUBLE)
sprintf(t, "%g", kl->pdefault.dval);
t += strlen(t);
s = w - 1;
}
else *t++ = *s;
*w = e;
}
else *t++ = *s;
}
*t = '\0';
}
else
strcpy(linetok, line);
nexttok = strdtok(linetok, WHITESPACE_DELIMITER, delimiter); TrimQuoted(linetok);
return 0; linenum++;
nexttok = strdtok(linetok, WHITESPACE_DELIMITER, delimiter);
if (nexttok == NULL) return 0;
/* Handle `ifdef, `ifndef, `elsif, `else, and `endif (verilog */
/* only, where indicated by a non-NULL "definitions") */
if (definitions == NULL) return 0;
/* If currently skipping through a section, handle conditionals differently */
if (condstack) {
if (((condstack->invert == 0) && (condstack->kl == NULL))
|| ((condstack->invert == 1) && (condstack->kl != NULL))) {
if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef")) {
nested++;
continue;
}
else if (nested > 0) {
if (match(nexttok, "`endif")) nested--;
continue;
}
else if (nexttok[0] != '`') continue;
}
}
/* Handle conditionals (that is not being skipped over) */
if (match(nexttok, "`endif")) {
if (condstack == NULL) {
fprintf(stderr, "Error: `endif without corresponding `if[n]def\n");
}
else {
struct ifstack *iftop = condstack;
condstack = condstack->next;
FREE(iftop);
}
}
/* Note that `if[n]def may be nested. */
else if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef") ||
match(nexttok, "`elsif") || match(nexttok, "`else")) {
/* Every `ifdef or `ifndef increases condstack by 1 */
if (nexttok[1] == 'i') {
struct ifstack *newif = (struct ifstack *)MALLOC(sizeof(struct ifstack));
newif->next = condstack;
condstack = newif;
}
if (condstack == NULL) {
fprintf(stderr, "Error: %s without `if[n]def\n", nexttok);
break;
}
else {
if (match(nexttok, "`else")) {
/* Invert the sense of the if[n]def scope */
condstack->invert = (condstack->invert == 1) ? 0 : 1;
}
else if (match(nexttok, "`elsif")) {
nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter);
if (nexttok == NULL) {
fprintf(stderr, "Error: `elsif with no conditional.\n");
return 0;
}
/* Keep the same scope but redefine the parameter */
condstack->invert = 0;
condstack->kl = (struct property *)HashLookup(nexttok, definitions);
}
else {
condstack->invert = (nexttok[3] == 'n') ? 1 : 0;
nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter);
if (nexttok == NULL) {
fprintf(stderr, "Error: %s with no conditional.\n", nexttok);
return 0;
}
condstack->kl = (struct property *)HashLookup(nexttok, definitions);
}
}
}
else if (condstack) {
if (((condstack->invert == 0) && (condstack->kl == NULL))
|| ((condstack->invert == 1) && (condstack->kl != NULL)))
continue;
else
break;
}
else
break;
}
return 0;
} }
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/

View File

@ -33,6 +33,7 @@ extern char *nexttok;
extern char *strdtok(char *pstring, char *delim1, char *delim2); extern char *strdtok(char *pstring, char *delim1, char *delim2);
extern void SkipTok(char *delimiter); extern void SkipTok(char *delimiter);
extern void SkipTokNoNewline(char *delimiter); extern void SkipTokNoNewline(char *delimiter);
extern void SkipTokComments(char *delimiter);
extern void SkipNewLine(char *delimiter); extern void SkipNewLine(char *delimiter);
extern void SpiceTokNoNewline(void); /* handles SPICE "+" continuation line */ extern void SpiceTokNoNewline(void); /* handles SPICE "+" continuation line */
extern void SpiceSkipNewLine(void); /* handles SPICE "+" continuation line */ extern void SpiceSkipNewLine(void); /* handles SPICE "+" continuation line */

View File

@ -560,7 +560,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
instname[255] = '\0'; instname[255] = '\0';
in_module = (char)0; in_module = (char)0;
in_param = (char)0; in_param = (char)0;
while (!EndParseFile()) { while (!EndParseFile()) {
SkipTokComments(VLOG_DELIMITERS); /* get the next token */ SkipTokComments(VLOG_DELIMITERS); /* get the next token */
@ -1010,46 +1010,6 @@ skip_endmodule:
} }
} }
/* Process conditions. Note that conditionals may be nested. */
else if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef") ||
match(nexttok, "`elsif") || match(nexttok, "`else")) {
struct property *kl;
int nested = 0;
int invert = (nexttok[3] == 'n') ? 1 : 0;
SkipTokNoNewline(VLOG_DELIMITERS);
/* To be done: Handle boolean arithmetic on conditionals */
kl = (struct property *)HashLookup(nexttok, &verilogdefs);
while (((invert == 0) && (kl == NULL))
|| ((invert == 1) && (kl != NULL))) {
/* Skip to matching `endif, `elsif, or `else */
while (1) {
SkipNewLine(VLOG_DELIMITERS);
SkipTokComments(VLOG_DELIMITERS);
if (EndParseFile()) break;
if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef")) {
nested++;
}
else if (match(nexttok, "`endif") || match(nexttok, "`elsif") ||
match(nexttok, "`else")) {
if (nested == 0)
break;
else
nested--;
}
}
if (match(nexttok, "`elsif")) {
SkipTokComments(VLOG_DELIMITERS);
invert = 0;
kl = (struct property *)HashLookup(nexttok, &verilogdefs);
}
else break;
}
}
else if (match(nexttok, "wire") || match(nexttok, "assign")) { /* wire = node */ else if (match(nexttok, "wire") || match(nexttok, "assign")) { /* wire = node */
struct bus wb, wb2, *nb; struct bus wb, wb2, *nb;
char nodename[128], noderoot[100]; char nodename[128], noderoot[100];
@ -1179,14 +1139,26 @@ skip_endmodule:
} }
} }
else { else {
j = -1;
rhs = LookupObject(nexttok, CurrentCell); rhs = LookupObject(nexttok, CurrentCell);
} }
if ((lhs == NULL) || (rhs == NULL)) { if ((lhs == NULL) || (rhs == NULL)) {
/* Not parsable, probably behavioral verilog? */ if (rhs != NULL) {
Printf("Module '%s' is not structural verilog, " Printf("Improper assignment; left-hand side cannot "
"making black-box.\n", model); "be parsed.\n");
SetClass(CLASS_MODULE); Printf("Right-hand side is \"%s\".\n", rhs->name);
goto skip_endmodule; break;
}
if (lhs != NULL) {
Printf("Improper assignment; right-hand side cannot "
"be parsed.\n");
Printf("Left-hand side is \"%s\".\n", lhs->name);
/* Not parsable, probably behavioral verilog? */
Printf("Module '%s' is not structural verilog, "
"making black-box.\n", model);
SetClass(CLASS_MODULE);
goto skip_endmodule;
}
} }
while (1) { while (1) {
/* Assign bits in turn from bundle in RHS to bits of LHS */ /* Assign bits in turn from bundle in RHS to bits of LHS */
@ -1219,9 +1191,10 @@ skip_endmodule:
// No action---new module is started with next 'module' statement, // No action---new module is started with next 'module' statement,
// if any. // if any.
SkipNewLine(VLOG_DELIMITERS); SkipNewLine(VLOG_DELIMITERS);
in_module = (char)0; /* Should have been done already */
} }
else if (nexttok[0] == '`') { else if (nexttok[0] == '`') {
// Ignore any other directive starting with a backtick // Ignore any other directive starting with a backtick (e.g., `timescale)
SkipNewLine(VLOG_DELIMITERS); SkipNewLine(VLOG_DELIMITERS);
} }
else if (match(nexttok, "reg") || match(nexttok, "always")) { else if (match(nexttok, "reg") || match(nexttok, "always")) {