Corrected an error in the code that handles no-connects as valid

pins for enabling parallel combinations, which could cause a crash.
Added a "-force" option to "equate pins" to allow pins to be matched
even on subcircuits that did not correctly match;  this was done in
conjuction with an extra option to the "lvs" command "-noflatten="
to pass a list of cellname to not be flattened even if they do not
match.  This is generally discouraged, as it prevents netgen from
resolving differences between layout and schematic hierarchy, but it
can be useful for checking that the hierarchy above a certain cell
is correct, given that if a subcell is really unmatched, then its
errors will keep propagating up the top level, making additional
errors hard to diagnose.
This commit is contained in:
Tim Edwards 2021-03-05 11:32:17 -05:00
parent 20077d3d56
commit fd72e24a86
4 changed files with 102 additions and 16 deletions

View File

@ -1 +1 @@
1.5.170 1.5.171

View File

@ -5363,13 +5363,21 @@ PropertyMatch(struct objlist *ob1, int file1,
/* WIP---Check for no-connect pins in merged devices on both sides. */ /* WIP---Check for no-connect pins in merged devices on both sides. */
/* Both sides should either have no-connects marked, or neither. */ /* Both sides should either have no-connects marked, or neither. */
/* (Permutable pins may need to be handled correctly. . . */ /* (Permutable pins may need to be handled correctly. . . */
for (tp1 = ob1, tp2 = ob2; (tp1 != NULL) && tp1->type >= FIRSTPIN && for (tp1 = ob1, tp2 = ob2; (tp1 != NULL) && tp1->type >= FIRSTPIN &&
(tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next) (tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next)
{ {
struct objlist *node1, *node2; struct objlist *node1, *node2;
node1 = Circuit1->nodename_cache[tp1->node]; if (file1 == Circuit1->file)
node2 = Circuit2->nodename_cache[tp2->node]; node1 = Circuit1->nodename_cache[tp1->node];
else
node1 = Circuit2->nodename_cache[tp1->node];
if (file2 == Circuit1->file)
node2 = Circuit1->nodename_cache[tp2->node];
else
node2 = Circuit2->nodename_cache[tp2->node];
if (node1->instance.flags != node2->instance.flags) if (node1->instance.flags != node2->instance.flags)
{ {

View File

@ -352,7 +352,7 @@ proc netgen::convert_to_json {filename lvs_final} {
close $fjson close $fjson
} }
#---------------------------------------------------------------- #-----------------------------------------------------------------------
# Define the "lvs" command as a way of calling the netgen options # Define the "lvs" command as a way of calling the netgen options
# for standard compare, essentially the same as the old "netcomp" # for standard compare, essentially the same as the old "netcomp"
# standalone program. # standalone program.
@ -361,14 +361,20 @@ proc netgen::convert_to_json {filename lvs_final} {
# although if the cells have not been read in yet, then the # although if the cells have not been read in yet, then the
# original syntax of filename or {filename cellname} is required. # original syntax of filename or {filename cellname} is required.
# #
# "args" is passed to verify and may therefore contain only the # "args" may be "-list", "-json", or "-blackbox".
# value "-list" or nothing. If "-list", then output is returned # "-list" returns output as a nested list.
# as a nested list. # "-json" creates a .json-format output file in addition to stdout.
#---------------------------------------------------------------- # "-blackbox" treats empty cells as black-box entries.
# "-noflatten={list}" is a list of cells not to flatten if mismatched.
# i.e., the cells are expected to match and any mismatch cannot be
# expected to be resolved by flattening the contents of the mismatched
# cells.
#-----------------------------------------------------------------------
proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set dolist 0 set dolist 0
set dojson 0 set dojson 0
set noflat {}
foreach arg $args { foreach arg $args {
if {$arg == "-list"} { if {$arg == "-list"} {
puts stdout "Generating list result" puts stdout "Generating list result"
@ -382,6 +388,9 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
} elseif {$arg == "-blackbox"} { } elseif {$arg == "-blackbox"} {
puts stdout "Treating empty subcircuits as black-box cells" puts stdout "Treating empty subcircuits as black-box cells"
netgen::model blackbox on netgen::model blackbox on
} elseif {[string first "-noflatten=" $arg] == 0} {
set noflat [string trim [string range $arg 11 end] \"\{\}]
puts stdout "Will not flatten these subcells: $noflat"
} }
} }
@ -501,6 +510,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
return return
} }
set properr {} set properr {}
set matcherr {}
set pinsgood 0 set pinsgood 0
while {$endval != {}} { while {$endval != {}} {
if {$dolist == 1} { if {$dolist == 1} {
@ -529,9 +539,30 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
# Flatten the non-matching subcircuit (but not the top-level cells) # Flatten the non-matching subcircuit (but not the top-level cells)
if {[netgen::print queue] != {}} { if {[netgen::print queue] != {}} {
netgen::log put " Flattening non-matched subcircuits $endval" if {([lsearch $noflat [lindex $endval 0]] == -1) &&
netgen::flatten class "[lindex $endval 0] $fnum1" ([lsearch $noflat [lindex $endval 1]] == -1)} {
netgen::flatten class "[lindex $endval 1] $fnum2" netgen::log put " Flattening non-matched subcircuits $endval"
netgen::flatten class "[lindex $endval 0] $fnum1"
netgen::flatten class "[lindex $endval 1] $fnum2"
} else {
netgen::log put " Continuing with black-boxed subcircuits $endval"
lappend matcherr [lindex $endval 0]
# 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 {
# Match pins # Match pins
@ -554,9 +585,32 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
} else { } else {
# Flatten the non-matching subcircuit (but not the top-level cells) # Flatten the non-matching subcircuit (but not the top-level cells)
if {[netgen::print queue] != {}} { if {[netgen::print queue] != {}} {
netgen::log put " Flattening non-matched subcircuits $endval" if {([lsearch $noflat [lindex $endval 1]] == -1) &&
netgen::flatten class "[lindex $endval 0] $fnum1" ([lsearch $noflat [lindex $endval 1]] == -1)} {
netgen::flatten class "[lindex $endval 1] $fnum2" netgen::log put " Flattening non-matched subcircuits $endval"
netgen::flatten class "[lindex $endval 0] $fnum1"
netgen::flatten class "[lindex $endval 1] $fnum2"
} else {
netgen::log put " Continuing with black-boxed subcircuits $endval"
lappend matcherr [lindex $endval 0]
netgen::log put " Continuing with black-boxed subcircuits $endval"
lappend matcherr [lindex $endval 0]
# 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 netgen::log echo off
@ -579,6 +633,9 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
if {$properr != {}} { if {$properr != {}} {
netgen::log put "The following cells had property errors: $properr\n" netgen::log put "The following cells had property errors: $properr\n"
} }
if {$matcherr != {}} {
netgen::log put "The following subcells failed to match: $matcherr\n"
}
if {$dolog} { if {$dolog} {
netgen::log end netgen::log end
} }

View File

@ -2827,11 +2827,13 @@ _netcmp_equate(ClientData clientData,
char *name1 = NULL, *name2 = NULL, *optstart; char *name1 = NULL, *name2 = NULL, *optstart;
struct nlist *tp1, *tp2, *SaveC1, *SaveC2; struct nlist *tp1, *tp2, *SaveC1, *SaveC2;
struct objlist *ob1, *ob2; struct objlist *ob1, *ob2;
struct ElementClass *saveEclass = NULL;
struct NodeClass *saveNclass = NULL;
int file1, file2; int file1, file2;
int i, l1, l2, ltest, lent, dolist = 0; int i, l1, l2, ltest, lent, dolist = 0, doforce = 0;
Tcl_Obj *tobj1, *tobj2, *tobj3; Tcl_Obj *tobj1, *tobj2, *tobj3;
if (objc > 1) { while (objc > 1) {
optstart = Tcl_GetString(objv[1]); optstart = Tcl_GetString(objv[1]);
if (*optstart == '-') optstart++; if (*optstart == '-') optstart++;
if (!strcmp(optstart, "list")) { if (!strcmp(optstart, "list")) {
@ -2839,6 +2841,13 @@ _netcmp_equate(ClientData clientData,
objv++; objv++;
objc--; objc--;
} }
else if (!strcmp(optstart, "force")) {
doforce = 1;
objv++;
objc--;
}
else
break;
} }
if ((objc != 2) && (objc != 4) && (objc != 6)) { if ((objc != 2) && (objc != 4) && (objc != 6)) {
@ -2996,6 +3005,12 @@ _netcmp_equate(ClientData clientData,
break; break;
case PINS_IDX: case PINS_IDX:
if ((ElementClasses != NULL) && (doforce == TRUE)) {
saveEclass = ElementClasses;
saveNclass = NodeClasses;
ElementClasses = NULL;
NodeClasses = NULL;
}
if ((ElementClasses == NULL) && (auto_blackbox == FALSE)) { if ((ElementClasses == NULL) && (auto_blackbox == FALSE)) {
if (CurrentCell == NULL) { if (CurrentCell == NULL) {
Fprintf(stderr, "Equate elements: no current cell.\n"); Fprintf(stderr, "Equate elements: no current cell.\n");
@ -3058,6 +3073,12 @@ _netcmp_equate(ClientData clientData,
/* Recover temporarily set global variables (see above) */ /* Recover temporarily set global variables (see above) */
Circuit1 = SaveC1; Circuit1 = SaveC1;
Circuit2 = SaveC2; Circuit2 = SaveC2;
/* Recover ElementClasses if forcing pins on mismatched circuits */
if (doforce == TRUE) {
ElementClasses = saveEclass;
NodeClasses = saveNclass;
}
} }
break; break;