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.
This commit is contained in:
Tim Edwards 2022-09-13 10:55:00 -04:00
parent 79e193e0c9
commit 9297090dc1
5 changed files with 271 additions and 174 deletions

View File

@ -1 +1 @@
1.5.228 1.5.229

View File

@ -66,7 +66,7 @@ void flattenCell(char *name, int file)
else else
ThisCell = LookupCellFile(name, file); ThisCell = LookupCellFile(name, file);
if (ThisCell == NULL) { if (ThisCell == NULL) {
Printf("No cell %s found.\n", name); Printf("No cell %s (%d) found.\n", name, file);
return; return;
} }
@ -282,13 +282,14 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
} }
else { else {
if (Debug) 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) if (fnum == -1)
ThisCell = LookupCell(name); ThisCell = LookupCell(name);
else else
ThisCell = LookupCellFile(name, fnum); ThisCell = LookupCellFile(name, fnum);
if (ThisCell == NULL) { if (ThisCell == NULL) {
Printf("No cell %s found.\n", name); Printf("No cell %s (%d) found.\n", name, fnum);
return 0; return 0;
} }
} }
@ -688,7 +689,7 @@ void convertGlobalsOf(char *name, int fnum, char *instance)
else else
ThisCell = LookupCellFile(name, fnum); ThisCell = LookupCellFile(name, fnum);
if (ThisCell == NULL) { if (ThisCell == NULL) {
Printf("No cell %s found.\n", name); Printf("No cell %s (%d) found.\n", name, fnum);
return; return;
} }
} }
@ -1118,7 +1119,7 @@ int UniquePins(char *name, int filenum)
ThisCell = LookupCellFile(name, filenum); ThisCell = LookupCellFile(name, filenum);
if (ThisCell == NULL) { if (ThisCell == NULL) {
Printf("No cell %s found.\n", name); Printf("No cell %s (%d) found.\n", name, filenum);
return 0; return 0;
} }
@ -1159,7 +1160,8 @@ int UniquePins(char *name, int filenum)
continue; continue;
} }
else { 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) { if (nodecount[ob->node] > 1) {
@ -1360,7 +1362,7 @@ int CleanupPins(char *name, int filenum)
ThisCell = LookupCellFile(name, filenum); ThisCell = LookupCellFile(name, filenum);
if (ThisCell == NULL) { if (ThisCell == NULL) {
Printf("No cell %s found.\n", name); Printf("No cell %s (%d) found.\n", name, filenum);
return 0; return 0;
} }

View File

@ -6185,7 +6185,8 @@ void PrintPropertyResults(int do_list)
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
/* Return 0 if perfect matching found, else return number of */ /* 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) int VerifyMatching(void)
@ -6196,6 +6197,9 @@ int VerifyMatching(void)
struct Element *E; struct Element *E;
struct Node *N; struct Node *N;
int C1, C2, result; int C1, C2, result;
int P1, P2;
struct objlist *ob1, *ob2;
int portMismatch = 0;
if (BadMatchDetected) return(-1); if (BadMatchDetected) return(-1);
@ -6216,14 +6220,40 @@ int VerifyMatching(void)
} }
} }
P1 = P2 = 0;
for (NC = NodeClasses; NC != NULL; NC = NC->next) { for (NC = NodeClasses; NC != NULL; NC = NC->next) {
C1 = C2 = 0; C1 = C2 = 0;
for (N = NC->nodes; N != NULL; N = N->next) { for (N = NC->nodes; N != NULL; N = N->next) {
(N->graph == Circuit1->file) ? C1++ : C2++; (N->graph == Circuit1->file) ? C1++ : C2++;
if (IsPort(N->object)) (N->graph == Circuit1->file) ? P1++ : P2++;
} }
if (C1 != C2) return(-1); if (C1 != C2) return(-1);
if (P1 != P2) portMismatch = 1;
if (C1 != 1) ret++; 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); return(ret);
} }
@ -6322,7 +6352,7 @@ int ResolveAutomorphsByPin()
FractureElementClass(&ElementClasses); FractureElementClass(&ElementClasses);
FractureNodeClass(&NodeClasses); FractureNodeClass(&NodeClasses);
ExhaustiveSubdivision = 1; ExhaustiveSubdivision = 1;
while (!Iterate() && VerifyMatching() != -1); while (!Iterate() && VerifyMatching() >= 0);
return(VerifyMatching()); return(VerifyMatching());
} }
@ -6425,7 +6455,7 @@ int ResolveAutomorphsByProperty()
FractureElementClass(&ElementClasses); FractureElementClass(&ElementClasses);
FractureNodeClass(&NodeClasses); FractureNodeClass(&NodeClasses);
ExhaustiveSubdivision = 1; ExhaustiveSubdivision = 1;
while (!Iterate() && VerifyMatching() != -1); while (!Iterate() && VerifyMatching() >= 0);
return(VerifyMatching()); return(VerifyMatching());
} }
@ -6502,7 +6532,7 @@ int ResolveAutomorphisms()
FractureElementClass(&ElementClasses); FractureElementClass(&ElementClasses);
FractureNodeClass(&NodeClasses); FractureNodeClass(&NodeClasses);
ExhaustiveSubdivision = 1; ExhaustiveSubdivision = 1;
while (!Iterate() && VerifyMatching() != -1); while (!Iterate() && VerifyMatching() >= 0);
return(VerifyMatching()); return(VerifyMatching());
} }
@ -7197,32 +7227,31 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
return NULL; /* Keep the search going */ return NULL; /* Keep the search going */
} }
/*------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* Declare that the device class "name1" is equivalent */ /* Declare that the device class "name1" is equivalent to class */
/* to class "name2". This is the same as the above */ /* "name2". This is the same as the above routine, except that */
/* routine, except that the cells must be at the top */ /* the cells must be at the top of the compare queue, and must */
/* of the compare queue, and must already be proven */ /* already be proven equivalent by LVS. Determine a pin */
/* equivalent by LVS. Determine a pin correspondence, */ /* correspondence, then modify all instances of "name2" to */
/* then modify all instances of "name2" to match all */ /* match all instances of "name1" by pin reordering. If either */
/* instances of "name1" by pin reordering. If either */ /* cell has disconnected pins, they are shuffled to the end of */
/* cell has disconnected pins, they are shuffled to the */ /* the pin list. If two or more pins correspond to net */
/* end of the pin list. If two or more pins correspond */ /* automorphisms, then they are added to the list of permuted */
/* to net automorphisms, then they are added to the */ /* pins. */
/* list of permuted pins. */ /* */
/* */ /* NOTE: This routine must not be called on any circuit pair */
/* NOTE: This routine must not be called on any */ /* that has not been matched. If a circuit pair has been */
/* circuit pair that has not been matched. If a */ /* matched with automorphisms, then some pins may be matched */
/* circuit pair has been matched with automorphisms, */ /* arbitrarily. */
/* then some pins may be matched arbitrarily. */ /* */
/* */ /* If "dolist" is 1, append the list representing the output */
/* If "dolist" is 1, append the list representing the */ /* (if any) to variable tcl_out, if it exists. */
/* output (if any) to variable tcl_out, if it exists. */ /* */
/* */ /* Return codes: */
/* Return codes: */ /* 2: Neither cell had pins, so matching is unnecessary */
/* 2: Neither cell had pins, so matching is unnecessary */ /* 1: Exact match */
/* 1: Exact match */ /* 0: Inexact match resolved by proxy pin insertion. */
/* 0: Inexact match resolved by proxy pin insertion */ /*--------------------------------------------------------------*/
/*------------------------------------------------------*/
int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
{ {
@ -7817,7 +7846,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
} }
/* Check for ports that did not get ordered */ /* 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->model.port == -1) {
if (obn->node == -1) { if (obn->node == -1) {
// This only happens when pins have become separated from any net. // This only happens when pins have become separated from any net.
@ -7995,10 +8024,12 @@ int EquivalentElement(char *name, struct nlist *circuit, struct objlist **retobj
void FlattenCurrent() void FlattenCurrent()
{ {
if (Circuit1 != NULL && Circuit2 != NULL) { 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); 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); FlattenInstancesOf(Circuit2->name, Circuit2->file);
} }
} }
@ -8069,7 +8100,25 @@ int Compare(char *cell1, char *cell2)
PrintIllegalClasses(); PrintIllegalClasses();
return(0); 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) { if (PropertyErrorDetected == 1) {
Fprintf(stdout, "There were property errors.\n"); Fprintf(stdout, "There were property errors.\n");
PrintPropertyResults(0); PrintPropertyResults(0);
@ -8078,22 +8127,10 @@ int Compare(char *cell1, char *cell2)
Fprintf(stdout, "There were missing properties.\n"); Fprintf(stdout, "There were missing properties.\n");
PrintPropertyResults(0); PrintPropertyResults(0);
} }
if (automorphisms == 0) return(1); else
Fprintf(stdout, "Circuits match correctly.\n");
Fprintf(stdout, "Circuits match with %d automorphisms.\n", automorphisms); return 1;
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);
} }
@ -8147,9 +8184,12 @@ void NETCOMP(void)
PrintIllegalClasses(); PrintIllegalClasses();
Fprintf(stdout, "Netlists do not match.\n"); Fprintf(stdout, "Netlists do not match.\n");
} }
else if (automorphisms == -2) { // port count mismatch
Fprintf(stdout, "Port counts do not match.\n");
}
else { else {
if (automorphisms) if (automorphisms)
Printf("Circuits match with %d automorphisms.\n", automorphisms); Printf("Circuits match with %d symmetries.\n", automorphisms);
else Printf("Circuits match correctly.\n"); else Printf("Circuits match correctly.\n");
} }
} }
@ -8162,11 +8202,13 @@ void NETCOMP(void)
while (!Iterate()) ; while (!Iterate()) ;
automorphisms = VerifyMatching(); automorphisms = VerifyMatching();
if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n"); if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n");
else if (automorphisms == -2) Fprintf(stdout, "Port counts do not match.\n");
else { else {
Printf("Netlists match with %d automorphisms.\n", automorphisms); Printf("Netlists match with %d symmetries.\n", automorphisms);
while ((automorphisms = ResolveAutomorphisms()) > 0) while ((automorphisms = ResolveAutomorphisms()) > 0)
Printf(" automorphisms = %d.\n", automorphisms); Printf(" automorphisms = %d.\n", automorphisms);
if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n"); 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"); else Printf("Circuits match correctly.\n");
} }
} }

View File

@ -532,14 +532,24 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
} }
set properr {} set properr {}
set matcherr {} set matcherr {}
set pinsgood -1 set childMismatch 0 ;# 1 indicates black-box child subcircuit mismatch
while {$endval != {}} { while {$endval != {}} {
if {$dolist == 1} { if {$dolist == 1} {
netgen::run -list converge netgen::run -list converge
} else { } else {
netgen::run converge 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]} { if {[verify equivalent]} {
# Resolve automorphisms by pin and property # Resolve automorphisms by pin and property
if {$dolist == 1} { if {$dolist == 1} {
@ -548,98 +558,105 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
netgen::run resolve netgen::run resolve
} }
set uresult [verify unique] 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} { if {$uresult == 0} {
netgen::log echo on
netgen::log put " Networks match locally but not globally.\n" netgen::log put " Networks match locally but not globally.\n"
netgen::log put " Probably connections are swapped.\n" netgen::log put " Probably connections are swapped.\n"
netgen::log put " Check the end of logfile ${logfile} for implicated nodes.\n" netgen::log put " Check the end of logfile ${logfile} for implicated nodes.\n"
netgen::log echo off
if {$dolist == 1} { if {$dolist == 1} {
verify -list nodes verify -list nodes
} else { } else {
verify nodes verify nodes
} }
set doCheckFlatten 1
# 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)"
netgen::flatten prohibit "[lindex $endval 0] $fnum1"
netgen::flatten prohibit "[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
}
}
} else { } else {
netgen::log echo off # Equate pins for black boxes, unique matches (possibly with property
if {$dolist == 1} { # errors), and unique with port errors
set result [equate -list pins "$fnum1 [lindex $endval 0]" \ set doEquatePins 1
"$fnum2 [lindex $endval 1]"] }
} else { if {$uresult == -1} { ;# black box
set result [equate pins "$fnum1 [lindex $endval 0]" \ set forceMatch 1
"$fnum2 [lindex $endval 1]"] } elseif {$uresult == -3} { ;# property error
} lappend properr [lindex $endval 0]
if {$result != 0} { } elseif {$uresult == -2} { ;# unmatched pins
equate classes "$fnum1 [lindex $endval 0]" \ set doCheckFlatten 1
"$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
} }
if {$uresult == 2} {lappend properr [lindex $endval 0]}
} else { } else {
# Flatten the non-matching subcircuit (but not the top-level cells) # not equivalent
if {[netgen::print queue] != {}} { 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) && if {([lsearch $noflat [lindex $endval 0]] == -1) &&
([lsearch $noflat [lindex $endval 1]] == -1)} { ([lsearch $noflat [lindex $endval 1]] == -1)} {
netgen::log put " Flattening non-matched subcircuits $endval\n" set doFlatten 1
netgen::flatten class "[lindex $endval 0] $fnum1" } else {
netgen::flatten class "[lindex $endval 1] $fnum2" netgen::log echo on
} else {
netgen::log put " Continuing with black-boxed subcircuits $endval\n" 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]"($fnum1)"
lappend matcherr [lindex $endval 0]"($fnum2)" lappend matcherr [lindex $endval 1]"($fnum2)"
# Match pins netgen::flatten prohibit "[lindex $endval 0] $fnum1"
netgen::log echo off netgen::flatten prohibit "[lindex $endval 1] $fnum2"
if {$dolist == 1} { set doEquatePins 1
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \ set childMismatch 1
"$fnum2 [lindex $endval 1]"] set forceMatch 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
} }
} }
} }
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} { if {$dolist == 1} {
catch {lappend lvs_final $lvs_out} catch {lappend lvs_final $lvs_out}
set lvs_out {} set lvs_out {}
@ -648,20 +665,23 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set endval [netgen::compare hierarchical] set endval [netgen::compare hierarchical]
} }
} }
netgen::log echo off
puts stdout "Result: " nonewline
netgen::log echo on netgen::log echo on
if {$pinsgood == 0} { netgen::log put "\nFinal result: "
# NOTE: Need to disambiguate these two cases. . . if {$pinMismatch || $childMismatch} {
netgen::log put "Cells failed matching, or top level cell failed pin matching.\n" if {$childMismatch} {
netgen::log put "Subcell(s) failed matching.\n"
}
if {$pinMismatch} {
netgen::log put "Top level cell failed pin matching.\n"
}
} else { } else {
verify only verify only
} }
if {$properr != {}} { 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 != {}} { 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} { if {$dolog} {
netgen::log end netgen::log end

View File

@ -1937,9 +1937,17 @@ _netgen_log(ClientData clientData,
switch(index) { switch(index) {
case START_IDX: case START_IDX:
LoggingFile = fopen(LogFileName, "w"); LoggingFile = fopen(LogFileName, "w");
if (!LoggingFile) {
Tcl_SetResult(interp, "Could not open log file.", NULL);
return TCL_ERROR;
}
break; break;
case RESUME_IDX: case RESUME_IDX:
LoggingFile = fopen(LogFileName, "a"); LoggingFile = fopen(LogFileName, "a");
if (!LoggingFile) {
Tcl_SetResult(interp, "Could not open log file.", NULL);
return TCL_ERROR;
}
break; break;
case END_IDX: case END_IDX:
fclose(LoggingFile); fclose(LoggingFile);
@ -1948,6 +1956,10 @@ _netgen_log(ClientData clientData,
case RESET_IDX: case RESET_IDX:
fclose(LoggingFile); fclose(LoggingFile);
LoggingFile = fopen(LogFileName, "w"); LoggingFile = fopen(LogFileName, "w");
if (!LoggingFile) {
Tcl_SetResult(interp, "Could not open log file.", NULL);
return TCL_ERROR;
}
break; break;
case SUSPEND_IDX: case SUSPEND_IDX:
fclose(LoggingFile); fclose(LoggingFile);
@ -2209,11 +2221,11 @@ _netcmp_compare(ClientData clientData,
hascontents2 = HasContents(tp2); hascontents2 = HasContents(tp2);
if (hascontents1 && !hascontents2 && (tp2->flags & CELL_PLACEHOLDER)) { 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); "Circuit 1\n", name2);
} }
else if (hascontents2 && !hascontents1 && (tp1->flags & CELL_PLACEHOLDER)) { 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); "Circuit 2\n", name1);
} }
else if (hascontents1 || hascontents2) { else if (hascontents1 || hascontents2) {
@ -2229,6 +2241,10 @@ _netcmp_compare(ClientData clientData,
DescribeContents(name1, fnum1, name2, fnum2); 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); CreateTwoLists(name1, fnum1, name2, fnum2, dolist);
// Return the names of the two cells being compared, if doing "compare // Return the names of the two cells being compared, if doing "compare
@ -2485,39 +2501,37 @@ _netcmp_run(ClientData clientData,
ExhaustiveSubdivision = 1; ExhaustiveSubdivision = 1;
while (!Iterate() && !InterruptPending); while (!Iterate() && !InterruptPending);
automorphisms = VerifyMatching(); automorphisms = VerifyMatching();
if (automorphisms == -1) if (automorphisms > 0) {
Fprintf(stdout, "Netlists do not match.\n");
else if (automorphisms == 0)
Fprintf(stdout, "Netlists match uniquely.\n");
else {
// First try to resolve automorphisms uniquely using // First try to resolve automorphisms uniquely using
// property matching // property matching
automorphisms = ResolveAutomorphsByProperty(); automorphisms = ResolveAutomorphsByProperty();
if (automorphisms == 0) if (automorphisms > 0) {
Fprintf(stdout, "Netlists match uniquely.\n");
else if (automorphisms > 0) {
// Next, attempt to resolve automorphisms uniquely by // Next, attempt to resolve automorphisms uniquely by
// using the pin names // using the pin names
automorphisms = ResolveAutomorphsByPin(); automorphisms = ResolveAutomorphsByPin();
} }
if (automorphisms > 0) {
if (automorphisms == 0)
Fprintf(stdout, "Netlists match uniquely.\n");
else if (automorphisms > 0) {
// Anything left is truly indistinguishable // Anything left is truly indistinguishable
Fprintf(stdout, "Netlists match with %d symmetr%s.\n", while (ResolveAutomorphisms() > 0);
automorphisms, (automorphisms == 1) ? "y" : "ies");
while ((automorphisms = 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"); if (automorphisms == -1)
PrintPropertyResults(dolist); 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(); disable_interrupt();
} }
@ -2535,8 +2549,14 @@ _netcmp_run(ClientData clientData,
/* all, or no option. */ /* all, or no option. */
/* Formerly: v */ /* Formerly: v */
/* Results: */ /* Results: */
/* For only, equivalent, unique: Return 1 if */ /* For only, equivalent, unique: Return */
/* verified, zero if not. */ /* 1: verified */
/* 0: not verified */
/* -1: no elements or nodes */
/* -3: verified with property error */
/* equiv option */
/* -2: pin mismatch */
/* */
/* Side Effects: */ /* Side Effects: */
/* For options elements, nodes, and all without */ /* For options elements, nodes, and all without */
/* option -list: Write output to log file. */ /* option -list: Write output to log file. */
@ -2636,7 +2656,7 @@ _netcmp_verify(ClientData clientData,
Tcl_SetObjResult(interp, Tcl_NewIntObj((int)automorphisms)); Tcl_SetObjResult(interp, Tcl_NewIntObj((int)automorphisms));
else if (index == UNIQUE_IDX) else if (index == UNIQUE_IDX)
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
else else if (index > 0)
Printf("Circuits match with %d symmetr%s.\n", Printf("Circuits match with %d symmetr%s.\n",
automorphisms, (automorphisms == 1) ? "y" : "ies"); automorphisms, (automorphisms == 1) ? "y" : "ies");
} }
@ -2645,11 +2665,13 @@ _netcmp_verify(ClientData clientData,
if (PropertyErrorDetected == 0) if (PropertyErrorDetected == 0)
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
else else
Tcl_SetObjResult(interp, Tcl_NewIntObj(2)); Tcl_SetObjResult(interp, Tcl_NewIntObj(-3));
} }
else { else if (index > 0) {
Fprintf(stdout, "Circuits match uniquely.\n"); Fprintf(stdout, "Circuits match uniquely.\n");
if (PropertyErrorDetected != 0) if (PropertyErrorDetected == 0)
Fprintf(stdout, ".\n");
else
Fprintf(stdout, "Property errors were found.\n"); Fprintf(stdout, "Property errors were found.\n");
} }
} }
@ -3072,7 +3094,11 @@ _netcmp_equate(ClientData clientData,
tp1->flags |= CELL_PLACEHOLDER; tp1->flags |= CELL_PLACEHOLDER;
tp2->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 " Fprintf(stdout, "Equate pins: cell %s and/or %s "
"has no elements.\n", name1, name2); "has no elements.\n", name1, name2);
/* This is not necessarily an error, so go ahead and match pins. */ /* This is not necessarily an error, so go ahead and match pins. */
@ -3104,6 +3130,13 @@ _netcmp_equate(ClientData clientData,
else if (result > 0) { else if (result > 0) {
Fprintf(stdout, "Cell pin lists are equivalent.\n"); 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 { else {
Fprintf(stdout, "Cell pin lists for %s and %s altered to match.\n", Fprintf(stdout, "Cell pin lists for %s and %s altered to match.\n",
name1, name2); name1, name2);