Compare commits

..
21 Commits
Author SHA1 Message Date
Tim Edwards d9425163e1 Merge branch 'master' into netgen-1.5 2022-09-18 02:00:02 -04:00
Tim Edwards f02e2b1ee0 Handled backslash-escapes (convert "\" to "\\") when writing pins
to the JSON format file (since JSON does not allow single backslash
characters.  Previously nets had been handled correctly, but not
pins.  Resolves github issue tracker Issue #60 from Proppy.
2022-09-17 14:33:27 -04:00
Tim Edwards 9ba1dfe814 Merge branch 'master' into netgen-1.5 2022-09-17 02:00:02 -04:00
Tim Edwards cc5f6d929f Added a missing block of code from Mitch Bailey's version that
fails to handle a topology match with a pin mismatch situation.
2022-09-16 13:55:23 -04:00
Tim Edwards fadd0ae2fc Merge branch 'master' into netgen-1.5 2022-09-16 02:00:02 -04:00
Tim Edwards 4fa4d046c8 Part 2 of folding in Mitch Bailey's code. This part is a
significant overhaul of the MatchPins() code, and better handles
issues with pins disconnected from nets and removes cases in
which proxy pins are incorrectly generated.
2022-09-15 10:50:52 -04:00
Tim Edwards 153ce0e2b3 Merge branch 'master' into netgen-1.5 2022-09-14 02:00:02 -04:00
Tim Edwards 9297090dc1 Start of merging Mitch Bailey's code changes from github pull
request #59 ("Pin match").  Because the pull request has rather
sweeping modifications, I am doing this in two steps.  The change
that most breaks with existing comparison methods is in the
PinMatch() routine in netcmp.c, where the method of generating
proxy pins has been removed.  There are specific cases for which
the proxy pin method exists, although these were coping with
issues arising from extraction in magic which have been dealt
with to some extend.  Possibly the proxy pin method is no longer
needed.  So the PinMatch() changes will be done in a second
commit where it's easier to revert or modify the changes without
affecting the modifications from this commit.
2022-09-13 10:55:00 -04:00
Tim Edwards bfdacab28c Merge branch 'master' into netgen-1.5 2022-09-13 02:00:02 -04:00
Tim Edwards 79e193e0c9 Modified behavior for the "-noflatten" option on LVS: Added a
command option "flatten prohibit" (or "flatten deny") to prevent
a subcell from being flattened at any time during the compare
process.  Previously, the "-noflatten" option for the "lvs"
script had been used to prevent flattening during initial
pre-match, but if the circuit passed the prematch phase and
subcells were mismatched, they would be flattened regardless of
whether or not they were listed by the "-noflatten" option.  This
also codifies a way to prevent subcells from being flattened in
the setup file rather than in the "lvs" command line.  Also:
Found and fixed a bug that prevents the use of "-noflatten=" with
a cell name or list of cell names instead of a filename.
2022-09-12 11:26:21 -04:00
Tim Edwards 7e9bd9f2a0 Merge branch 'master' into netgen-1.5 2022-06-28 02:00:02 -04:00
Tim Edwards 2056b37c95 Yesterday's commit surfaced two errors in series; this fixes the
second one of them, which is a failure to change CurrentTail when
an extra (implicit) pin was added to the last component in the
current cell, resulting in the failure of Node() to add the new
no-connect node, which instead overwrites the pin just created.
2022-06-27 20:35:30 -04:00
Tim Edwards ee92d880d7 Merge branch 'master' into netgen-1.5 2022-06-27 02:00:01 -04:00
Tim Edwards 7550ef9258 Corrected an error in reworking verilog instances to add pins that
were implicit in the first instances but made explicit in a later
one.  If more than one such implicit pin was handled for the same
cell, then the pin count would become wrong and rather unpredictable
behavior results.
2022-06-26 22:16:03 -04:00
Tim Edwards a795981eff Corrected a prematch issue that will flatten a cell on one side
even when the opposing netlist has a black-box entry for the same
cell.  The black-box entry can't be flattened, so this just
results in the cell mysteriously disappearing from one side.
2022-06-26 14:57:25 -04:00
Tim Edwards d3407b3e56 Merge branch 'master' into netgen-1.5 2022-06-15 02:00:50 -04:00
Tim Edwards 1b6e4e2b36 Corrected an error in the last commit which can cause the pin
enumeration in MatchPins() to overflow the cover() array and
cause a segmentation fault.
2022-06-14 11:36:30 -04:00
Tim Edwards 0a94bec191 Merge branch 'master' into netgen-1.5 2022-06-13 02:00:18 -04:00
Tim Edwards edbe5d6e86 Made minor changes to MatchPins() to handle multiple pins connected
to a single net (as can be done with assignments in verilog or with
zero-voltage sources or zero-value resistors in SPICE).  Corrected
an error in the SPICE netlist reader that prevented the proper use
of zero-voltage sources as net splitters.
2022-06-12 17:25:37 -04:00
Tim Edwards 4a7b6bf22a Merge branch 'master' into netgen-1.5 2022-06-09 02:00:52 -04:00
Tim Edwards f8ed4e42e2 Corrected the parsing of verilog netlists to use the right
delimiter set when parsing pin names (the correct delimiter set
was used in one place but not in another).  Extended the pin
matching to include the minor hack of ignoring the backslash
before backslash-escaped verilog names when there is otherwise
no exact match, since many tools convert verilog to SPICE by
removing the backslash and trailing space.  This avoids pin
mismatches in a known set of use cases.
2022-06-08 11:53:47 -04:00
7 changed files with 593 additions and 499 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.221
1.5.232
+68 -19
View File
@@ -66,9 +66,13 @@ void flattenCell(char *name, int file)
else
ThisCell = LookupCellFile(name, file);
if (ThisCell == NULL) {
Printf("No cell %s found.\n", name);
Printf("No cell %s (%d) found.\n", name, file);
return;
}
/* Placeholder cells must not be flattened */
if (ThisCell->flags & CELL_PLACEHOLDER) return;
FreeNodeNames(ThisCell);
ParentParams = ThisCell->cell;
@@ -278,16 +282,20 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
}
else {
if (Debug)
Printf("Flattening instances of %s within cell: %s\n", instance, name);
Printf("Flattening instances of %s within cell: %s (%d)\n", instance,
name, fnum);
if (fnum == -1)
ThisCell = LookupCell(name);
else
ThisCell = LookupCellFile(name, fnum);
if (ThisCell == NULL) {
Printf("No cell %s found.\n", name);
Printf("No cell %s (%d) found.\n", name, fnum);
return 0;
}
}
/* Placeholder cells must not be flattened */
if (ThisCell->flags & CELL_PLACEHOLDER) return 0;
FreeNodeNames(ThisCell);
ParentParams = ThisCell->cell;
@@ -681,7 +689,7 @@ void convertGlobalsOf(char *name, int fnum, char *instance)
else
ThisCell = LookupCellFile(name, fnum);
if (ThisCell == NULL) {
Printf("No cell %s found.\n", name);
Printf("No cell %s (%d) found.\n", name, fnum);
return;
}
}
@@ -1111,7 +1119,7 @@ int UniquePins(char *name, int filenum)
ThisCell = LookupCellFile(name, filenum);
if (ThisCell == NULL) {
Printf("No cell %s found.\n", name);
Printf("No cell %s (%d) found.\n", name, filenum);
return 0;
}
@@ -1128,12 +1136,33 @@ int UniquePins(char *name, int filenum)
firstport = (struct objlist **)CALLOC(maxnode + 1, sizeof(struct objlist *));
portcount = FIRSTPIN;
lob = NULL;
for (ob = ThisCell->cell; ob != NULL; ob = ob->next) {
if (ob->type != PORT) break;
if (ob->node > 0) {
nodecount[ob->node]++;
if (nodecount[ob->node] == 2) {
Printf("Duplicate pin %s in cell %s\n", ob->name, ThisCell->name);
if (!(*matchfunc)(firstport[ob->node]->name, ob->name)) {
Printf("Pins %s and %s are shorted in cell %s (%d)\n", ob->name,
firstport[ob->node]->name, ThisCell->name, ThisCell->file);
/* Do not count this as a duplicate pin. */
nodecount[ob->node]--;
/* Move the pin adjacent to the one it is shorted to (if it
* isn't already); this will make the work of MatchPins() easier.
*/
if (firstport[ob->node]->next != ob) {
lob->next = ob->next;
ob->next = firstport[ob->node]->next;
firstport[ob->node]->next = ob;
ob = lob;
}
lob = ob;
continue;
}
else {
Printf("Duplicate pin %s in cell %s (%d)\n", ob->name,
ThisCell->name, filenum);
}
}
if (nodecount[ob->node] > 1) {
/* Remove this node; prep for removal by marking with UNKNOWN */
@@ -1148,6 +1177,7 @@ int UniquePins(char *name, int filenum)
}
}
portcount++;
lob = ob;
}
if (needscleanup)
@@ -1332,7 +1362,7 @@ int CleanupPins(char *name, int filenum)
ThisCell = LookupCellFile(name, filenum);
if (ThisCell == NULL) {
Printf("No cell %s found.\n", name);
Printf("No cell %s (%d) found.\n", name, filenum);
return 0;
}
@@ -1599,19 +1629,22 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
}
if (match) {
if (ecomp->cell1 && (ecomp->num1 > 0)) {
if (ecomp->cell1 && (ecomp->num1 > 0) &&
(!(ecomp->cell1->flags & CELL_PLACEHOLDER))) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell1->name,
name1, file1);
flattenInstancesOf(name1, file1, ecomp->cell1->name);
modified++;
}
if (ecomp->cell2 && (ecomp->num2 > 0)) {
if (ecomp->cell2 && (ecomp->num2 > 0) &&
(!(ecomp->cell2->flags & CELL_PLACEHOLDER))) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell2->name,
name2, file2);
flattenInstancesOf(name2, file2, ecomp->cell2->name);
modified++;
}
modified++;
}
/* Reset or apply the count adjustments */
@@ -1688,13 +1721,21 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
}
if (match) {
if (ecomp->cell2) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
/* Don't flatten if cell1 is a black box, because it */
/* can't also be flattened. */
if ((ecomp->num1 == 0) || (ecomp->cell1->class !=
CLASS_MODULE)) {
if (ecomp->cell2 && !(ecomp->cell2->flags & CELL_PLACEHOLDER)) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell2->name,
name2, file2);
flattenInstancesOf(name2, file2, ecomp->cell2->name);
flattenInstancesOf(name2, file2, ecomp->cell2->name);
modified++;
}
}
modified++;
}
/* Reset or apply the count adjustments */
@@ -1718,7 +1759,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
/* Case 3: Cell1 class is a subcircuit, and flattening */
/* it (without regard to cell1) improves the matching. */
/* it (without regard to cell2) improves the matching. */
else if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) &&
(ecomp->num1 != 0) && (ecomp->cell1->class == CLASS_SUBCKT)) {
@@ -1746,13 +1787,21 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
}
if (match) {
if (ecomp->cell1) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
/* Don't flatten if cell2 is a black box, because it */
/* can't also be flattened. */
if ((ecomp->num2 == 0) || (ecomp->cell2->class !=
CLASS_MODULE)) {
if (ecomp->cell1 && !(ecomp->cell1->flags & CELL_PLACEHOLDER)) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell1->name,
name1, file1);
flattenInstancesOf(name1, file1, ecomp->cell1->name);
flattenInstancesOf(name1, file1, ecomp->cell1->name);
modified++;
}
}
modified++;
}
/* Reset or apply the count adjustments */
+315 -358
View File
@@ -875,7 +875,11 @@ struct FormattedList *FormatBadNodeFragment(struct Node *N)
for (n = pins[i]->subelement->element->nodelist; n != NULL; n = n->next){
if (n->pin_magic == pins[i]->subelement->pin_magic) {
if ((permute == 0) && (ob->instance.name != NULL)) {
pinname = ob->name + strlen(ob->instance.name) + 1;
/* Handle "port_match_error" */
if ((ob->name[0] == 'p') && !strcmp(ob->name, "port_match_error"))
pinname = ob->name;
else
pinname = ob->name + strlen(ob->instance.name) + 1;
}
else if (ob->instance.name != NULL) {
char *pinsave = pinname;
@@ -6181,7 +6185,8 @@ void PrintPropertyResults(int do_list)
/*----------------------------------------------------------------------*/
/* Return 0 if perfect matching found, else return number of */
/* automorphisms, and return -1 if invalid matching found. */
/* automorphisms, and return -1 if invalid matching found, */
/* and return -2 if there is a port count mismatch. */
/*----------------------------------------------------------------------*/
int VerifyMatching(void)
@@ -6192,6 +6197,9 @@ int VerifyMatching(void)
struct Element *E;
struct Node *N;
int C1, C2, result;
int P1, P2;
struct objlist *ob1, *ob2;
int portMismatch = 0;
if (BadMatchDetected) return(-1);
@@ -6212,14 +6220,40 @@ int VerifyMatching(void)
}
}
P1 = P2 = 0;
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
C1 = C2 = 0;
for (N = NC->nodes; N != NULL; N = N->next) {
(N->graph == Circuit1->file) ? C1++ : C2++;
if (IsPort(N->object)) (N->graph == Circuit1->file) ? P1++ : P2++;
}
if (C1 != C2) return(-1);
if (P1 != P2) portMismatch = 1;
if (C1 != 1) ret++;
}
P1 = P2 = 0;
if (ret == 0) { /* automorphisms have precedence over port count mismatch */
if (portMismatch) return -2;
/* Count ports in each subcircuit including disconnected ports */
for (ob1 = Circuit1->cell; ob1 && IsPort(ob1); ob1 = ob1->next, P1++);
for (ob2 = Circuit2->cell; ob2 && IsPort(ob2); ob2 = ob2->next, P2++);
if (P1 == P2) { // pin counts match. Make sure disconnected pins match, too.
for (ob1 = Circuit1->cell; ob1 && IsPort(ob1); ob1 = ob1->next) {
if (ob1->node == -1) { // disconnected pin
for (ob2 = Circuit2->cell; ob2 && IsPort(ob2); ob2 = ob2->next) {
if (ob2->node == -1 && (*matchfunc)(ob1->name, ob2->name))
break; // disconnected pin match
}
if (ob2 == NULL) return -2;
}
}
}
else { // pin count mismatch
return -2;
}
}
return(ret);
}
@@ -6318,7 +6352,7 @@ int ResolveAutomorphsByPin()
FractureElementClass(&ElementClasses);
FractureNodeClass(&NodeClasses);
ExhaustiveSubdivision = 1;
while (!Iterate() && VerifyMatching() != -1);
while (!Iterate() && VerifyMatching() >= 0);
return(VerifyMatching());
}
@@ -6421,7 +6455,7 @@ int ResolveAutomorphsByProperty()
FractureElementClass(&ElementClasses);
FractureNodeClass(&NodeClasses);
ExhaustiveSubdivision = 1;
while (!Iterate() && VerifyMatching() != -1);
while (!Iterate() && VerifyMatching() >= 0);
return(VerifyMatching());
}
@@ -6498,7 +6532,7 @@ int ResolveAutomorphisms()
FractureElementClass(&ElementClasses);
FractureNodeClass(&NodeClasses);
ExhaustiveSubdivision = 1;
while (!Iterate() && VerifyMatching() != -1);
while (!Iterate() && VerifyMatching() >= 0);
return(VerifyMatching());
}
@@ -7193,44 +7227,46 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
return NULL; /* Keep the search going */
}
/*------------------------------------------------------*/
/* Declare that the device class "name1" is equivalent */
/* to class "name2". This is the same as the above */
/* routine, except that the cells must be at the top */
/* of the compare queue, and must already be proven */
/* equivalent by LVS. Determine a pin correspondence, */
/* then modify all instances of "name2" to match all */
/* instances of "name1" by pin reordering. If either */
/* cell has disconnected pins, they are shuffled to the */
/* end of the pin list. If two or more pins correspond */
/* to net automorphisms, then they are added to the */
/* list of permuted pins. */
/* */
/* NOTE: This routine must not be called on any */
/* circuit pair that has not been matched. If a */
/* circuit pair has been matched with automorphisms, */
/* then some pins may be matched arbitrarily. */
/* */
/* If "dolist" is 1, append the list representing the */
/* output (if any) to variable tcl_out, if it exists. */
/* */
/* Return codes: */
/* 2: Neither cell had pins, so matching is unnecessary */
/* 1: Exact match */
/* 0: Inexact match resolved by proxy pin insertion */
/*------------------------------------------------------*/
/*--------------------------------------------------------------*/
/* Declare that the device class "name1" is equivalent to class */
/* "name2". This is the same as the above routine, except that */
/* the cells must be at the top of the compare queue, and must */
/* already be proven equivalent by LVS. Determine a pin */
/* correspondence, then modify all instances of "name2" to */
/* match all instances of "name1" by pin reordering. If either */
/* cell has disconnected pins, they are shuffled to the end of */
/* the pin list. If two or more pins correspond to net */
/* automorphisms, then they are added to the list of permuted */
/* pins. */
/* */
/* NOTE: This routine must not be called on any circuit pair */
/* that has not been matched. If a circuit pair has been */
/* matched with automorphisms, then some pins may be matched */
/* arbitrarily. */
/* */
/* If "dolist" is 1, append the list representing the output */
/* (if any) to variable tcl_out, if it exists. */
/* */
/* Return codes: */
/* 2: Neither cell had pins, so matching is unnecessary */
/* 1: Exact match */
/* 0: Circuit match w/pin name mismatch. Force a match. */
/* -1: Pin mismatch. Flatten cell. */
/*--------------------------------------------------------------*/
int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
{
char *cover, *ctemp;
char *bangptr1, *bangptr2;
char *cover1, *cover2, *ctemp;
char *bangptr1, *bangptr2, *backslashptr1, *backslashptr2;
struct objlist *ob1, *ob2, *obn, *obp, *ob1s, *ob2s, *obt;
struct NodeClass *NC;
struct Node *N1, *N2;
int i, j, k, m, a, b, swapped, numnodes, numorig;
int i, j, k, m, a, b, swapped, numnodes, numnodes2, numorig;
int result = 1, haspins = 0, notempty = 0;
int hasproxy1 = 0, hasproxy2 = 0;
int needclean1 = 0, needclean2 = 0;
int hasDevices1, hasDevices2;
int isBlackBox1, isBlackBox2;
char *ostr;
#ifdef TCL_NETGEN
Tcl_Obj *mlist, *plist1, *plist2;
@@ -7239,10 +7275,12 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (tc1 == NULL) tc1 = Circuit1;
if (tc2 == NULL) tc2 = Circuit2;
numnodes2 = 0;
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
if (ob2->type != PORT) break;
else haspins = 1;
ob2->model.port = -1;
numnodes2++;
}
numnodes = 0;
for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next) {
@@ -7257,7 +7295,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
return 2;
}
cover = (char *)CALLOC(numnodes, sizeof(char));
cover1 = (char *)CALLOC(numnodes, sizeof(char));
cover2 = (char *)CALLOC(numnodes2, sizeof(char));
numorig = numnodes;
#ifdef TCL_NETGEN
@@ -7290,187 +7329,195 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
}
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
a = 0;
a = 0; // circuit1 node offset
for (N1 = NC->nodes; N1 != NULL; N1 = N1->next) {
if (N1->graph == Circuit1->file) {
obn = N1->object;
b = 0; // circuit2 node offset
for (N2 = NC->nodes; N2 != NULL; N2 = N2->next) {
if (N2->graph != Circuit1->file) {
if (b == a) break;
else b++;
}
}
if (N2 == NULL) { // This should never occur in matched nets
continue;
}
else {
obp = N2->object;
}
ob1 = NULL;
if (IsPort(obn)) {
i = 0;
for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next, i++) {
if ((IsPort(ob1))
&& (*matchfunc)(ob1->name, obn->name)) {
b = 0;
for (N2 = NC->nodes; N2 != NULL; N2 = N2->next) {
if (N2->graph != Circuit1->file) {
if (b == a) break;
else b++;
}
}
if (N2 == NULL) {
#ifdef TCL_NETGEN
if (dolist) {
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL,
Tcl_NewStringObj("pins", -1),
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, mlist,
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
}
#endif
FREE(ostr);
return 1;
}
obp = N2->object;
j = 0;
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next, j++) {
if ((IsPort(ob2))
&& (*matchfunc)(ob2->name, obp->name)) {
if (Debug == 0) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "%s", obn->name);
if ((*matchfunc)(obn->name, obp->name))
snprintf(ostr + left_col_end + 1, left_col_end, "%s", obp->name);
else {
snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", obp->name);
/* Pins with different names are on different nets,
* so this should trigger an error return code.
*/
result = 0;
}
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
}
else {
Fprintf(stdout, "Circuit %s port %d \"%s\""
" = cell %s port %d \"%s\"\n",
tc1->name, i, obn->name,
tc2->name, j, obp->name);
}
#ifdef TCL_NETGEN
if (dolist) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj(obn->name, -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj(obp->name, -1));
}
#endif
ob2->model.port = i; /* save order */
*(cover + i) = (char)1;
break;
}
}
if (ob2 == NULL) {
if (Debug == 0) {
// If first cell has no pins but 2nd cell
// does, then "no matching pin" entries will
// be generated for all pins in the 2nd cell,
// so don't print out the "no pins" entry.
if (strcmp(obn->name, "(no pins)")) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, 32, "%s", obn->name);
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
}
}
else {
Fprintf(stderr, "No matching pin in cell %s for "
"cell %s pin %s\n",
tc2->name, tc1->name, obn->name);
}
#ifdef TCL_NETGEN
if (dolist && strcmp(obn->name, "(no pins)")) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj(obn->name, -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj("(no matching pin)", -1));
}
#endif
result = 0;
/* Make a pass through circuit 1 to find out if */
/* the pin really is connected to anything, or */
/* has been left orphaned after flattening. If */
/* disconnected, set its node number to -2. */
notempty = 0;
for (obt = ob1->next; obt; obt = obt->next) {
if (obt->type >= FIRSTPIN) {
notempty = 1;
if (obt->node == ob1->node)
break;
}
}
if ((obt == NULL) && (notempty == 1)) {
ob1->node = -2; // Will run this through cleanuppins
needclean1 = 1;
}
}
if ((IsPort(ob1)) && (*matchfunc)(ob1->name, obn->name)) {
break;
}
}
*(cover1 + i) = (char)1;
}
ob2 = NULL;
if (obp && IsPort(obp)) {
j = 0;
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next, j++) {
if ((IsPort(ob2)) && (*matchfunc)(ob2->name, obp->name)) {
break;
}
}
*(cover2 + j) = (char)1;
}
if (ob1 == NULL) {
if (Debug == 0) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
if (Debug == 0) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
if (ob1 && ob2) { // both pins are in both circuits
if (NC->legalpartition) { // nets match
snprintf(ostr, left_col_end, "%s", obn->name);
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
if ((*matchfunc)(obn->name, obp->name))
/* MatchPins - case 1: portA(0) = portA(1)
* Pin names match
*/
snprintf(ostr + left_col_end + 1, left_col_end,
"%s", obp->name);
else {
/* MatchPins - case 2: portA(0) = portb(1)
* circuits match but the pin names don't.
*/
snprintf(ostr + left_col_end + 1, left_col_end,
"%s **Mismatch**", obp->name);
/* Pins with different names are on different nets,
* so this should trigger an error return code.
*/
result = (result == 1) ? 0 : result; // only set if 1
}
ob2->model.port = i; /* save the order */
}
else {
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
tc1->name, obn->name);
snprintf(ostr, left_col_end, "*%s", obn->name);
snprintf(ostr + left_col_end + 1, left_col_end,
"*%s **Mismatch**", obp->name);
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
result = -1;
}
#ifdef TCL_NETGEN
if (dolist) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj(obn->name, -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj("(no matching pin)", -1));
}
else if (ob1) { // implies (&& !ob2)
/* MatchPins - case 3: portA(0) = netA(1)
* circuits match but circuit2 is missing pin
*/
snprintf(ostr, left_col_end, "%s", obn->name);
if (NC->legalpartition) { // net match
snprintf(ostr + left_col_end + 1, left_col_end,
"*%s **not a pin**", obp->name);
}
#endif
result = 0;
else {
snprintf(ostr + left_col_end + 1, left_col_end,
"*%s **Mismatch**", obp->name);
}
result = -1;
}
else if (ob2) { // imples (&& !ob1)
/* MatchPins - case 4: netA(0) = portA(1)
* circuits match but circuit1 is missing pin
*/
if (NC->legalpartition) { // net match
snprintf(ostr, left_col_end, "*%s **not pin**", obn->name);
}
else {
snprintf(ostr, left_col_end, "*%s **Mismatch**", obn->name);
}
snprintf(ostr + left_col_end + 1, left_col_end, "%s", obp->name);
result = -1;
}
if (ob1 || ob2) {
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
}
}
else {
Fprintf(stdout, "Circuit %s port %d \"%s\""
" = cell %s port %d \"%s\"\n",
tc1->name, i, (obn) ? obn->name : "",
tc2->name, j, (obp) ? obp->name : "");
}
#ifdef TCL_NETGEN
if (dolist) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj((obn) ? obn->name : "", -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj((obp) ? obp->name : "", -1));
}
#endif
a++;
}
}
}
/* Check for unconnected nodes in tc1 */
for (ob1 = tc1->cell; ob1 && IsPort(ob1); ob1 = ob1->next) {
if (ob1->node >= 0) {
/* Check if ob1->node might really be disconnected */
for (obn = ob1->next; obn; obn = obn->next) {
if (obn->node == ob1->node) break;
}
if (obn == NULL) ob1->node = -1; // Make disconnected
}
}
/* Check for unconnected nodes in tc2 */
for (ob2 = tc2->cell; ob2 && IsPort(ob2); ob2 = ob2->next) {
if (ob2->node >= 0) {
/* Check if ob2->node might really be disconnected */
for (obp = ob2->next; obp; obp = obp->next) {
if (obp->node == ob2->node) break;
}
if (obp == NULL) ob2->node = -1; // Make disconnected
}
}
/* Do any unmatched pins have the same name? */
/* This should not happen if unconnected pins are eliminated */
/* so apply only to black-box (CELL_PLACEHOLDER) entries. */
/* (Semi-hack: Allow "!" global flag) */
/* (Semi-hack: Allow "!" global flag) */
/* (Another semi-hack: Ignore the leading backslash in */
/* backslash-escaped verilog names. Removing the backslash */
/* and ending space character is a common way to convert to */
/* legal SPICE. */
ob1 = tc1->cell;
bangptr1 = strrchr(ob1->name, '!');
if (bangptr1 && (*(bangptr1 + 1) == '\0'))
*bangptr1 = '\0';
else bangptr1 = NULL;
isBlackBox1 = (tc1->flags & CELL_PLACEHOLDER);
isBlackBox2 = (tc2->flags & CELL_PLACEHOLDER);
for (i = 0; i < numorig; i++) {
if (*(cover + i) == (char)0) {
bangptr1 = strrchr(ob1->name, '!');
if (bangptr1 && (*(bangptr1 + 1) == '\0'))
*bangptr1 = '\0';
else bangptr1 = NULL;
backslashptr1 = (*(ob1->name) == '\\') ? ob1->name + 1 : ob1->name;
if (*(cover1 + i) == (char)0) {
j = 0;
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next, j++) {
char *name1, *name2;
if (!IsPort(ob2)) break;
if (*(cover2 + j) == (char)1) continue; // port was processed
bangptr2 = strrchr(ob2->name, '!');
if (bangptr2 && (*(bangptr2 + 1) == '\0'))
*bangptr2 = '\0';
else bangptr2 = NULL;
name1 = ob1->name;
name2 = ob2->name;
backslashptr2 = (*(ob2->name) == '\\') ? ob2->name + 1 : ob2->name;
name1 = backslashptr1;
name2 = backslashptr2;
/* Recognize proxy pins as matching unconnected pins */
if (!strncmp(name1, "proxy", 5) && (ob2->node == -1)) name1 +=5;
@@ -7484,18 +7531,23 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
/* matched by name. */
if (((ob1->node == -1) && (ob2->node == -1)) ||
(((tc1->flags & CELL_PLACEHOLDER) &&
(tc2->flags & CELL_PLACEHOLDER)) ||
(NodeClasses == NULL))) {
(isBlackBox1 && isBlackBox2) ||
(NodeClasses == NULL)) {
ob2->model.port = i; /* save order */
*(cover + i) = (char)1;
*(cover1 + i) = (char)1;
*(cover2 + j) = (char)1;
if (Debug == 0) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "%s", ob1->name);
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
snprintf(ostr, left_col_end, "%s%s", ob1->name,
(ob1->node == -1 && !isBlackBox1) ?
" (disconnected)" : "");
snprintf(ostr + left_col_end + 1, left_col_end,
"%s%s", ob2->name,
(ob2->node == -1 && !isBlackBox2) ?
" (disconnected)" : "");
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
@@ -7519,7 +7571,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
}
}
if (bangptr2) *bangptr2 = '!';
j++;
}
}
ob1 = ob1->next;
@@ -7538,8 +7589,9 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
/* connections in the cell to the end. Create pins */
/* in tc1 to match. */
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
for (j = 0, ob2 = tc2->cell; ob2 != NULL; j++, ob2 = ob2->next) {
if (ob2->type != PORT) break;
if (*(cover2 + j) == (char)1) continue; // port was processed
if (ob2->model.port == -1) {
if (Debug == 0) {
@@ -7547,8 +7599,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (strcmp(ob2->name, "(no pins)")) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "(no matching pin)");
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
snprintf(ostr, left_col_end, "**no match**");
snprintf(ostr + left_col_end + 1, left_col_end,
"%s%s", ob2->name,
(ob2->node == -1) ? " (disconnected)" : "");
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
@@ -7559,80 +7613,12 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
tc2->name, ob2->name);
}
/* Before making a proxy pin, check to see if */
/* flattening instances has left a port with a */
/* net number that doesn't connect to anything */
notempty = 0;
for (obt = ob2->next; obt; obt = obt->next) {
if (obt->type >= FIRSTPIN) {
notempty = 1;
if (obt->node == ob2->node)
break;
}
}
if ((obt == NULL) && (notempty == 1)) {
ob2->node = -2; // Will run this through cleanuppins
needclean2 = 1;
/* On the top level, missing pins are an error, even if */
/* they appear to match unconnected pins on the other side. */
if (CompareQueue == NULL)
result = 0;
#ifdef TCL_NETGEN
if (dolist) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj("(no pin)", -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj(ob2->name, -1));
}
#endif
continue;
}
else if (notempty == 1) {
/* Flag this as an error */
result = 0;
#ifdef TCL_NETGEN
if (dolist) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj("(no matching pin)", -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj(ob2->name, -1));
}
#endif
}
ob2->model.port = numnodes++; // Assign a port order
/* Add a proxy pin to tc1 */
/* Technically, this should have a matching net number. */
/* But nothing connects to it, so it is only needed to */
/* make sure the "pin magic" numbers are correctly */
/* assigned to both cells. */
obn = (struct objlist *)CALLOC(1, sizeof(struct objlist));
obn->name = (char *)MALLOC(6 + strlen(ob2->name));
sprintf(obn->name, "proxy%s", ob2->name);
obn->type = UNKNOWN;
// obn->model.port = -1;
obn->instance.name = NULL;
obn->node = -1;
if (ob1 == tc1->cell) {
obn->next = ob1;
tc1->cell = obn;
}
else {
obn->next = ob1->next;
ob1->next = obn;
}
ob1 = obn;
hasproxy1 = 1;
HashPtrInstall(obn->name, obn, &(tc1->objdict));
result = -1;
}
}
/* Find the end of the pin list in tc2, for adding proxy pins */
/* Find the end of the pin list in tc2 */
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
if (ob2 && ((ob2->next && ob2->next->type != PORT) || ob2->next == NULL))
@@ -7645,97 +7631,55 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
/* sequence, then fill in the missing numbers. Otherwise, add the */
/* extra nodes to the end. */
j = 0;
for (i = 0; i < numorig; i++) {
if (*(cover + i) == (char)1) continue;
for (i = 0, ob1 = tc1->cell; i < numorig; i++, ob1 = ob1->next) {
if (*(cover1 + i) == (char)1) continue;
/* If the equivalent node in tc1 is not disconnected */
/* (node != -1) then we should report a match error, */
/* although this does not necessarily imply an error in */
/* netlist connectivity. */
ob1 = tc1->cell;
for (k = i; k > 0 && ob1 != NULL; k--)
ob1 = ob1->next;
if (ob1 == NULL || ob1->type != PORT || ob1->node >= 0) {
/* Check if ob1->node might really be disconnected */
for (obn = ob1->next; obn; obn = obn->next) {
if (obn->node == ob1->node) break;
/* Note: Has this pin already been accounted for? */
if (Debug == 0) {
if (strcmp(ob1->name, "(no pins)")) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "%s%s", ob1->name,
(ob1->node == -1) ? " (disconnected)" : "");
snprintf(ostr + left_col_end + 1, left_col_end, "**no match**");
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
}
if (obn == NULL) ob1->node = -1; /* Make disconnected */
result = -1;
}
if (ob1 == NULL || ob1->type != PORT || ob1->node >= 0
|| (ob1->node < 0 && tc1->class == CLASS_MODULE)
|| (ob1->node < 0 && ob1->model.port == -1)) {
/* Add a proxy pin to tc2 */
obn = (struct objlist *)CALLOC(1, sizeof(struct objlist));
if (ob1 == NULL) {
obn->name = (char *)MALLOC(15);
sprintf(obn->name, "proxy%d", rand() & 0x3ffffff);
}
else {
obn->name = (char *)MALLOC(6 + strlen(ob1->name));
sprintf(obn->name, "proxy%s", ob1->name);
}
obn->type = UNKNOWN;
obn->model.port = (i - j);
obn->instance.name = NULL;
obn->node = -1;
/* Note: Has this pin already been accounted for? */
if (Debug == 0) {
if (strcmp(ob1->name, "(no pins)")) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "%s", ob1->name);
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
}
}
else {
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
tc1->name, ob1->name);
}
if (ob2 == tc2->cell) {
obn->next = ob2;
tc2->cell = obn;
}
else {
obn->next = ob2->next;
ob2->next = obn;
}
ob2 = obn;
hasproxy2 = 1;
HashPtrInstall(obn->name, obn, &(tc2->objdict));
}
else if (ob1 != NULL && ob1->type == PORT) {
/* Disconnected node was not meaningful, has no pin match in */
/* the compared circuit, and so should be discarded. */
ob1->node = -2;
needclean1 = 1;
/* Adjust numbering around removed node */
for (ob2s = tc2->cell; ob2s != NULL && ob2s->type == PORT; ob2s = ob2s->next) {
if (ob2s->model.port > (i - j)) ob2s->model.port--;
}
j++;
else {
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
tc1->name, ob1->name);
}
}
FREE(cover);
FREE(cover1);
FREE(cover2);
if (Debug == 0) {
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
Fprintf(stdout, ostr);
}
hasDevices1 = hasDevices2 = 0;
for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next) {
if (ob1->type == FIRSTPIN) {
hasDevices1 = 1;
break;
}
}
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
if (ob2->type == FIRSTPIN) {
hasDevices2 = 1;
break;
}
}
if (hasDevices1 != hasDevices2)
result = -2; // Attempt to compare empty cell to non-empty cell
if (result < 0) return result;
/* Run cleanuppins on circuit 1 */
if (needclean1) {
CleanupPins(tc1->name, tc1->file);
@@ -7775,7 +7719,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
}
/* Check for ports that did not get ordered */
for (obn = tc2->cell; obn && (obn->type == PORT); obn = obn->next) {
for (obn = tc2->cell; obn && IsPort(obn); obn = obn->next) {
if (obn->model.port == -1) {
if (obn->node == -1) {
// This only happens when pins have become separated from any net.
@@ -7953,10 +7897,12 @@ int EquivalentElement(char *name, struct nlist *circuit, struct objlist **retobj
void FlattenCurrent()
{
if (Circuit1 != NULL && Circuit2 != NULL) {
Fprintf(stdout, "Flattening subcell %s\n", Circuit1->name);
Fprintf(stdout, "Flattening subcell %s (%d)\n", Circuit1->name,
Circuit1->file);
FlattenInstancesOf(Circuit1->name, Circuit1->file);
Fprintf(stdout, "Flattening subcell %s\n", Circuit2->name);
Fprintf(stdout, "Flattening subcell %s (%d)\n", Circuit2->name,
Circuit2->file);
FlattenInstancesOf(Circuit2->name, Circuit2->file);
}
}
@@ -8027,7 +7973,25 @@ int Compare(char *cell1, char *cell2)
PrintIllegalClasses();
return(0);
}
if (automorphisms == 0) Fprintf(stdout, "Circuits match correctly.\n");
if (automorphisms > 0) {
Fprintf(stdout, "Circuits match with %d symmetries.\n", automorphisms);
if (VerboseOutput) PrintAutomorphisms();
/* arbitrarily resolve automorphisms */
Fprintf(stdout, "\n");
Fprintf(stdout, "Resolving automorphisms by arbitrary symmetry breaking:\n");
while ((automorphisms = ResolveAutomorphisms()) > 0) ;
if (automorphisms == -1) {
MatchFail(cell1, cell2);
Fprintf(stdout, "Circuits do not match.\n");
return 0;
}
}
if (automorphisms == -2) { // Port count mismatch
Fprintf(stderr, "Port counts do not match.\n");
return 0;
}
if (PropertyErrorDetected == 1) {
Fprintf(stdout, "There were property errors.\n");
PrintPropertyResults(0);
@@ -8036,22 +8000,10 @@ int Compare(char *cell1, char *cell2)
Fprintf(stdout, "There were missing properties.\n");
PrintPropertyResults(0);
}
if (automorphisms == 0) return(1);
else
Fprintf(stdout, "Circuits match correctly.\n");
Fprintf(stdout, "Circuits match with %d automorphisms.\n", automorphisms);
if (VerboseOutput) PrintAutomorphisms();
/* arbitrarily resolve automorphisms */
Fprintf(stdout, "\n");
Fprintf(stdout, "Resolving automorphisms by arbitrary symmetry breaking:\n");
while ((automorphisms = ResolveAutomorphisms()) > 0) ;
if (automorphisms == -1) {
MatchFail(cell1, cell2);
Fprintf(stdout, "Circuits do not match.\n");
return(0);
}
Fprintf(stdout, "Circuits match correctly.\n");
return(1);
return 1;
}
@@ -8105,9 +8057,12 @@ void NETCOMP(void)
PrintIllegalClasses();
Fprintf(stdout, "Netlists do not match.\n");
}
else if (automorphisms == -2) { // port count mismatch
Fprintf(stdout, "Port counts do not match.\n");
}
else {
if (automorphisms)
Printf("Circuits match with %d automorphisms.\n", automorphisms);
Printf("Circuits match with %d symmetries.\n", automorphisms);
else Printf("Circuits match correctly.\n");
}
}
@@ -8120,11 +8075,13 @@ void NETCOMP(void)
while (!Iterate()) ;
automorphisms = VerifyMatching();
if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n");
else if (automorphisms == -2) Fprintf(stdout, "Port counts do not match.\n");
else {
Printf("Netlists match with %d automorphisms.\n", automorphisms);
Printf("Netlists match with %d symmetries.\n", automorphisms);
while ((automorphisms = ResolveAutomorphisms()) > 0)
Printf(" automorphisms = %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");
}
}
+15 -2
View File
@@ -1449,7 +1449,20 @@ skip_ends:
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
if (LookupObject(neg, CurrentCell) == NULL) Node(neg);
/* Any device properties? */
/* Get voltage value (if present); save as property "value" */
if (nexttok != NULL) {
if (matchnocase(nexttok, "DC")) {
SpiceTokNoNewline();
}
}
if (nexttok != NULL) {
if (StringIsValueOrExpression(nexttok)) {
AddProperty(&kvlist, "value", nexttok);
}
}
/* Any other device properties? */
while (nexttok != NULL)
{
SpiceTokNoNewline();
@@ -1477,7 +1490,7 @@ skip_ends:
else if (CountPorts(model, filenum) != 2) {
/* Modeled device: Make sure it has the right number of ports */
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a "
"voltage source.\n");
"voltage source.\n", inst);
goto baddevice;
}
Cell(instname, model, pos, neg);
+5 -1
View File
@@ -1669,7 +1669,7 @@ nextinst:
// Read the pin list
while (nexttok != NULL) {
SkipTokComments(VLOG_DELIMITERS);
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
if (match(nexttok, ")")) break;
else if (match(nexttok, ",")) continue;
@@ -2228,6 +2228,9 @@ nextinst:
obptr->next = nobj;
HashPtrInstall(nobj->name, nobj, &(CurrentCell->objdict));
/* Ensure that CurrentTail is correct */
if (obptr == CurrentTail) CurrentTail = nobj;
if (LookupObject(scan->net, CurrentCell) == NULL)
Node(scan->net);
join(scan->net, nobj->name);
@@ -2269,6 +2272,7 @@ nextinst:
}
}
}
obptr = obptr->next;
}
else {
Fprintf(stderr, "Error: Instance %s has pin %s which is "
+110 -86
View File
@@ -62,16 +62,18 @@ proc netgen::convert_to_json {filename lvs_final} {
puts $fjson " \["
set cktval [lindex $value 0]
foreach pin [lrange $cktval 0 end-1] {
puts $fjson " \"$pin\","
set pinstr [string map {"\\" "\\\\"} $pin]
puts $fjson " \"$pinstr\","
}
set pin [lindex $cktval end]
set pin [string map {"\\" "\\\\"} [lindex $cktval end]]
puts $fjson " \"$pin\""
puts $fjson " \], \["
set cktval [lindex $value 1]
foreach pin [lrange $cktval 0 end-1] {
puts $fjson " \"$pin\","
set pinstr [string map {"\\" "\\\\"} $pin]
puts $fjson " \"$pinstr\","
}
set pin [lindex $cktval end]
set pin [string map {"\\" "\\\\"} [lindex $cktval end]]
puts $fjson " \"$pin\""
puts $fjson " \]"
if {$kidx == $nkeys} {
@@ -393,7 +395,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
# If argument is a filename then read the list of cells from it;
# otherwise, argument is the list of files itself in quotes or
# braces.
if {![catch {file exists $value}]} {
if {[file exists $value]} {
if {![catch {open $value r} fnf]} {
while {[gets $fnf line] >= 0} {
if {[lindex $line 0] != "#"} {
@@ -532,14 +534,24 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
}
set properr {}
set matcherr {}
set pinsgood -1
set childMismatch 0 ;# 1 indicates black-box child subcircuit mismatch
while {$endval != {}} {
if {$dolist == 1} {
netgen::run -list converge
} else {
netgen::run converge
}
netgen::log echo on
set pinMismatch 0 ;# indicates pin mismatch in top cell
set doCheckFlatten 0
set doFlatten 0
if {[netgen::print queue] == {}} {
set doEquatePins 1 ;# run equate pins on top cell
} else {
set doEquatePins 0 ;# don't run equate pins unless unique match
}
set forceMatch 0 ;# for pin matching
netgen::log echo off
if {[verify equivalent]} {
# Resolve automorphisms by pin and property
if {$dolist == 1} {
@@ -548,96 +560,105 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
netgen::run resolve
}
set uresult [verify unique]
# uresult: -3 : unique with property error
# -2 : equivalent with port errors
# -1 : black box
# 0 : equivalent but not unique
# 1 : unique
if {$uresult == 0} {
netgen::log echo on
netgen::log put " Networks match locally but not globally.\n"
netgen::log put " Probably connections are swapped.\n"
netgen::log put " Check the end of logfile ${logfile} for implicated nodes.\n"
netgen::log echo off
if {$dolist == 1} {
verify -list nodes
} else {
verify nodes
}
# Flatten the non-matching subcircuit (but not the top-level cells)
if {[netgen::print queue] != {}} {
if {([lsearch $noflat [lindex $endval 0]] == -1) &&
([lsearch $noflat [lindex $endval 1]] == -1)} {
netgen::log put " Flattening non-matched subcircuits $endval\n"
netgen::flatten class "[lindex $endval 0] $fnum1"
netgen::flatten class "[lindex $endval 1] $fnum2"
} else {
netgen::log put " Continuing with black-boxed subcircuits $endval\n"
lappend matcherr [lindex $endval 0]"($fnum1)"
lappend matcherr [lindex $endval 1]"($fnum2)"
# Match pins
netgen::log echo off
if {$dolist == 1} {
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
} else {
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
}
if {$result != 0} {
equate classes "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"
}
set pinsgood $result
netgen::log echo on
}
}
set doCheckFlatten 1
} else {
netgen::log echo off
if {$dolist == 1} {
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
} else {
set result [equate pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
}
if {$result != 0} {
equate classes "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"
}
# If $uresult == -1 then these are black-box entries and
# $pinsgood should not be set to the resulting value.
if {$uresult > 0} {
set pinsgood $result
}
netgen::log echo on
# Equate pins for black boxes, unique matches (possibly with property
# errors), and unique with port errors
set doEquatePins 1
}
if {$uresult == -1} { ;# black box
set forceMatch 1
} elseif {$uresult == -3} { ;# property error
lappend properr [lindex $endval 0]
} elseif {$uresult == -2} { ;# unmatched pins
set doCheckFlatten 1
}
if {$uresult == 2} {lappend properr [lindex $endval 0]}
} else {
# Flatten the non-matching subcircuit (but not the top-level cells)
if {[netgen::print queue] != {}} {
# not equivalent
netgen::log echo on
# netgen::log put " DEBUG: not equivalent $endval\n"
netgen::log echo off
set doCheckFlatten 1
}
if {$doCheckFlatten} {
# Flatten the non-matching subcircuit (but not the top-level cell,
# or cells explicitly prohibited from flattening)
if {[netgen::print queue] != {}} {
if {([lsearch $noflat [lindex $endval 0]] == -1) &&
([lsearch $noflat [lindex $endval 1]] == -1)} {
netgen::log put " Flattening non-matched subcircuits $endval\n"
netgen::flatten class "[lindex $endval 0] $fnum1"
netgen::flatten class "[lindex $endval 1] $fnum2"
} else {
([lsearch $noflat [lindex $endval 1]] == -1)} {
set doFlatten 1
} else {
netgen::log echo on
netgen::log put " Continuing with black-boxed subcircuits $endval\n"
netgen::log echo off
lappend matcherr [lindex $endval 0]"($fnum1)"
lappend matcherr [lindex $endval 0]"($fnum2)"
# Match pins
netgen::log echo off
if {$dolist == 1} {
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
} else {
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
}
if {$result != 0} {
equate classes "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"
}
set pinsgood $result
netgen::log echo on
lappend matcherr [lindex $endval 1]"($fnum2)"
netgen::flatten prohibit "[lindex $endval 0] $fnum1"
netgen::flatten prohibit "[lindex $endval 1] $fnum2"
set doEquatePins 1
set childMismatch 1
set forceMatch 1
}
}
}
netgen::log echo off
if {$doEquatePins} {
# Match pins
if {$dolist == 1} {
if {$forceMatch} {
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
} else {
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
}
} else {
if {$forceMatch} {
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
} else {
set result [equate pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
}
}
if {$result >= 0} {
equate classes "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"
}
# Do not set pinMismatch for black boxes
if {$result < 0} {
if {$result == -1 && [netgen::print queue] != {} && $forceMatch != 1} {
# flatten pin mismatch, but not empty cells (-2) or top cell or
# cells prohibited from flattening.
set doFlatten 1
}
} elseif {[netgen::print queue] == {} && $result == 0} {
set pinMismatch 1
}
}
if {$doFlatten} {
netgen::log echo on
netgen::log put " Flattening non-matched subcircuits $endval\n"
netgen::log echo off
netgen::flatten class "[lindex $endval 0] $fnum1"
netgen::flatten class "[lindex $endval 1] $fnum2"
}
if {$dolist == 1} {
catch {lappend lvs_final $lvs_out}
set lvs_out {}
@@ -646,20 +667,23 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set endval [netgen::compare hierarchical]
}
}
netgen::log echo off
puts stdout "Result: " nonewline
netgen::log echo on
if {$pinsgood == 0} {
# NOTE: Need to disambiguate these two cases. . .
netgen::log put "Cells failed matching, or top level cell failed pin matching.\n"
netgen::log put "\nFinal result: "
if {$pinMismatch || $childMismatch} {
if {$childMismatch} {
netgen::log put "Subcell(s) failed matching.\n"
}
if {$pinMismatch} {
netgen::log put "Top level cell failed pin matching.\n"
}
} else {
verify only
}
if {$properr != {}} {
netgen::log put "The following cells had property errors:\n " [regsub -all { } $properr "\n "] "\n"
netgen::log put "\nThe following cells had property errors:\n " [regsub -all { } $properr "\n "] "\n"
}
if {$matcherr != {}} {
netgen::log put "The following subcells failed to match:\n " [regsub -all { } $matcherr "\n "] "\n"
netgen::log put "\nThe following subcells failed to match:\n " [regsub -all { } $matcherr "\n "] "\n"
}
if {$dolog} {
netgen::log end
+79 -32
View File
@@ -1056,6 +1056,12 @@ _netgen_flatten(ClientData clientData,
FlattenInstancesOf(repstr, filenum);
}
}
else if (!strcmp(argv, "prohibit") || !strcmp(argv, "deny")) {
tp = GetTopCell(filenum);
Printf("Will not flatten instances of %s in file %s\n", repstr, tp->name);
/* Mark cell as placeholder so it will not be flattened */
tp->flags |= CELL_PLACEHOLDER;
}
else {
Tcl_WrongNumArgs(interp, 1, objv, "class valid_cellname");
return TCL_ERROR;
@@ -1931,9 +1937,17 @@ _netgen_log(ClientData clientData,
switch(index) {
case START_IDX:
LoggingFile = fopen(LogFileName, "w");
if (!LoggingFile) {
Tcl_SetResult(interp, "Could not open log file.", NULL);
return TCL_ERROR;
}
break;
case RESUME_IDX:
LoggingFile = fopen(LogFileName, "a");
if (!LoggingFile) {
Tcl_SetResult(interp, "Could not open log file.", NULL);
return TCL_ERROR;
}
break;
case END_IDX:
fclose(LoggingFile);
@@ -1942,6 +1956,10 @@ _netgen_log(ClientData clientData,
case RESET_IDX:
fclose(LoggingFile);
LoggingFile = fopen(LogFileName, "w");
if (!LoggingFile) {
Tcl_SetResult(interp, "Could not open log file.", NULL);
return TCL_ERROR;
}
break;
case SUSPEND_IDX:
fclose(LoggingFile);
@@ -2203,11 +2221,11 @@ _netcmp_compare(ClientData clientData,
hascontents2 = HasContents(tp2);
if (hascontents1 && !hascontents2 && (tp2->flags & CELL_PLACEHOLDER)) {
Fprintf(stdout, "Circuit 2 cell %s is a black box; will not flatten "
Fprintf(stdout, "\nCircuit 2 cell %s is a black box; will not flatten "
"Circuit 1\n", name2);
}
else if (hascontents2 && !hascontents1 && (tp1->flags & CELL_PLACEHOLDER)) {
Fprintf(stdout, "Circuit 1 cell %s is a black box; will not flatten "
Fprintf(stdout, "\nCircuit 1 cell %s is a black box; will not flatten "
"Circuit 2\n", name1);
}
else if (hascontents1 || hascontents2) {
@@ -2223,6 +2241,10 @@ _netcmp_compare(ClientData clientData,
DescribeContents(name1, fnum1, name2, fnum2);
}
}
else { /* Two empty subcircuits */
Fprintf(stdout, "\nCircuit 1 cell %s and Circuit 2 cell %s are black"
" boxes.\n", name1, name2);
}
CreateTwoLists(name1, fnum1, name2, fnum2, dolist);
// Return the names of the two cells being compared, if doing "compare
@@ -2479,39 +2501,37 @@ _netcmp_run(ClientData clientData,
ExhaustiveSubdivision = 1;
while (!Iterate() && !InterruptPending);
automorphisms = VerifyMatching();
if (automorphisms == -1)
Fprintf(stdout, "Netlists do not match.\n");
else if (automorphisms == 0)
Fprintf(stdout, "Netlists match uniquely.\n");
else {
if (automorphisms > 0) {
// First try to resolve automorphisms uniquely using
// property matching
automorphisms = ResolveAutomorphsByProperty();
if (automorphisms == 0)
Fprintf(stdout, "Netlists match uniquely.\n");
else if (automorphisms > 0) {
if (automorphisms > 0) {
// Next, attempt to resolve automorphisms uniquely by
// using the pin names
automorphisms = ResolveAutomorphsByPin();
}
if (automorphisms == 0)
Fprintf(stdout, "Netlists match uniquely.\n");
else if (automorphisms > 0) {
if (automorphisms > 0) {
// Anything left is truly indistinguishable
Fprintf(stdout, "Netlists match with %d symmetr%s.\n",
automorphisms, (automorphisms == 1) ? "y" : "ies");
while ((automorphisms = ResolveAutomorphisms()) > 0);
while (ResolveAutomorphisms() > 0);
}
if (automorphisms == -1)
Fprintf(stdout, "Netlists do not match.\n");
else
Fprintf(stdout, "Circuits match correctly.\n");
}
if (PropertyErrorDetected) {
Fprintf(stdout, "There were property errors.\n");
PrintPropertyResults(dolist);
if (automorphisms == -1)
Fprintf(stdout, "Netlists do not match.\n");
else if (automorphisms == -2)
Fprintf(stdout, "Netlists match uniquely with port errors.\n");
else {
if (automorphisms == 0)
Fprintf(stdout, "Netlists match uniquely");
else
Fprintf(stdout, "Netlists match with %d symmetr%s",
automorphisms, (automorphisms == 1) ? "y" : "ies");
if (PropertyErrorDetected) {
Fprintf(stdout, " with property errors.\n");
PrintPropertyResults(dolist);
}
else
Fprintf(stdout, ".\n");
}
disable_interrupt();
}
@@ -2529,8 +2549,14 @@ _netcmp_run(ClientData clientData,
/* all, or no option. */
/* Formerly: v */
/* Results: */
/* For only, equivalent, unique: Return 1 if */
/* verified, zero if not. */
/* For only, equivalent, unique: Return */
/* 1: verified */
/* 0: not verified */
/* -1: no elements or nodes */
/* -3: verified with property error */
/* equiv option */
/* -2: pin mismatch */
/* */
/* Side Effects: */
/* For options elements, nodes, and all without */
/* option -list: Write output to log file. */
@@ -2624,13 +2650,21 @@ _netcmp_verify(ClientData clientData,
else
Fprintf(stdout, "Netlists do not match.\n");
}
else if (automorphisms == -2) {
if (index == EQUIV_IDX)
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
else if (index == UNIQUE_IDX)
Tcl_SetObjResult(interp, Tcl_NewIntObj(-2));
else if (index > 0)
Fprintf(stdout, "Circuits match uniquely with port errors.\n");
}
else {
if (automorphisms) {
if (index == EQUIV_IDX)
Tcl_SetObjResult(interp, Tcl_NewIntObj((int)automorphisms));
else if (index == UNIQUE_IDX)
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
else
else if (index > 0)
Printf("Circuits match with %d symmetr%s.\n",
automorphisms, (automorphisms == 1) ? "y" : "ies");
}
@@ -2639,11 +2673,13 @@ _netcmp_verify(ClientData clientData,
if (PropertyErrorDetected == 0)
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
else
Tcl_SetObjResult(interp, Tcl_NewIntObj(2));
Tcl_SetObjResult(interp, Tcl_NewIntObj(-3));
}
else {
else if (index > 0) {
Fprintf(stdout, "Circuits match uniquely.\n");
if (PropertyErrorDetected != 0)
if (PropertyErrorDetected == 0)
Fprintf(stdout, ".\n");
else
Fprintf(stdout, "Property errors were found.\n");
}
}
@@ -3066,7 +3102,11 @@ _netcmp_equate(ClientData clientData,
tp1->flags |= CELL_PLACEHOLDER;
tp2->flags |= CELL_PLACEHOLDER;
}
else {
else if (doforce != TRUE) {
/* When doforce is TRUE, ElementClass has been set to NULL
* even though circuits contain elements, so this message
* is not correct.
*/
Fprintf(stdout, "Equate pins: cell %s and/or %s "
"has no elements.\n", name1, name2);
/* This is not necessarily an error, so go ahead and match pins. */
@@ -3098,6 +3138,13 @@ _netcmp_equate(ClientData clientData,
else if (result > 0) {
Fprintf(stdout, "Cell pin lists are equivalent.\n");
}
else if (result == -1) {
Fprintf(stdout, "Cell pin lists for %s and %s do not match.\n",
name1, name2);
}
else if (result == -2) {
Fprintf(stdout, "Attempt to match empty cell to non-empty cell.\n");
}
else {
Fprintf(stdout, "Cell pin lists for %s and %s altered to match.\n",
name1, name2);