diff --git a/VERSION b/VERSION index 67f7f06..d27c89c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.240 +1.5.241 diff --git a/base/netcmp.c b/base/netcmp.c index 8d8efbc..179cb96 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -5788,14 +5788,15 @@ Tcl_Obj * #else void #endif -PropertyMatch(struct objlist *ob1, int file1, - struct objlist *ob2, int file2, +PropertyMatch(struct Element *E1, struct Element *E2, int do_print, int do_list, int *retval) { struct nlist *tc1, *tc2; - struct objlist *tp1, *tp2, *obn1, *obn2, *tpc; + struct objlist *ob1, *ob2, *tp1, *tp2, *obn1, *obn2, *tpc; struct property *kl1, *kl2; struct valuelist *vl1, *vl2; + struct NodeList *nl1, *nl2; + int file1, file2; int t1type, t2type, run1, run2; int i, mismatches = 0, checked_one; int rval = 1; @@ -5804,6 +5805,12 @@ PropertyMatch(struct objlist *ob1, int file1, Tcl_Obj *proplist = NULL, *mpair, *mlist; #endif + ob1 = E1->object; + ob2 = E2->object; + + file1 = E1->graph; + file2 = E2->graph; + tc1 = LookupCellFile(ob1->model.class, file1); tc2 = LookupCellFile(ob2->model.class, file2); @@ -5891,12 +5898,14 @@ PropertyMatch(struct objlist *ob1, int file1, /* Check for no-connect pins in merged devices on both sides. */ /* Both sides should either have no-connects marked, or neither. */ - /* (Permutable pins may need to be handled correctly. . . */ + /* Permutable pins need to be handled correctly. */ - for (tp1 = ob1, tp2 = ob2; (tp1 != NULL) && tp1->type >= FIRSTPIN && - (tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next) { + for (tp1 = ob1, tp2 = ob2, nl1 = E1->nodelist; tp1 && tp2; tp1 = tp1->next, tp2 = tp2->next) { struct objlist *node1, *node2; + if ((tp1 != ob1) && (tp1->type <= FIRSTPIN)) break; + if ((tp2 != ob2) && (tp2->type <= FIRSTPIN)) break; + if (file1 == Circuit1->file) node1 = Circuit1->nodename_cache[tp1->node]; else @@ -5907,22 +5916,45 @@ PropertyMatch(struct objlist *ob1, int file1, else node2 = Circuit2->nodename_cache[tp2->node]; + if (node1->flags != node2->flags) { + struct objlist *tp2b; + + /* Find if there is permutable pin node with matching flags */ + /* Note that this is not rigorous, and should be better handled. */ + + for (tp2b = ob2, nl2 = E2->nodelist; tp2b; tp2b = tp2b->next, nl2 = nl2->next) { + if ((tp2b != ob2) && (tp2b->type <= FIRSTPIN)) break; + if (tp2b == tp2) continue; + if (nl2->pin_magic == nl1->pin_magic) { + if (file2 == Circuit1->file) + node2 = Circuit1->nodename_cache[tp2b->node]; + else + node2 = Circuit2->nodename_cache[tp2b->node]; + } + if (node1->flags == node2->flags) break; + } + } + /* NOTE: A "no-connect" node (multiple no-connects represented by a * single node) has non-zero flags. A non-node entry in the cache * implies a node with zero flags. */ - if (node1->flags != node1->flags) { - Fprintf(stdout, " Parallelized instances disagree on pin connections.\n"); - Fprintf(stdout, " Circuit1 instance %s pin %s connections are %s (%d)\n", + if (node1->flags != node2->flags) { + if (do_print) { + Fprintf(stdout, " Parallelized instances disagree on pin connections.\n"); + Fprintf(stdout, " Circuit1 instance %s pin %s connections are %s (%d)\n", tp1->instance.name, node1->name, (node1->flags == 0) ? "tied together" : "no connects", node1->flags); - Fprintf(stdout, " Circuit2 instance %s pin %s connections are %s (%d)\n", + Fprintf(stdout, " Circuit2 instance %s pin %s connections are %s (%d)\n", tp2->instance.name, node2->name, (node2->flags == 0) ? "tied together" : "no connects", node2->flags); + } mismatches++; } + + nl1 = nl1->next; } // Attempt to organize devices by series and parallel combination @@ -5932,8 +5964,11 @@ PropertyMatch(struct objlist *ob1, int file1, // PropertySortAndCombine can move the first property, so recompute it // for each circuit. - for (tp1 = ob1; (tp1 != NULL) && tp1->type >= FIRSTPIN; tp1 = tp1->next); - for (tp2 = ob2; (tp2 != NULL) && tp2->type >= FIRSTPIN; tp2 = tp2->next); + tp1 = tp2 = NULL; + if (t1type == PROPERTY) + for (tp1 = ob1; (tp1 != NULL) && tp1->type >= FIRSTPIN; tp1 = tp1->next); + if (t2type == PROPERTY) + for (tp2 = ob2; (tp2 != NULL) && tp2->type >= FIRSTPIN; tp2 = tp2->next); // Find name for printing, removing leading slash if needed. inst1 = ob1->instance.name; @@ -5963,12 +5998,16 @@ PropertyMatch(struct objlist *ob1, int file1, if (vl2->type == PROP_ENDLIST) break; if (vl2 == NULL) continue; if (vl2->key == NULL) continue; - kl2 = (struct property *)HashLookup(vl2->key, &(tc2->propdict)); - if (kl2 != NULL) { - // Allowed for one instance to be missing "M" or "S". - if (!(*matchfunc)(vl2->key, "M") && !(*matchfunc)(vl2->key, "S")) + + // Allowed for one instance to be missing "M" or "S" if the other + // has value 1. + if (!(*matchfunc)(vl2->key, "M") && !(*matchfunc)(vl2->key, "S")) { + kl2 = (struct property *)HashLookup(vl2->key, &(tc2->propdict)); + if (kl2 != NULL) break; // Property is required } + else if (vl2->value.ival != 1) + break; // Property M != 1 or S != 1 is a mismatch. } if (vl2->type != PROP_ENDLIST) { mismatches++; @@ -6016,12 +6055,16 @@ PropertyMatch(struct objlist *ob1, int file1, if (vl1->type == PROP_ENDLIST) break; if (vl1 == NULL) continue; if (vl1->key == NULL) continue; - kl1 = (struct property *)HashLookup(vl1->key, &(tc1->propdict)); - if (kl1 != NULL) { - // Allowed for one instance to be missing "M" or "S". - if (!(*matchfunc)(vl1->key, "M") && !(*matchfunc)(vl1->key, "S")) + + // Allowed for one instance to be missing "M" or "S" if the other + // has value 1. + if (!(*matchfunc)(vl1->key, "M") && !(*matchfunc)(vl1->key, "S")) { + kl1 = (struct property *)HashLookup(vl1->key, &(tc1->propdict)); + if (kl1 != NULL) break; // Property is required } + else if (vl1->value.ival != 1) + break; // Property M != 1 or S != 1 is a mismatch. } if (vl1->type != PROP_ENDLIST) { mismatches++; @@ -6146,11 +6189,9 @@ PropertyCheck(struct ElementClass *EC, int do_print, int do_list, int *rval) E2 = Etmp; } #ifdef TCL_NETGEN - return PropertyMatch(E1->object, E1->graph, E2->object, E2->graph, - do_print, do_list, rval); + return PropertyMatch(E1, E2, do_print, do_list, rval); #else - PropertyMatch(E1->object, E1->graph, E2->object, E2->graph, - do_print, do_list, rval); + PropertyMatch(E1, E2, do_print, do_list, rval); #endif } @@ -6321,7 +6362,7 @@ int ResolveAutomorphsByPin() int portnum; /* Diagnostic */ - Fprintf(stdout, "Resolving automorphisms by pin name.\n"); + Fprintf(stdout, "Resolving symmetries by pin name.\n"); for (NC = NodeClasses; NC != NULL; NC = NC->next) { struct Node *N1, *N2; @@ -6346,6 +6387,8 @@ int ResolveAutomorphsByPin() for (N2 = N1->next; N2 != NULL; N2 = N2->next) { if ((N2->graph != N1->graph) && (*matchfunc)(N2->object->name, N1->object->name)) { + if (Debug == TRUE) + Printf("Symmetry group broken by name match (pin %s)\n", N2->object->name); Magic(newhash); N1->hashval = newhash; N2->hashval = newhash; @@ -6381,7 +6424,7 @@ int ResolveAutomorphsByProperty() unsigned long orighash, newhash; /* Diagnostic */ - Fprintf(stdout, "Resolving automorphisms by property value.\n"); + Fprintf(stdout, "Resolving symmetries by property value.\n"); for (EC = ElementClasses; EC != NULL; EC = EC->next) { struct Element *E1, *E2; @@ -6419,9 +6462,10 @@ int ResolveAutomorphsByProperty() badmatch = FALSE; for (E2 = E1->next; E2 != NULL; E2 = E2->next) { if (E2->hashval != orighash) continue; - PropertyMatch(E1->object, E1->graph, E2->object, E2->graph, - FALSE, FALSE, &result); + PropertyMatch(E1, E2, FALSE, FALSE, &result); if (result == 0) { + if (Debug == TRUE) + Printf("Symmetry group split by property (element %s)\n", E2->object->model.class); E2->hashval = newhash; if (E2->graph == E1->graph) C1++; @@ -6488,6 +6532,7 @@ int ResolveAutomorphisms() struct NodeClass *NC; struct Node *N; int C1, C2; + int automorphs; for (EC = ElementClasses; EC != NULL; EC = EC->next) { struct Element *E1, *E2; @@ -6539,8 +6584,9 @@ int ResolveAutomorphisms() FractureElementClass(&ElementClasses); FractureNodeClass(&NodeClasses); ExhaustiveSubdivision = 1; - while (!Iterate() && VerifyMatching() >= 0); - return(VerifyMatching()); + while (!Iterate() && (VerifyMatching() >= 0)); + + return VerifyMatching(); } /*------------------------------------------------------*/ @@ -8115,7 +8161,7 @@ int Compare(char *cell1, char *cell2) /* arbitrarily resolve automorphisms */ Fprintf(stdout, "\n"); - Fprintf(stdout, "Resolving automorphisms by arbitrary symmetry breaking:\n"); + Fprintf(stdout, "Resolving symmetries by arbitrary symmetry breaking:\n"); while ((automorphisms = ResolveAutomorphisms()) > 0) ; if (automorphisms == -1) { MatchFail(cell1, cell2); @@ -8214,7 +8260,7 @@ void NETCOMP(void) else { Printf("Netlists match with %d symmetries.\n", automorphisms); while ((automorphisms = ResolveAutomorphisms()) > 0) - Printf(" automorphisms = %d.\n", automorphisms); + Printf(" symmetries = %d.\n", automorphisms); if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n"); else if (automorphisms == -2) Fprintf(stdout, "Port counts do not match.\n"); else Printf("Circuits match correctly.\n"); @@ -8281,7 +8327,7 @@ void NETCOMP(void) Printf("(c)reate internal data structure\n"); Printf("do an (i)teration\n"); Printf("(r)un to completion (convergence)\n"); - Printf("(R)un to completion (resolve automorphisms)\n"); + Printf("(R)un to completion (resolve symmetries)\n"); Printf("(v)erify results\n"); Printf("print (a)utomorphisms\n"); Printf("equate two (d)evices\n"); diff --git a/base/objlist.h b/base/objlist.h index 6845a29..6facb4a 100644 --- a/base/objlist.h +++ b/base/objlist.h @@ -206,7 +206,7 @@ struct nlist { char *name; int number; /* number of instances defined */ int dumped; /* instance count, and general-purpose marker */ - unsigned char flags; + unsigned short flags; unsigned char class; unsigned long classhash; /* randomized hash value for cell class */ struct Permutation *permutes; /* list of permuting pins */ @@ -222,17 +222,18 @@ struct nlist { /* Defined nlist structure flags */ -#define CELL_MATCHED 0x01 /* cell matched to another */ -#define CELL_NOCASE 0x02 /* cell is case-insensitive (e.g., SPICE) */ -#define CELL_TOP 0x04 /* cell is a top-level cell */ -#define CELL_PLACEHOLDER 0x08 /* cell is a placeholder cell */ -#define CELL_PROPSMATCHED 0x10 /* properties matched to matching cell */ -#define CELL_DUPLICATE 0x20 /* cell has a duplicate */ +#define CELL_MATCHED 0x001 /* cell matched to another */ +#define CELL_NOCASE 0x002 /* cell is case-insensitive (e.g., SPICE) */ +#define CELL_TOP 0x004 /* cell is a top-level cell */ +#define CELL_PLACEHOLDER 0x008 /* cell is a placeholder cell */ +#define CELL_PROPSMATCHED 0x010 /* properties matched to matching cell */ +#define CELL_DUPLICATE 0x020 /* cell has a duplicate */ +#define CELL_VERILOG 0x040 /* cell is verilog module */ /* Flags for combination allowances and prohibitions */ -#define COMB_SERIES 0x40 -#define COMB_NO_PARALLEL 0x80 +#define COMB_SERIES 0x100 +#define COMB_NO_PARALLEL 0x200 extern struct nlist *CurrentCell; extern struct objlist *CurrentTail; diff --git a/base/spice.c b/base/spice.c index 55b9a5f..e888bd5 100644 --- a/base/spice.c +++ b/base/spice.c @@ -1783,6 +1783,18 @@ skip_ends: ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ update = 1; } + else if (tp->flags & CELL_VERILOG) { + if (tp->flags & CELL_PLACEHOLDER) { + /* Flag this as an error. To do: Rearrange the verilog instance pins to */ + /* match the SPICE subcircuit pin order. */ + Fprintf(stderr, "Error: SPICE subcircuit %s should be read before verilog " + "module using it, or pins may not match!\n", subcktname); + } + else { + Fprintf(stderr, "Error: SPICE subcircuit %s redefines a verilog module!\n", + subcktname); + } + } /* nexttok is now NULL, scan->name points to class */ diff --git a/base/verilog.c b/base/verilog.c index b3cba76..4598b1c 100644 --- a/base/verilog.c +++ b/base/verilog.c @@ -803,6 +803,56 @@ extern void IncludeVerilog(char *, int, struct cellstack **, int); extern void PushStack(char *cellname, struct cellstack **top); extern void PopStack(struct cellstack **top); +/*------------------------------------------------------*/ +/* Callback routine for FindInstanceOf() */ +/* NOTE: This casts a (struct objlist) pointer to a */ +/* (struct nlist) pointer for the purpose of using */ +/* RecurseCellHashTable2(). FindInstanceOf() casts it */ +/* back into a (struct objlist) pointer. */ +/*------------------------------------------------------*/ + +struct nlist *findInstance(struct hashlist *p, void *clientdata) +{ + struct nlist *ptr; + struct objlist *ob; + struct nlist *tref = (struct nlist *)clientdata; + + ptr = (struct nlist *)(p->ptr); + if (ptr->file != tref->file) return NULL; + + ob = LookupInstance(tref->name, ptr); + return (struct nlist *)ob; +} + +/*------------------------------------------------------*/ +/* Routine to find the first instance of a cell */ +/*------------------------------------------------------*/ + +struct objlist *FindInstanceOf(struct nlist *tc) +{ + return (struct objlist *)RecurseCellHashTable2(findInstance, (void *)tc); +} + +/*------------------------------------------------------*/ +/* Given a reference cell pointer tref and a port name */ +/* portname, check if portname is a port of tref. If */ +/* not, then call Port() to add one. If tref is NULL, */ +/* then always add the port. */ +/*------------------------------------------------------*/ + +void CheckPort(struct objlist *tref, char *portname) +{ + struct objlist *ob; + + if (tref != NULL) { + for (ob = CurrentCell->cell; ob && (ob->type == PORT); ob = ob->next) { + if ((*matchfunc)(ob->name, portname)) + return; + } + } + Port(portname); +} + /*------------------------------------------------------*/ /* Read a verilog structural netlist */ /*------------------------------------------------------*/ @@ -818,7 +868,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, struct keyvalue *kvlist = NULL; char inst[MAX_STR_LEN], model[MAX_STR_LEN], instname[MAX_STR_LEN], portname[MAX_STR_LEN], pkey[MAX_STR_LEN]; struct nlist *tp; - struct objlist *parent, *sobj, *nobj, *lobj, *pobj; + struct objlist *parent, *sobj, *nobj, *lobj, *pobj, *cref; inst[MAX_STR_LEN-1] = '\0'; model[MAX_STR_LEN-1] = '\0'; @@ -938,6 +988,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, InputParseError(stderr); } in_module = (char)1; + cref = NULL; /* Save pointer to current cell */ if (CurrentCell != NULL) @@ -949,6 +1000,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, snprintf(model, MAX_STR_LEN-1, "%s", nexttok); tp = LookupCellFile(nexttok, filenum); + hasports = (char)0; /* Check for name conflict with duplicate cell names */ /* This may mean that the cell was used before it was */ @@ -986,23 +1038,48 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, CellDef(nexttok, filenum); tp = LookupCellFile(nexttok, filenum); } - else if (tp != NULL) { /* Make a new definition for an empty cell */ - FreePorts(nexttok); - CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */ + else if (tp != NULL) { /* Cell exists, but as a placeholder */ + struct nlist *tptmp = NULL; + char ctemp[8]; + int n = 0; + + /* This redefines a placeholder module to an unused temporary cell name */ + while (1) { + sprintf(ctemp, "%d", n); + tptmp = LookupCellFile(ctemp, filenum); + if (tptmp == NULL) break; + n++; + } + CellRehash(nexttok, ctemp, filenum); + tptmp = LookupCellFile(ctemp, filenum); + + /* Create a new module definition */ CellDef(model, filenum); tp = LookupCellFile(model, filenum); + + /* Find an instance of this module in the netlist */ + cref = FindInstanceOf(tp); + if ((cref != NULL) && (cref->name != NULL)) { + hasports = (char)1; + /* Copy ports from the original parent cell to the new parent cell */ + for (pobj = tptmp->cell; pobj && (pobj->type == PORT); pobj = pobj->next) + Port(pobj->name); + } + /* Remove the original cell definition */ + FreePorts(ctemp); + CellDelete(ctemp, filenum); /* This removes any PLACEHOLDER flag */ } else if (tp == NULL) { /* Completely new cell, no name conflict */ CellDef(model, filenum); tp = LookupCellFile(model, filenum); } - hasports = (char)0; inlined_decls = (char)0; if (tp != NULL) { struct bus wb, *nb; + tp->flags |= CELL_VERILOG; PushStack(tp->name, CellStackPtr); /* Need to support both types of I/O lists: Those */ @@ -1071,7 +1148,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, if (GetBusTok(&wb) != 0) { // Didn't parse as a bus, so wing it wb.start = wb.end = -1; - Port(nexttok); + CheckPort(cref, nexttok); } } else { @@ -1079,13 +1156,13 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, if (wb.start > wb.end) { for (i = wb.start; i >= wb.end; i--) { sprintf(portname, "%s[%d]", nexttok, i); - Port(portname); + CheckPort(cref, portname); } } else { for (i = wb.start; i <= wb.end; i++) { sprintf(portname, "%s[%d]", nexttok, i); - Port(portname); + CheckPort(cref, portname); } } /* Also register this port as a bus */ @@ -1097,7 +1174,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, wb.start = wb.end = -1; } else { - Port(nexttok); + CheckPort(cref, nexttok); } } hasports = 1; @@ -1153,7 +1230,7 @@ skip_endmodule: if (GetBusTok(&wb) != 0) { // Didn't parse as a bus, so wing it wb.start = wb.end = -1; - Port(nexttok); + CheckPort(cref, nexttok); } } else if (!match(nexttok, ",")) { @@ -1161,13 +1238,13 @@ skip_endmodule: if (wb.start > wb.end) { for (i = wb.start; i >= wb.end; i--) { sprintf(portname, "%s[%d]", nexttok, i); - Port(portname); + CheckPort(cref, portname); } } else { for (i = wb.start; i <= wb.end; i++) { sprintf(portname, "%s[%d]", nexttok, i); - Port(portname); + CheckPort(cref, portname); } } /* Also register this port as a bus */ @@ -1178,7 +1255,7 @@ skip_endmodule: wb.start = wb.end = -1; } else { - Port(nexttok); + CheckPort(cref, nexttok); } } hasports = 1; @@ -1194,6 +1271,7 @@ skip_endmodule: InputParseError(stderr); } in_module = (char)0; + cref = NULL; if (*CellStackPtr) PopStack(CellStackPtr); if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum); @@ -2115,7 +2193,7 @@ nextinst: sprintf(localnet, "_noconnect_%d_", localcount++); Node(localnet); join(localnet, obptr->name); - Fprintf(stderr, + Fprintf(stdout, "Note: Implicit pin %s in instance %s of %s in cell %s\n", obpinname, locinst, modulename, CurrentCell->name); } @@ -2207,8 +2285,8 @@ nextinst: char tempname[MAX_STR_LEN]; int maxnode; - /* This pin was probably implicit in the first call */ - /* and so it needs to be added to the definition. */ + /* This pin was probably implicit in the first call */ + /* and so it needs to be added to the definition. */ ReopenCellDef(modulename, filenum); Port(scan->name); @@ -2265,7 +2343,7 @@ nextinst: sprintf(tempname, "_noconnect_%d_", localcount++); Node(tempname); join(tempname, nobj->name); - Fprintf(stderr, "Note: Implicit pin %s in instance " + Fprintf(stdout, "Note: Implicit pin %s in instance " "%s of %s in cell %s\n", scan->name, sobj->instance.name, modulename, CurrentCell->name);