mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 14:07:07 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ba1dfe814 | ||
|
|
cc5f6d929f | ||
|
|
fadd0ae2fc | ||
|
|
4fa4d046c8 | ||
|
|
153ce0e2b3 | ||
|
|
9297090dc1 | ||
|
|
bfdacab28c | ||
|
|
79e193e0c9 |
+26
-14
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1152,7 +1160,8 @@ int UniquePins(char *name, int filenum)
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
Printf("Duplicate pin %s in cell %s\n", ob->name, ThisCell->name);
|
||||
Printf("Duplicate pin %s in cell %s (%d)\n", ob->name,
|
||||
ThisCell->name, filenum);
|
||||
}
|
||||
}
|
||||
if (nodecount[ob->node] > 1) {
|
||||
@@ -1353,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;
|
||||
}
|
||||
|
||||
@@ -1620,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 */
|
||||
@@ -1716,13 +1728,13 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
if ((ecomp->num1 == 0) || (ecomp->cell1->class !=
|
||||
CLASS_MODULE)) {
|
||||
|
||||
if (ecomp->cell2) {
|
||||
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);
|
||||
modified++;
|
||||
}
|
||||
modified++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1782,13 +1794,13 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
if ((ecomp->num2 == 0) || (ecomp->cell2->class !=
|
||||
CLASS_MODULE)) {
|
||||
|
||||
if (ecomp->cell1) {
|
||||
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);
|
||||
modified++;
|
||||
}
|
||||
modified++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+294
-379
@@ -6185,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)
|
||||
@@ -6196,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);
|
||||
|
||||
@@ -6216,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);
|
||||
}
|
||||
|
||||
@@ -6322,7 +6352,7 @@ int ResolveAutomorphsByPin()
|
||||
FractureElementClass(&ElementClasses);
|
||||
FractureNodeClass(&NodeClasses);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && VerifyMatching() != -1);
|
||||
while (!Iterate() && VerifyMatching() >= 0);
|
||||
return(VerifyMatching());
|
||||
}
|
||||
|
||||
@@ -6425,7 +6455,7 @@ int ResolveAutomorphsByProperty()
|
||||
FractureElementClass(&ElementClasses);
|
||||
FractureNodeClass(&NodeClasses);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && VerifyMatching() != -1);
|
||||
while (!Iterate() && VerifyMatching() >= 0);
|
||||
return(VerifyMatching());
|
||||
}
|
||||
|
||||
@@ -6502,7 +6532,7 @@ int ResolveAutomorphisms()
|
||||
FractureElementClass(&ElementClasses);
|
||||
FractureNodeClass(&NodeClasses);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && VerifyMatching() != -1);
|
||||
while (!Iterate() && VerifyMatching() >= 0);
|
||||
return(VerifyMatching());
|
||||
}
|
||||
|
||||
@@ -7197,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 *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;
|
||||
@@ -7243,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) {
|
||||
@@ -7261,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
|
||||
@@ -7294,194 +7329,159 @@ 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)) && (ob1->node == obn->node)) {
|
||||
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)) && (ob2->node == obp->node)) {
|
||||
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);
|
||||
if ((*matchfunc)(ob1->name, ob2->name))
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
else {
|
||||
/* Check remainder of ports to see if there is a name match on the
|
||||
* same net number (multiple ports tied to the same net)
|
||||
*/
|
||||
struct objlist *ob3;
|
||||
for (ob3 = ob2->next, ++j; ob3 != NULL; ob3 = ob3->next, j++) {
|
||||
if ((IsPort(ob3)) && (ob3->node == ob2->node)) {
|
||||
if ((*matchfunc)(ob3->name, ob1->name)) {
|
||||
ob2 = ob3;
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ob3 = NULL;
|
||||
break; /* All pins w/the same node should be together */
|
||||
}
|
||||
}
|
||||
if (ob3 == NULL) {
|
||||
if (ob2->model.port == -1)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", ob2->name);
|
||||
else
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
|
||||
/* 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;
|
||||
|
||||
/* If there are multiple pins on the same net, cycle through them; */
|
||||
/* otherwise, move to the next entry in the partition. */
|
||||
if (ob1->next && (ob1->next->type == PORT) && (ob1->next->node == ob1->node)) {
|
||||
ob1 = ob1->next;
|
||||
ob2 = tc2->cell; /* Restart search for matching pin */
|
||||
i++;
|
||||
}
|
||||
else
|
||||
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 */
|
||||
@@ -7489,7 +7489,11 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
|
||||
ob1 = tc1->cell;
|
||||
|
||||
isBlackBox1 = (tc1->flags & CELL_PLACEHOLDER);
|
||||
isBlackBox2 = (tc2->flags & CELL_PLACEHOLDER);
|
||||
|
||||
for (i = 0; i < numorig; i++) {
|
||||
|
||||
bangptr1 = strrchr(ob1->name, '!');
|
||||
if (bangptr1 && (*(bangptr1 + 1) == '\0'))
|
||||
*bangptr1 = '\0';
|
||||
@@ -7497,12 +7501,13 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
|
||||
backslashptr1 = (*(ob1->name) == '\\') ? ob1->name + 1 : ob1->name;
|
||||
|
||||
if (*(cover + i) == (char)0) {
|
||||
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'))
|
||||
@@ -7526,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);
|
||||
@@ -7561,7 +7571,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
}
|
||||
}
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
j++;
|
||||
}
|
||||
}
|
||||
ob1 = ob1->next;
|
||||
@@ -7580,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) {
|
||||
@@ -7589,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);
|
||||
@@ -7601,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))
|
||||
@@ -7687,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);
|
||||
@@ -7817,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.
|
||||
@@ -7995,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);
|
||||
}
|
||||
}
|
||||
@@ -8069,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);
|
||||
@@ -8078,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -8147,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");
|
||||
}
|
||||
}
|
||||
@@ -8162,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");
|
||||
}
|
||||
}
|
||||
|
||||
+104
-82
@@ -393,7 +393,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 +532,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 +558,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 +665,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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user