Merge branch 'master' into netgen-1.5

This commit is contained in:
Tim Edwards 2022-11-05 02:00:01 -04:00
commit a4ae5ed989
5 changed files with 197 additions and 60 deletions

View File

@ -1 +1 @@
1.5.240
1.5.241

View File

@ -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,11 +5916,31 @@ 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) {
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,
@ -5921,8 +5950,11 @@ PropertyMatch(struct objlist *ob1, int file1,
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,7 +5964,10 @@ PropertyMatch(struct objlist *ob1, int file1,
// PropertySortAndCombine can move the first property, so recompute it
// for each circuit.
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.
@ -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;
// 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) {
// Allowed for one instance to be missing "M" or "S".
if (!(*matchfunc)(vl2->key, "M") && !(*matchfunc)(vl2->key, "S"))
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;
// 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) {
// Allowed for one instance to be missing "M" or "S".
if (!(*matchfunc)(vl1->key, "M") && !(*matchfunc)(vl1->key, "S"))
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");

View File

@ -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;

View File

@ -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 */

View File

@ -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);
}
@ -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);