Merge branch 'master' into netgen-1.5
This commit is contained in:
commit
153ce0e2b3
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
126
base/netcmp.c
126
base/netcmp.c
|
|
@ -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 */
|
/* NOTE: This routine must not be called on any circuit pair */
|
||||||
/* circuit pair that has not been matched. If a */
|
/* that has not been matched. If a circuit pair has been */
|
||||||
/* circuit pair has been matched with automorphisms, */
|
/* matched with automorphisms, then some pins may be matched */
|
||||||
/* then some pins may be matched arbitrarily. */
|
/* arbitrarily. */
|
||||||
/* */
|
/* */
|
||||||
/* If "dolist" is 1, append the list representing the */
|
/* If "dolist" is 1, append the list representing the output */
|
||||||
/* output (if any) to variable tcl_out, if it exists. */
|
/* (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,18 +8100,9 @@ int Compare(char *cell1, char *cell2)
|
||||||
PrintIllegalClasses();
|
PrintIllegalClasses();
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
if (automorphisms == 0) Fprintf(stdout, "Circuits match correctly.\n");
|
|
||||||
if (PropertyErrorDetected == 1) {
|
|
||||||
Fprintf(stdout, "There were property errors.\n");
|
|
||||||
PrintPropertyResults(0);
|
|
||||||
}
|
|
||||||
else if (PropertyErrorDetected == -1) {
|
|
||||||
Fprintf(stdout, "There were missing properties.\n");
|
|
||||||
PrintPropertyResults(0);
|
|
||||||
}
|
|
||||||
if (automorphisms == 0) return(1);
|
|
||||||
|
|
||||||
Fprintf(stdout, "Circuits match with %d automorphisms.\n", automorphisms);
|
if (automorphisms > 0) {
|
||||||
|
Fprintf(stdout, "Circuits match with %d symmetries.\n", automorphisms);
|
||||||
if (VerboseOutput) PrintAutomorphisms();
|
if (VerboseOutput) PrintAutomorphisms();
|
||||||
|
|
||||||
/* arbitrarily resolve automorphisms */
|
/* arbitrarily resolve automorphisms */
|
||||||
|
|
@ -8090,10 +8112,25 @@ int Compare(char *cell1, char *cell2)
|
||||||
if (automorphisms == -1) {
|
if (automorphisms == -1) {
|
||||||
MatchFail(cell1, cell2);
|
MatchFail(cell1, cell2);
|
||||||
Fprintf(stdout, "Circuits do not match.\n");
|
Fprintf(stdout, "Circuits do not match.\n");
|
||||||
return(0);
|
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);
|
||||||
|
}
|
||||||
|
else if (PropertyErrorDetected == -1) {
|
||||||
|
Fprintf(stdout, "There were missing properties.\n");
|
||||||
|
PrintPropertyResults(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
Fprintf(stdout, "Circuits match correctly.\n");
|
Fprintf(stdout, "Circuits match correctly.\n");
|
||||||
return(1);
|
|
||||||
|
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
} else {
|
||||||
|
# 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
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# 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 {[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"
|
|
||||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
|
||||||
} else {
|
} else {
|
||||||
|
netgen::log echo on
|
||||||
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 1]"($fnum2)"
|
lappend matcherr [lindex $endval 1]"($fnum2)"
|
||||||
netgen::flatten prohibit "[lindex $endval 0] $fnum1"
|
netgen::flatten prohibit "[lindex $endval 0] $fnum1"
|
||||||
netgen::flatten prohibit "[lindex $endval 1] $fnum2"
|
netgen::flatten prohibit "[lindex $endval 1] $fnum2"
|
||||||
|
set doEquatePins 1
|
||||||
|
set childMismatch 1
|
||||||
|
set forceMatch 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if {$doEquatePins} {
|
||||||
# Match pins
|
# Match pins
|
||||||
netgen::log echo off
|
|
||||||
if {$dolist == 1} {
|
if {$dolist == 1} {
|
||||||
|
if {$forceMatch} {
|
||||||
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
|
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
|
||||||
"$fnum2 [lindex $endval 1]"]
|
"$fnum2 [lindex $endval 1]"]
|
||||||
} else {
|
} else {
|
||||||
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
|
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
|
||||||
"$fnum2 [lindex $endval 1]"]
|
"$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
|
if {$forceMatch} {
|
||||||
if {$dolist == 1} {
|
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
|
||||||
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
|
|
||||||
"$fnum2 [lindex $endval 1]"]
|
"$fnum2 [lindex $endval 1]"]
|
||||||
} else {
|
} else {
|
||||||
set result [equate pins "$fnum1 [lindex $endval 0]" \
|
set result [equate pins "$fnum1 [lindex $endval 0]" \
|
||||||
"$fnum2 [lindex $endval 1]"]
|
"$fnum2 [lindex $endval 1]"]
|
||||||
}
|
}
|
||||||
if {$result != 0} {
|
}
|
||||||
|
if {$result >= 0} {
|
||||||
equate classes "$fnum1 [lindex $endval 0]" \
|
equate classes "$fnum1 [lindex $endval 0]" \
|
||||||
"$fnum2 [lindex $endval 1]"
|
"$fnum2 [lindex $endval 1]"
|
||||||
}
|
}
|
||||||
# If $uresult == -1 then these are black-box entries and
|
# Do not set pinMismatch for black boxes
|
||||||
# $pinsgood should not be set to the resulting value.
|
if {$result < 0} {
|
||||||
if {$uresult > 0} {
|
if {$result == -1 && [netgen::print queue] != {} && $forceMatch != 1} {
|
||||||
set pinsgood $result
|
# 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 echo on
|
||||||
}
|
|
||||||
if {$uresult == 2} {lappend properr [lindex $endval 0]}
|
|
||||||
} else {
|
|
||||||
# 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::log put " Flattening non-matched subcircuits $endval\n"
|
||||||
|
netgen::log echo off
|
||||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
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 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
netgen::log echo off
|
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -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,40 +2501,38 @@ _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)
|
if (automorphisms == -1)
|
||||||
Fprintf(stdout, "Netlists do not match.\n");
|
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
|
else
|
||||||
Fprintf(stdout, "Circuits match correctly.\n");
|
Fprintf(stdout, "Netlists match with %d symmetr%s",
|
||||||
}
|
automorphisms, (automorphisms == 1) ? "y" : "ies");
|
||||||
if (PropertyErrorDetected) {
|
if (PropertyErrorDetected) {
|
||||||
Fprintf(stdout, "There were property errors.\n");
|
Fprintf(stdout, " with property errors.\n");
|
||||||
PrintPropertyResults(dolist);
|
PrintPropertyResults(dolist);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
Fprintf(stdout, ".\n");
|
||||||
|
}
|
||||||
disable_interrupt();
|
disable_interrupt();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue