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:
parent
3dc70148d1
commit
ea4083893c
293
base/netfile.c
293
base/netfile.c
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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")) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue