Compare commits

..
10 Commits
Author SHA1 Message Date
Tim Edwards 02a77b61f9 Merge branch 'master' into work 2018-04-26 08:01:20 -04:00
Tim Edwards dfd1e59432 Update at Thu Apr 26 08:01:18 EDT 2018 by tim 2018-04-26 08:01:18 -04:00
Tim Edwards f14ebf323f Fixed a script error that caused pins not to be reported in the
Tcl list and JSON formatted outputs.
2018-04-26 08:00:47 -04:00
Tim Edwards 62648c5672 Merge branch 'master' into work 2018-04-25 15:03:18 -04:00
Tim Edwards 7d113beada Update at Wed Apr 25 15:03:16 EDT 2018 by tim 2018-04-25 15:03:16 -04:00
Tim Edwards 1fe341833c Expanded the verilog parsing to include simple handling of ifdef,
ifndef, endif conditional statements.  Pre-define the key "LVS"
for use with netgen.  Also corrected some problems stemming from
the way delimiters are handled and the flexible use of whitespace
in verilog.
2018-04-25 15:00:49 -04:00
Tim Edwards aee4b846e2 Corrected the known issue with pin bus index matching that was in
the last commit and which was expected to be corrected by this
commit.
2018-04-16 17:19:26 -04:00
Tim Edwards 004378be11 Merge branch 'master' into work 2018-04-16 15:43:25 -04:00
Tim Edwards dc42e98ab9 Update at Mon Apr 16 15:43:23 EDT 2018 by tim 2018-04-16 15:43:23 -04:00
Tim Edwards 58d7e17231 Corrected basic problem with verilog instance pins not needing to
be in any specific order since all ports are named.  Also corrected
problem with pin names not using the same string matching function
as used for nets in general (which affects the ability to match
against different bus delimiters).
2018-04-16 15:41:20 -04:00
5 changed files with 274 additions and 111 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.95
1.5.98
+4 -4
View File
@@ -4915,7 +4915,7 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
case PROP_STRING:
islop = (int)(MAX(kl1->slop.dval, kl2->slop.dval) + 0.5);
if (islop == 0) {
if (strcasecmp(vl1->value.string, vl2->value.string)) {
if (!(*matchfunc)(vl1->value.string, vl2->value.string)) {
if (do_print) {
if (mismatches == 0)
Fprintf(stdout, "%s vs. %s:\n", inst1, inst2);
@@ -5172,7 +5172,7 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
kl2 = (struct property *)HashLookup(vl2->key, &(tc2->propdict));
if (kl2 != NULL) {
// Allowed for one instance to be missing "M" or "S".
if (strcasecmp(vl2->key, "M") && strcasecmp(vl2->key, "S"))
if (!(*matchfunc)(vl2->key, "M") && !(*matchfunc)(vl2->key, "S"))
break; // Property is required
}
}
@@ -5223,7 +5223,7 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
kl1 = (struct property *)HashLookup(vl1->key, &(tc1->propdict));
if (kl1 != NULL) {
// Allowed for one instance to be missing "M" or "S".
if (strcasecmp(vl1->key, "M") && strcasecmp(vl1->key, "S"))
if (!(*matchfunc)(vl1->key, "M") && !(*matchfunc)(vl1->key, "S"))
break; // Property is required
}
}
@@ -6508,7 +6508,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
for (m = 0; m < 43; m++) *(ostr + m) = ' ';
for (m = 44; m < 87; m++) *(ostr + m) = ' ';
snprintf(ostr, 43, "%s", obn->name);
if (!strcasecmp(obn->name, obp->name))
if ((*matchfunc)(obn->name, obp->name))
snprintf(ostr + 44, 43, "%s", obp->name);
else
snprintf(ostr + 44, 43, "%s **Mismatch**", obp->name);
+1
View File
@@ -290,6 +290,7 @@ void InitCellHashTable(void)
{
hashfunc = hash;
matchfunc = match;
matchintfunc = matchfile;
InitializeHashTable(&cell_dict, CELLHASHSIZE);
}
+266 -104
View File
@@ -62,6 +62,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
// Global storage for verilog parameters
struct hashdict verilogparams;
// Global storage for verilog definitions
struct hashdict verilogdefs;
// Global storage for wire buses
struct hashdict buses;
@@ -339,8 +341,10 @@ void CleanupModule() {
}
if (has_submodules == FALSE) SetClass(CLASS_MODULE);
RecurseHashTable(&verilogparams, freebus);
HashKill(&buses);
if (buses.hashtab != NULL) {
RecurseHashTable(&buses, freebus);
HashKill(&buses);
}
}
/*------------------------------------------------------*/
@@ -371,7 +375,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
char devtype, in_module, in_comment, in_param;
char *eqptr, *parptr, *matchptr;
struct keyvalue *kvlist = NULL;
char inst[256], model[256], instname[256];
char inst[256], model[256], instname[256], portname[256];
struct nlist *tp;
struct objlist *parent, *sobj, *nobj, *lobj, *pobj;
@@ -401,6 +405,19 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
if (match(nexttok, "//"))
SkipNewLine(VLOG_DELIMITERS);
/* Ignore primitive definitions */
else if (match(nexttok, "primitive")) {
while (1) {
SkipNewLine(VLOG_DELIMITERS);
SkipTok(VLOG_DELIMITERS);
if (EndParseFile()) break;
if (match(nexttok, "endprimitive")) {
in_module = 0;
break;
}
}
}
else if (match(nexttok, "module")) {
InitializeHashTable(&buses, OBJHASHSIZE);
SkipTokNoNewline(VLOG_DELIMITERS);
@@ -477,6 +494,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
inlined_decls = (char)0;
if (tp != NULL) {
struct bus wb;
PushStack(tp->name, CellStackPtr);
@@ -499,14 +517,18 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
}
in_param = (char)1;
}
else if (match(nexttok, "(")) {
SkipTok(VLOG_DELIMITERS);
else if (nexttok[0] == '(') {
if (match(nexttok, "("))
SkipTok(VLOG_DELIMITERS);
else
nexttok++;
while (match(nexttok, "//")) {
SkipNewLine(VLOG_DELIMITERS);
SkipTok(VLOG_DELIMITERS);
}
}
wb.start = wb.end = -1;
while ((nexttok != NULL) && (nexttok[0] != ';')) {
if (in_param) {
if (!strcmp(nexttok, ")")) {
@@ -536,12 +558,44 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
if (!match(nexttok, "input") && !match(nexttok, "output") &&
!match(nexttok, "inout") && !match(nexttok, "real") &&
!match(nexttok, "logic") && !match(nexttok, "integer")) {
Port(nexttok);
if (nexttok[0] == '[') {
if (GetBus(nexttok, &wb) != 0) {
// Didn't parse as a bus, so wing it
wb.start = wb.end = -1;
Port(nexttok);
}
}
else {
if (wb.start != -1) {
if (wb.start > wb.end) {
for (i = wb.start; i >= wb.end; i--) {
sprintf(portname, "%s[%d]", nexttok, i);
Port(portname);
}
}
else {
for (i = wb.start; i <= wb.end; i++) {
sprintf(portname, "%s[%d]", nexttok, i);
Port(portname);
}
}
wb.start = wb.end = -1;
}
else {
char *pptr;
if ((pptr = strrchr(nexttok, ')')) != NULL)
*pptr = '\0';
Port(nexttok);
if (pptr != NULL) break;
}
}
hasports = 1;
}
}
}
SkipTok(VLOG_DELIMITERS);
if (nexttok == NULL) break;
while (match(nexttok, "//")) { SkipNewLine(VLOG_DELIMITERS); SkipTok(VLOG_DELIMITERS); }
}
SetClass((blackbox) ? CLASS_MODULE : CLASS_SUBCKT);
@@ -652,28 +706,51 @@ skip_endmodule:
// Eliminate any single or double quotes around the filename
iptr = iname;
quotptr = iptr;
while (*quotptr != '\'' && *quotptr != '\"' && *quotptr != '`' &&
while (*quotptr != '\'' && *quotptr != '\"' &&
*quotptr != '\0' && *quotptr != '\n') quotptr++;
if (*quotptr == '\'' || *quotptr == '\"' || *quotptr == '`') *quotptr = '\0';
if (*quotptr == '\'' || *quotptr == '\"') *quotptr = '\0';
IncludeVerilog(iptr, filenum, CellStackPtr, blackbox);
FREE(iname);
SkipNewLine(VLOG_DELIMITERS);
}
else if (match(nexttok, "`define") || match(nexttok, "localparam")) {
else if (match(nexttok, "`define")) {
struct property *kl = NULL;
// Pick up key-value pair and store in current cell
/* Parse for definitions used in expressions. Save */
/* definitions in the "verilogdefs" hash table. */
SkipTokNoNewline(VLOG_DELIMITERS);
if ((nexttok == NULL) || (nexttok[0] == '\0')) break;
kl = NewProperty();
kl->key = strsave(nexttok);
kl->idx = 0;
kl->type = PROP_STRING;
kl->slop.dval = 0.0;
SkipTokNoNewline(VLOG_DELIMITERS);
if ((nexttok == NULL) || (nexttok[0] == '\0'))
// Let "`define X" be equivalent to "`define X 1"
kl->pdefault.string = strsave("1");
else
kl->pdefault.string = strsave(nexttok);
HashPtrInstall(kl->key, kl, &verilogdefs);
}
else if (match(nexttok, "localparam")) {
// Pick up key = value pairs and store in current cell
while (nexttok != NULL)
{
struct property *kl = NULL;
/* Parse for parameters used in expressions. Save */
/* parameters in the "verilogparams" hash table. */
SkipTokNoNewline(VLOG_DELIMITERS);
if ((nexttok == NULL) || (nexttok[0] == '\0')) break;
if ((eqptr = strchr(nexttok, '=')) != NULL)
{
struct property *kl = NULL;
if ((eqptr = strchr(nexttok, '=')) != NULL) {
*eqptr = '\0';
kl = NewProperty();
kl->key = strsave(nexttok);
@@ -686,6 +763,41 @@ skip_endmodule:
}
}
/* Note: This is just the most basic processing of conditionals, */
/* although it does handle nested conditionals. */
else if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef")) {
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);
if (((invert == 0) && (kl == NULL))
|| ((invert == 1) && (kl != NULL))) {
/* Skip to matching `endif */
while (1) {
SkipNewLine(VLOG_DELIMITERS);
SkipTok(VLOG_DELIMITERS);
if (EndParseFile()) break;
if (match(nexttok, "//"))
continue;
else if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef")) {
nested++;
}
else if (match(nexttok, "`endif")) {
if (nested == 0)
break;
else
nested--;
}
}
}
}
else if (match(nexttok, "wire")) { /* wire = node */
struct bus wb, *nb;
char nodename[128];
@@ -698,13 +810,15 @@ skip_endmodule:
if (wb.start > wb.end) {
for (i = wb.end; i <= wb.start; i++) {
sprintf(nodename, "%s[%d]", nexttok, i);
Node(nodename);
if (LookupObject(nodename, CurrentCell) == NULL)
Node(nodename);
}
}
else {
for (i = wb.start; i <= wb.end; i++) {
sprintf(nodename, "%s[%d]", nexttok, i);
Node(nodename);
if (LookupObject(nodename, CurrentCell) == NULL)
Node(nodename);
}
}
nb = NewBus();
@@ -713,7 +827,8 @@ skip_endmodule:
HashPtrInstall(nexttok, nb, &buses);
}
else {
Node(nexttok);
if (LookupObject(nexttok, CurrentCell) == NULL)
Node(nexttok);
}
SkipTokNoNewline(VLOG_DELIMITERS);
}
@@ -748,7 +863,7 @@ skip_endmodule:
struct portelement *next;
};
struct portelement *head, *tail, *scan, *scannext;
struct portelement *head, *tail, *scan, *last, *scannext;
struct objlist *obptr;
strncpy(modulename, nexttok, 99);
@@ -845,7 +960,8 @@ skip_endmodule:
while (nexttok != NULL) {
if (savetok == (char)0) SkipTok(VLOG_DELIMITERS2);
savetok = (char)0;
while (match(nexttok, "//")) {
// NOTE: Deal with `ifdef et al. properly. Ignoring for now.
while (match(nexttok, "//") || (nexttok[0] == '`')) {
SkipNewLine(VLOG_DELIMITERS);
SkipTok(VLOG_DELIMITERS2);
}
@@ -920,7 +1036,7 @@ skip_endmodule:
}
if (head == NULL) {
Fprintf(stderr, "Warning: Cell %s has no pins\n", scan->name);
Fprintf(stderr, "Warning: Cell %s has no pins\n", modulename);
}
/* Check that the module exists. If not, generate an empty */
@@ -928,7 +1044,7 @@ skip_endmodule:
tp = LookupCellFile(modulename, filenum);
if (tp == NULL) {
struct bus wb;
struct bus wb, pb;
char defport[128];
Fprintf(stdout, "Creating placeholder cell definition for "
@@ -966,10 +1082,91 @@ skip_endmodule:
Port((char *)NULL); // Must have something for pin 1
}
SetClass(CLASS_MODULE);
tp = CurrentCell;
EndCell();
ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */
}
/* Work through scan list and expand ports/nets that are arrays */
last = (struct portelement *)NULL;
scan = head;
while (scan != NULL) {
int portstart, portend, portnum;
scannext = scan->next;
portstart = -1;
for (obptr = tp->cell; obptr && obptr->type == PORT; obptr = obptr->next) {
char *delimiter;
if ((delimiter = strrchr(obptr->name, '[')) != NULL) {
*delimiter = '\0';
if ((*matchfunc)(obptr->name, scan->name)) {
if (sscanf(delimiter + 1, "%d", &portnum) == 1) {
if (portstart == -1)
portstart = portnum;
else
portend = portnum;
}
}
*delimiter = '[';
}
}
if (portstart != -1) {
struct bus wb;
struct portelement *new_port;
char vname[256];
int j;
if (GetBus(scan->net, &wb) == 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.
}
else if (wb.start > wb.end) {
i = wb.start;
j = portstart;
while (1) {
new_port = (struct portelement *)CALLOC(1,
sizeof(struct portelement));
sprintf(vname, "%s[%d]", scan->name, j);
new_port->name = strsave(vname);
sprintf(vname, "%s[%d]", scan->net, i);
new_port->net = strsave(vname);
if (last == NULL)
head = new_port;
else
last->next = new_port;
new_port->next = scannext;
last = new_port;
if (j == portend) break;
if (portstart > portend) j--;
else j++;
if (wb.start > wb.end) i--;
else i++;
}
FREE(scan);
scan = last;
}
}
else if (portstart != portend) {
Fprintf(stderr, "Error: Single net %s is connected to bus port %s\n",
scan->net, scan->name);
}
}
last = scan;
scan = scannext;
}
arraymax = (arraystart > arrayend) ? arraystart : arrayend;
arraymin = (arraystart > arrayend) ? arrayend : arraystart;
@@ -987,10 +1184,33 @@ skip_endmodule:
obptr = LookupInstance(locinst, CurrentCell);
if (obptr != NULL) {
scan = head;
if (scan != NULL)
do {
struct bus wb;
char *obpinname;
int obpinidx;
// NOTE: Verilog allows any order of pins, since both the
// instance and cell pin names are given. So for each pin
// in obptr (which defines the pin order) , we have to find
// the corresponding pin in the scan list.
obpinname = strrchr(obptr->name, '/');
if (!obpinname) break;
obpinname++;
scan = head;
obpinidx = -1;
while (scan != NULL) {
if (match(obpinname, scan->name)) {
break;
}
scan = scan->next;
}
if (scan == NULL) {
Fprintf(stderr, "Error: No match in call for pin %s\n", obpinname);
break;
}
if (GetBus(scan->net, &wb) == 0) {
char *scanroot;
scanroot = strsave(scan->net);
@@ -1003,7 +1223,7 @@ skip_endmodule:
char pinname[128];
// Check if port is an array
if (strchr(obptr->name, '[') == NULL) {
if (obpinidx == -1) {
if (wb.start != wb.end) {
Printf("Error: Bus connected to single port\n");
}
@@ -1014,67 +1234,13 @@ skip_endmodule:
join(pinname, obptr->name);
if (brackptr) *brackptr = '[';
}
else if (wb.start > wb.end) {
range = wb.start - wb.end;
for (j = range; j >= 0; j--) {
sprintf(pinname, "%s[%d]", scanroot, j);
if (LookupObject(pinname, CurrentCell) == NULL)
Node(pinname);
join(pinname, obptr->name);
if (j == 0) break;
if (obptr->next && (brackptr =
strchr(obptr->next->name, '[')) != NULL) {
if (strncmp(obptr->next->name, obptr->name,
(int)(brackptr - obptr->next->name))) {
Printf("Error: More bits in net than in port!\n");
break;
}
obptr = obptr->next;
}
else {
Printf("Error: More bits in net than in port!\n");
break;
}
}
// Are there port bits left over?
while (obptr->next && ((brackptr =
strchr(obptr->next->name, '[')) != NULL) &&
(!strncmp(obptr->next->name, obptr->name,
(int)(brackptr - obptr->next->name)))) {
Printf("Error: More bits in port than in net!\n");
obptr = obptr->next;
}
}
else {
range = wb.end - wb.start;
for (j = 0; j <= range; j++) {
sprintf(pinname, "%s[%d]", scanroot, j);
if (LookupObject(pinname, CurrentCell) == NULL)
Node(pinname);
join(pinname, obptr->name);
if (j == range) break;
if (obptr->next && (brackptr =
strchr(obptr->next->name, '[')) != NULL) {
if (strncmp(obptr->next->name, obptr->name,
(int)(brackptr - obptr->next->name))) {
Printf("Error: More bits in net than in port!\n");
break;
}
obptr = obptr->next;
}
else {
Printf("Error: More bits in net than in port!\n");
break;
}
}
// Are there port bits left over?
while (obptr->next && ((brackptr =
strchr(obptr->next->name, '[')) != NULL) &&
(!strncmp(obptr->next->name, obptr->name,
(int)(brackptr - obptr->next->name)))) {
Printf("Error: More bits in port than in net!\n");
obptr = obptr->next;
}
// NOTE: Making unsupportable assumption that
// pin and port indexes match---need to fix this!
sprintf(pinname, "%s[%d]", scanroot, obpinidx);
if (LookupObject(pinname, CurrentCell) == NULL)
Node(pinname);
join(pinname, obptr->name);
}
}
else {
@@ -1100,27 +1266,9 @@ skip_endmodule:
join(scan->net, obptr->name);
}
obptr = obptr->next;
scan = scan->next;
} while (obptr != NULL && obptr->type > FIRSTPIN && scan != NULL);
if ((obptr == NULL && scan != NULL) ||
(obptr != NULL && scan == NULL && obptr->type > FIRSTPIN)) {
if (warnings <= 100) {
Fprintf(stderr,"Parameter list mismatch in %s: ", instancename);
if (obptr == NULL)
Fprintf(stderr, "Too many parameters in call!\n");
else if (scan == NULL)
Fprintf(stderr, "Not enough parameters in call!\n");
InputParseError(stderr);
if (warnings == 100)
Fprintf(stderr, "Too many warnings. . . will not "
"report any more.\n");
}
warnings++;
}
}
if (i == -1) break; /* No array */
} while (obptr != NULL && obptr->type > FIRSTPIN);
}
if (i == -1) break; /* No array */
}
DeleteProperties(&kvlist);
@@ -1165,6 +1313,7 @@ baddevice:
char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
{
struct property *kl = NULL;
struct cellstack *CellStack = NULL;
struct nlist *tp;
int filenum;
@@ -1193,6 +1342,17 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
}
InitializeHashTable(&verilogparams, OBJHASHSIZE);
InitializeHashTable(&verilogdefs, OBJHASHSIZE);
/* Add the pre-defined key "LVS" to verilogdefs */
kl = NewProperty();
kl->key = strsave("LVS");
kl->idx = 0;
kl->type = PROP_STRING;
kl->slop.dval = 0.0;
kl->pdefault.string = strsave("1");
HashPtrInstall(kl->key, kl, &verilogdefs);
/* All verilog files should start with a comment line, */
/* but we won't depend upon it. Any comment line */
@@ -1206,6 +1366,8 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
RecurseHashTable(&verilogparams, freeprop);
HashKill(&verilogparams);
RecurseHashTable(&verilogdefs, freeprop);
HashKill(&verilogdefs);
// Record the top level file.
if (LookupCellFile(fname, filenum) == NULL) CellDef(fname, filenum);
+2 -2
View File
@@ -536,10 +536,10 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
# Match pins
netgen::log echo off
if {$dolist == 1} {
set result [equate pins "$fnum1 [lindex $endval 0]" \
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
} else {
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
set result [equate pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
}
if {$result != 0} {