From da667c3b170daf6a4ed94df8ecf4f8d2c02edf15 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 27 Mar 2020 08:48:48 -0400 Subject: [PATCH 1/5] Corrected handling of wire bundles in the verilog parser. --- VERSION | 2 +- base/verilog.c | 69 +++++++++++++++++++++++++++++++------------------- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/VERSION b/VERSION index 8dcb446..c995b25 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.145 +1.5.146 diff --git a/base/verilog.c b/base/verilog.c index d7b60fe..d620288 100644 --- a/base/verilog.c +++ b/base/verilog.c @@ -1445,25 +1445,25 @@ nextinst: } else { if (!strcmp(nexttok, "{")) { - char *in_line_net = (char *)MALLOC(1); - char *new_in_line_net = NULL; - *in_line_net = '\0'; - /* In-line array---read to "}" */ + char *wire_bundle = (char *)MALLOC(1); + char *new_wire_bundle = NULL; + *wire_bundle = '\0'; + /* Wire bundle---read to "}" */ while (nexttok) { - new_in_line_net = (char *)MALLOC(strlen(in_line_net) + + new_wire_bundle = (char *)MALLOC(strlen(wire_bundle) + strlen(nexttok) + 1); /* Roundabout way to do realloc() becase there is no REALLOC() */ - strcpy(new_in_line_net, in_line_net); - strcat(new_in_line_net, nexttok); - FREE(in_line_net); - in_line_net = new_in_line_net; + strcpy(new_wire_bundle, wire_bundle); + strcat(new_wire_bundle, nexttok); + FREE(wire_bundle); + wire_bundle = new_wire_bundle; if (!strcmp(nexttok, "}")) break; SkipTokComments(VLOG_PIN_CHECK_DELIMITERS); } if (!nexttok) { - Printf("Unterminated net in pin %s\n", in_line_net); + Printf("Unterminated net in pin %s\n", wire_bundle); } - new_port->net = in_line_net; + new_port->net = wire_bundle; } else new_port->net = strsave(nexttok); @@ -1702,16 +1702,33 @@ nextinst: } if (result == 0) { - if (((wb.start - wb.end) != (portstart - portend)) && - ((wb.start - wb.end) != (portend - portstart))) { - if (((wb.start - wb.end) != (arraystart - arrayend)) && - ((wb.start - wb.end) != (arrayend - arraystart))) { - Fprintf(stderr, "Error: Net %s bus width does not match " - "port %s bus width.\n", scan->net, scan->name); - } - // Otherwise, net is bit-sliced across array of instances. + int match = 0; + int wblen, portlen, arraylen; + + arraylen = arraystart - arrayend; + portlen = portstart - portend; + wblen = wb.start - wb.end; + + if (arraylen < 0) arraylen = -arraylen; + if (portlen < 0) portlen = -portlen; + if (wblen < 0) wblen = -wblen; + + arraylen++; + portlen++; + wblen++; + + if ((portlen * arraylen) == wblen) match = 1; + else if (wblen == portlen) match = 1; + else if (wblen == arraylen) match = 1; + else { + Fprintf(stderr, "Warning: Net %s bus width (%d) does not match " + "port %s bus width (%d) or array width (%d).\n", + scan->net, wblen, scan->name, portlen, arraylen); } - else if (wb.start > wb.end) { + + // Net is bit-sliced across array of instances. + + if (wb.start > wb.end) { char *bptr, *cptr, cchar, *netname; unsigned char is_bundle = 0; struct bus wbb; @@ -1739,8 +1756,6 @@ nextinst: else i = -1; - if (is_bundle) *cptr = cchar; /* Restore bundle delimiter */ - while (1) { new_port = (struct portelement *)CALLOC(1, sizeof(struct portelement)); @@ -1764,8 +1779,10 @@ nextinst: if (portstart > portend) j--; else j++; - if (wbb.start > wbb.end) i--; - else i++; + if (i != -1) { + if (wbb.start > wbb.end) i--; + else i++; + } if (is_bundle && ((i == -1) || @@ -1774,6 +1791,7 @@ nextinst: if (bptr) *bptr = '['; netname = cptr + 1; + if (cptr) *cptr = cchar; /* Restore previous bundle delimiter */ cptr = strchr(netname, ','); if (cptr == NULL) cptr = strchr(netname, '}'); if (cptr == NULL) cptr = netname + strlen(netname) - 1; @@ -1786,12 +1804,11 @@ nextinst: *bptr = '\0'; } else i = -1; - - *cptr = cchar; /* Restore delimiter */ } } FREE(scan); scan = last; + if (cptr) *cptr = cchar; /* Restore bundle delimiter */ } } else if (portstart != portend) { From cf9dedb2f7717e8e93c1d1619275e940a99943af Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 27 Mar 2020 11:31:21 -0400 Subject: [PATCH 2/5] Additional corrections; needed to maintain port width in the scan structure because it is used in two different places and would have to run a cost-prohibitive search of the cell's object list. Also, was missing recording a bus input/output signal from an "input" or "output" statement (as opposed to in-line signals in the I/O list). --- base/verilog.c | 54 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/base/verilog.c b/base/verilog.c index d620288..83d1f06 100644 --- a/base/verilog.c +++ b/base/verilog.c @@ -919,7 +919,7 @@ skip_endmodule: } else if (match(nexttok, "input") || match(nexttok, "output") || match(nexttok, "inout")) { - struct bus wb; + struct bus wb, *nb; // Parsing of ports as statements not in the module pin list. wb.start = wb.end = -1; @@ -952,6 +952,11 @@ skip_endmodule: Port(portname); } } + /* Also register this port as a bus */ + nb = NewBus(); + nb->start = wb.start; + nb->end = wb.end; + HashPtrInstall(nexttok, nb, &buses); wb.start = wb.end = -1; } else { @@ -1315,6 +1320,7 @@ skip_endmodule: struct portelement { char *name; // Name of port in subcell char *net; // Name of net connecting to port in the parent + int width; // Width of port, if port is a bus struct portelement *next; }; @@ -1424,6 +1430,7 @@ nextinst: else { new_port = (struct portelement *)CALLOC(1, sizeof(struct portelement)); new_port->name = strsave(nexttok + 1); + new_port->width = -1; SkipTokComments(VLOG_DELIMITERS); if (!match(nexttok, "(")) { Printf("Badly formed subcircuit pin line at \"%s\"\n", nexttok); @@ -1650,7 +1657,12 @@ nextinst: int j, result; struct objlist *bobj; char *bptr; - int minnet, maxnet, testidx; + int minnet, maxnet, testidx, width; + + width = portstart - portend; + if (width < 0) width = -width; + width++; + scan->width = width; result = GetBus(scan->net, &wb); if (result == -1) { @@ -1703,27 +1715,24 @@ nextinst: if (result == 0) { int match = 0; - int wblen, portlen, arraylen; + int wblen, arraylen; arraylen = arraystart - arrayend; - portlen = portstart - portend; wblen = wb.start - wb.end; if (arraylen < 0) arraylen = -arraylen; - if (portlen < 0) portlen = -portlen; if (wblen < 0) wblen = -wblen; arraylen++; - portlen++; wblen++; - if ((portlen * arraylen) == wblen) match = 1; - else if (wblen == portlen) match = 1; + if ((scan->width * arraylen) == wblen) match = 1; + else if (wblen == scan->width) match = 1; else if (wblen == arraylen) match = 1; else { Fprintf(stderr, "Warning: Net %s bus width (%d) does not match " "port %s bus width (%d) or array width (%d).\n", - scan->net, wblen, scan->name, portlen, arraylen); + scan->net, wblen, scan->name, scan->width, arraylen); } // Net is bit-sliced across array of instances. @@ -1766,6 +1775,7 @@ nextinst: else sprintf(vname, "%s[%d]", netname, i); new_port->net = strsave(vname); + new_port->width = scan->width; if (last == NULL) head = new_port; @@ -1838,7 +1848,7 @@ nextinst: obptr = LookupInstance(locinst, CurrentCell); if (obptr != NULL) { do { - struct bus wb; + struct bus wb, wb2; char *obpinname; int obpinidx; @@ -1865,6 +1875,7 @@ nextinst: } if (GetBus(scan->net, &wb) == 0) { + char *bptr2; char *scanroot; scanroot = strsave(scan->net); brackptr = strchr(scanroot, '['); @@ -1899,15 +1910,28 @@ nextinst: else { // Instance must be an array char netname[128]; - int slice; + int slice, portlen; + + /* Get the array size of the port for bit slicing */ + portlen = (scan->width < 0) ? 1 : scan->width; + if (wb.start >= wb.end && arraystart >= arrayend) - slice = wb.start - (arraystart - i); + slice = wb.start - (arraystart - i) * portlen; else if (wb.start < wb.end && arraystart > arrayend) - slice = wb.start + (arraystart - i); + slice = wb.start + (arraystart - i) * portlen; else if (wb.start > wb.end && arraystart < arrayend) - slice = wb.start - (arraystart + i); + slice = wb.start - (arraystart + i) * portlen; else // (wb.start < wb.end && arraystart < arrayend) - slice = wb.start + (arraystart + i); + slice = wb.start + (arraystart + i) * portlen; + + if (wb.start < wb.end) { + while (slice < wb.start) slice += portlen; + while (slice > wb.end) slice -= portlen; + } + else { + while (slice > wb.start) slice -= portlen; + while (slice < wb.end) slice += portlen; + } sprintf(netname, "%s[%d]", scanroot, slice); if (LookupObject(netname, CurrentCell) == NULL) Node(netname); From 5ea7916ff1ef36714d19b76b065277a9674f71e5 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 27 Mar 2020 12:15:57 -0400 Subject: [PATCH 3/5] Final (I hope) correction to netgen for handling signal wraparound for buses applied to instance arrayes. --- base/verilog.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/base/verilog.c b/base/verilog.c index 83d1f06..317e28e 100644 --- a/base/verilog.c +++ b/base/verilog.c @@ -1910,29 +1910,37 @@ nextinst: else { // Instance must be an array char netname[128]; - int slice, portlen; + int slice, portlen, siglen; /* Get the array size of the port for bit slicing */ portlen = (scan->width < 0) ? 1 : scan->width; - if (wb.start >= wb.end && arraystart >= arrayend) - slice = wb.start - (arraystart - i) * portlen; - else if (wb.start < wb.end && arraystart > arrayend) - slice = wb.start + (arraystart - i) * portlen; - else if (wb.start > wb.end && arraystart < arrayend) - slice = wb.start - (arraystart + i) * portlen; - else // (wb.start < wb.end && arraystart < arrayend) - slice = wb.start + (arraystart + i) * portlen; + /* Get the full array size of the connecting bus */ + GetBus(scanroot, &wb2); + siglen = wb2.start - wb2.end; + if (siglen < 0) siglen = -siglen; + siglen++; - if (wb.start < wb.end) { - while (slice < wb.start) slice += portlen; - while (slice > wb.end) slice -= portlen; + // If signal array is smaller than the portlength * + // length of instance array, then the signal wraps. + + if (wb2.start >= wb2.end && arraystart >= arrayend) { + slice = wb.start - (arraystart - i) * portlen; + while (slice < wb2.end) slice += siglen; } - else { - while (slice > wb.start) slice -= portlen; - while (slice < wb.end) slice += portlen; + else if (wb2.start < wb2.end && arraystart > arrayend) { + slice = wb.start + (arraystart - i) * portlen; + while (slice > wb2.end) slice -= siglen; } - + else if (wb2.start > wb2.end && arraystart < arrayend) { + slice = wb.start - (arraystart + i) * portlen; + while (slice < wb2.end) slice += siglen; + } + else { // (wb2.start < wb2.end && arraystart < arrayend) + slice = wb.start + (arraystart + i) * portlen; + while (slice > wb2.end) slice -= siglen; + } + sprintf(netname, "%s[%d]", scanroot, slice); if (LookupObject(netname, CurrentCell) == NULL) Node(netname); join(netname, obptr->name); From d985ea340ec46539f9ce9cf115070ef7415b6cd7 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 27 Mar 2020 12:47:24 -0400 Subject: [PATCH 4/5] One more bug fix. . . unitialized variable error. --- base/verilog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/verilog.c b/base/verilog.c index 317e28e..4a1c469 100644 --- a/base/verilog.c +++ b/base/verilog.c @@ -1738,7 +1738,7 @@ nextinst: // Net is bit-sliced across array of instances. if (wb.start > wb.end) { - char *bptr, *cptr, cchar, *netname; + char *bptr, *cptr = NULL, cchar, *netname; unsigned char is_bundle = 0; struct bus wbb; From 6ae6a246e93333b1be3b21d35907b479ec53c615 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 27 Mar 2020 15:09:56 -0400 Subject: [PATCH 5/5] Some additional changes to better identify behavioral verilog blocks. --- base/verilog.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/base/verilog.c b/base/verilog.c index 4a1c469..ca3de18 100644 --- a/base/verilog.c +++ b/base/verilog.c @@ -1070,6 +1070,13 @@ skip_endmodule: kl->pdefault.ival = 1; kl->slop.ival = 0; } + else if (nexttok[0] == '(') { + /* For now, the netgen verilog parser doesn't handle `define f(X) ... */ + SkipNewLine(VLOG_DELIMITERS); + FREE(kl->key); + FREE(kl); + kl = NULL; + } else if (ConvertStringToInteger(nexttok, &ival) == 1) { /* Parameter parses as an integer */ kl->type = PROP_INTEGER; @@ -1088,7 +1095,7 @@ skip_endmodule: kl->pdefault.string = strsave(nexttok); kl->slop.dval = 0.0; } - HashPtrInstall(kl->key, kl, &verilogdefs); + if (kl) HashPtrInstall(kl->key, kl, &verilogdefs); } else if (match(nexttok, "`undef")) { struct property *kl = NULL; @@ -1328,6 +1335,22 @@ skip_endmodule: struct objlist *obptr; strncpy(modulename, nexttok, 99); + + /* If module name is a verilog primitive, then treat the module as a */ + /* black box (this is not a complete list. Preferable to use hash */ + /* function instead of lots of strcmp() calls). */ + + if (!strcmp(modulename, "buf") || !strcmp(modulename, "notif1") || + !strcmp(modulename, "not") || !strcmp(modulename, "and") || + !strcmp(modulename, "or") || !strcmp(modulename, "bufif0") || + !strcmp(modulename, "bufif1") || !strcmp(modulename, "notif0")) { + + Printf("Module contains verilog primitive '%s'.\n", nexttok); + Printf("Module '%s' is not structural verilog, making black-box.\n", model); + SetClass(CLASS_MODULE); + goto skip_endmodule; + } + if (!(*CellStackPtr)) { CellDef(fname, filenum); PushStack(fname, CellStackPtr);