Fixed a bug in the combine routine that causes a segfault; added

preliminary support for a Tcl list output format.
This commit is contained in:
Tim Edwards 2017-01-07 06:56:51 -05:00
parent 4f24915661
commit 8deccaad9c
11 changed files with 7381 additions and 87 deletions

View File

@ -170,7 +170,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SetExtension(name, fname, EXT_EXTENSION);
if ((filenum = OpenParseFile(name, *fnum)) < 0) {
Printf("No file: %s\n",name);
Printf("Error in ext file read: No file %s\n",name);
*fnum = filenum;
return NULL;
}
@ -643,7 +643,7 @@ char *ReadSim(char *fname, int *fnum)
SetExtension(name, fname, SIM_EXTENSION);
if (OpenParseFile(name, *fnum) < 0) {
Printf("No file: %s\n",name);
Printf("Error in ext file read: No file %s\n",name);
*fnum = filenum;
return NULL;
}

File diff suppressed because it is too large Load Diff

6423
base/netcmp.c.orig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@ extern struct nlist *Circuit2;
extern int ExhaustiveSubdivision;
#ifdef TCL_NETGEN
#include <tcl.h>
extern int InterruptPending;
#endif
@ -17,10 +18,11 @@ extern int InterruptPending;
extern void PrintElementClasses(struct ElementClass *EC, int type, int dolist);
extern void PrintNodeClasses(struct NodeClass *NC, int type, int dolist);
extern void SummarizeNodeClasses(struct NodeClass *NC);
extern void PrintPropertyResults(void);
extern void PrintPropertyResults(int do_list);
extern void PrintCoreStats(void);
extern void ResetState(void);
extern void CreateTwoLists(char *name1, int file1, char *name2, int file2);
extern void CreateTwoLists(char *name1, int file1, char *name2, int file2,
int dolist);
extern int Iterate(void);
extern int VerifyMatching(void);
extern void PrintAutomorphisms(void);
@ -33,7 +35,7 @@ extern int EquivalenceElements(char *name1, int file1, char *name2, int file2);
extern int EquivalenceNodes(char *name1, int file1, char *name2, int file2);
extern int EquivalenceClasses(char *name1, int file1, char *name2, int file2);
extern int IgnoreClass(char *name, int file, unsigned char type);
extern int MatchPins(struct nlist *tp1, struct nlist *tp2);
extern int MatchPins(struct nlist *tp1, struct nlist *tp2, int dolist);
extern int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int serial);
extern int CreateCompareQueue(char *, int, char *, int);
@ -51,5 +53,8 @@ extern int EquivalentElement();
extern void enable_interrupt();
extern void disable_interrupt();
extern Tcl_Obj *ListNodeClasses(int legal);
extern Tcl_Obj *ListElementClasses(int legal);
#endif

View File

@ -77,8 +77,9 @@ extern char *SetExtension(char *buffer, char *path, char *extension)
strcat(tmpbuf, extension);
/* step 4: lower-case the entire name */
for (pt = tmpbuf; *pt != '\0'; pt++)
if (isupper(*pt)) *pt = tolower(*pt);
/* (Commented out because this is really stupid.) */
// for (pt = tmpbuf; *pt != '\0'; pt++)
// if (isupper(*pt)) *pt = tolower(*pt);
if (buffer != NULL) {
strcpy(buffer, tmpbuf);
@ -567,7 +568,7 @@ char *ReadNetgenFile (char *fname, int *fnum)
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
SetExtension(name, fname, NETGEN_EXTENSION);
if ((filenum = OpenParseFile(name, *fnum)) < 0) {
Printf("No file: %s\n",name);
Printf("Error in netgen read: No file %s\n",name);
*fnum = -1;
return NULL;
}
@ -803,7 +804,7 @@ char *ReadNetgenFile (char *fname, int *fnum)
if ((File = open(fname, O_RDONLY, FILE_ACCESS_BITS)) == -1) {
SetExtension(name, fname, NETGEN_EXTENSION);
if ((File = open(name, O_RDONLY, FILE_ACCESS_BITS)) == -1) {
Printf("No file: %s\n",name);
Printf("Error in netgen read: No file %s\n",name);
return NULL;
}
}

View File

@ -3072,7 +3072,7 @@ int CombineParallel(char *model, int file)
pob = ob2;
pcnt += 10;
}
if (ob2->type == PROPERTY) propfirst = ob2;
if (ob2 && (ob2->type == PROPERTY)) propfirst = ob2;
/* Find last record in device and first record in next object */
while (ob2 && ob2->type == PROPERTY) {

View File

@ -186,7 +186,7 @@ char *ReadNtk (char *fname, int *fnum)
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
SetExtension(name, fname, NTK_EXTENSION);
if ((filenum = OpenParseFile(name, *fnum)) < 0) {
Printf("No file: %s\n",name);
Printf("Error in ntk file read: No file %s\n",name);
*fnum = filenum;
return NULL;
}

View File

@ -1808,7 +1808,7 @@ char *ReadSpiceTop(char *fname, int *fnum, int blackbox)
SetExtension(name, fname, SPICE_EXTENSION);
if ((filenum = OpenParseFile(name, *fnum)) < 0) {
Fprintf(stderr,"No file: %s\n",name);
Fprintf(stderr,"Error in SPICE file read: No file %s\n",name);
*fnum = filenum;
return NULL;
}
@ -1903,7 +1903,7 @@ void IncludeSpice(char *fname, int parent, struct cellstack **CellStackPtr,
SetExtension(name, fname, SPICE_EXTENSION);
if ((filenum = OpenParseFile(name, parent)) < 0) {
Fprintf(stderr,"No file: %s\n",name);
Fprintf(stderr,"Error in SPICE file read: No file %s\n",name);
return;
}
}

View File

@ -271,7 +271,7 @@ void initialize_netcmp_datastructures(Widget w, Widget textwidget,
{
X_START();
Printf("Comparing cells '%s' and '%s'\n", get_cell(), get_other());
CreateTwoLists(get_cell(), get_other());
CreateTwoLists(get_cell(), get_other(), 0);
Permute();
#ifdef DEBUG_ALLOC
PrintCoreStats();

View File

@ -34,9 +34,22 @@ if {${tcl_version} >= 8.6} {
# Use the "canonical" command to parse the file and cell names,
# although if the cells have not been read in yet, then the
# original syntax of filename or {filename cellname} is required.
#
# "args" is passed to verify and may therefore contain only the
# value "-list" or nothing. If "-list", then output is returned
# as a nested list.
#----------------------------------------------------------------
proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out}} {
proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set dolist 0
puts stdout "Diagnostic version"
foreach arg $args {
if {$arg == "-list"} {
puts stdout "Generating list result"
set dolist 1
set lvs_final {}
}
}
# Allow name1 or name2 to be a list of {filename cellname},
# A single <filename>, or any valid_cellname form if the
@ -137,24 +150,40 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out}} {
netgen::log file $logfile
netgen::log start
netgen::log echo off
set endval [netgen::compare hierarchical "$fnum1 $cell1" "$fnum2 $cell2"]
if {$dolist == 1} {
set endval [netgen::compare -list hierarchical "$fnum1 $cell1" "$fnum2 $cell2"]
} else {
set endval [netgen::compare hierarchical "$fnum1 $cell1" "$fnum2 $cell2"]
}
if {$endval == {}} {
netgen::log put "No cells in queue!\n"
return
}
set properr {}
while {$endval != {}} {
netgen::run converge
if {$dolist == 1} {
netgen::run -list converge
} else {
netgen::run converge
}
netgen::log echo on
if {[verify equivalent]} {
# Resolve automorphisms by pin and property
netgen::run resolve
if {$dolist == 1} {
netgen::run -list resolve
} else {
netgen::run resolve
}
set uresult [verify unique]
if {$uresult == 0} {
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::verify nodes
if {$dolist == 1} {
verify -list nodes
} else {
verify nodes
}
# Flatten the non-matching subcircuit (but not the top-level cells)
if {[netgen::print queue] != {}} {
@ -183,17 +212,26 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out}} {
}
}
netgen::log echo off
set endval [netgen::compare hierarchical]
if {$dolist == 1} {
catch {lappend lvs_final $lvs_out}
set lvs_out {}
set endval [netgen::compare -list hierarchical]
} else {
set endval [netgen::compare hierarchical]
}
}
netgen::log echo off
puts stdout "Result: " nonewline
netgen::log echo on
netgen::verify only
verify only
if {$properr != {}} {
netgen::log put "The following cells had property errors: $properr\n"
}
netgen::log end
puts stdout "LVS Done."
if {$dolist == 1} {
return $lvs_final
}
}
# It is important to make sure no netgen commands overlap with Tcl built-in

View File

@ -1939,13 +1939,24 @@ int
_netcmp_compare(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *name1, *name2, *file1, *file2;
int fnum1, fnum2;
char *name1, *name2, *file1, *file2, *optstart;
int fnum1, fnum2, dolist = 0;
int dohierarchy = FALSE;
int assignonly = FALSE;
int argstart = 1, qresult, llen, result;
struct Correspond *nextcomp;
struct nlist *tp;
Tcl_Obj *flist = NULL;
if (objc > 1) {
optstart = Tcl_GetString(objv[1]);
if (*optstart == '-') optstart++;
if (!strcmp(optstart, "list")) {
dolist = 1;
objv++;
objc--;
}
}
if (objc > 1) {
if (!strncmp(Tcl_GetString(objv[argstart]), "assign", 6)) {
@ -2033,18 +2044,15 @@ _netcmp_compare(ClientData clientData,
ConvertGlobals(name2, fnum2);
}
// Run cleanup a 2nd time; this corrects for cells that have no ports
// but define global nodes that are brought out as ports by
// ConvertGlobals().
CreateTwoLists(name1, fnum1, name2, fnum2);
CreateTwoLists(name1, fnum1, name2, fnum2, dolist);
while (PrematchLists(name1, fnum1, name2, fnum2) > 0) {
Fprintf(stdout, "Making another compare attempt.\n");
CreateTwoLists(name1, fnum1, name2, fnum2);
CreateTwoLists(name1, fnum1, name2, fnum2, dolist);
}
// Return the names of the two cells being compared, if doing "compare
// hierarchical"
// hierarchical". If "-list" was specified, then append the output
// to the end of the list.
if (dohierarchy) {
Tcl_Obj *lobj;
@ -2242,6 +2250,19 @@ _netcmp_run(ClientData clientData,
};
int result, index;
int automorphisms;
char *optstart;
int dolist;
dolist = 0;
if (objc > 1) {
optstart = Tcl_GetString(objv[1]);
if (*optstart == '-') optstart++;
if (!strcmp(optstart, "list")) {
dolist = 1;
objv++;
objc--;
}
}
if (objc == 1)
index = RESOLVE_IDX;
@ -2260,8 +2281,13 @@ _netcmp_run(ClientData clientData,
else {
enable_interrupt();
while (!Iterate() && !InterruptPending);
_netcmp_verify(clientData, interp, 1, NULL);
if (dolist) {
result = _netcmp_verify(clientData, interp, 2, objv - 1);
}
else
result = _netcmp_verify(clientData, interp, 1, NULL);
disable_interrupt();
if (result != TCL_OK) return result;
}
break;
case RESOLVE_IDX:
@ -2304,7 +2330,7 @@ _netcmp_run(ClientData clientData,
}
if (PropertyErrorDetected) {
Fprintf(stdout, "There were property errors.\n");
PrintPropertyResults();
PrintPropertyResults(dolist);
}
disable_interrupt();
}
@ -2318,9 +2344,17 @@ _netcmp_run(ClientData clientData,
/* Syntax: netgen::verify [option] */
/* options: nodes, elements, only, all, */
/* equivalent, or unique. */
/* option "-list" may be used with nodes, elements */
/* all, or no option. */
/* Formerly: v */
/* Results: */
/* For only, equivalent, unique: Return 1 if */
/* verified, zero if not. */
/* Side Effects: */
/* For options elements, nodes, and all without */
/* option -list: Write output to log file. */
/* For -list options, append list to global */
/* variable "lvs_out", if it exists. */
/*------------------------------------------------------*/
int
@ -2333,8 +2367,23 @@ _netcmp_verify(ClientData clientData,
enum OptionIdx {
NODE_IDX, ELEM_IDX, PROP_IDX, ONLY_IDX, ALL_IDX, EQUIV_IDX, UNIQUE_IDX
};
char *optstart;
int result, index = -1;
int automorphisms;
int dolist = 0;
Tcl_Obj *egood, *ebad, *ngood, *nbad;
if (objc > 1) {
optstart = Tcl_GetString(objv[1]);
if (*optstart == '-') optstart++;
if (!strcmp(optstart, "list")) {
dolist = 1;
egood = ngood = NULL;
ebad = nbad = NULL;
objv++;
objc--;
}
}
if (objc != 1 && objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv,
@ -2365,14 +2414,28 @@ _netcmp_verify(ClientData clientData,
if (objc == 1 || index == NODE_IDX || index == ALL_IDX) {
if (Debug == TRUE)
PrintIllegalNodeClasses(); // Old style
else
FormatIllegalNodeClasses(); // Side-by-side
else {
FormatIllegalNodeClasses(); // Side-by-side, to log file
if (dolist) {
nbad = ListNodeClasses(FALSE); // As Tcl nested list
#if 0
ngood = ListNodeClasses(TRUE); // As Tcl nested list
#endif
}
}
}
if (objc == 1 || index == ELEM_IDX || index == ALL_IDX) {
if (Debug == TRUE)
PrintIllegalElementClasses(); // Old style
else
FormatIllegalElementClasses(); // Side-by-side
else {
FormatIllegalElementClasses(); // Side-by-side, to log file
if (dolist) {
ebad = ListElementClasses(FALSE); // As Tcl nested list
#if 0
egood = ListElementClasses(TRUE); // As Tcl nested list
#endif
}
}
}
disable_interrupt();
if (index == EQUIV_IDX || index == UNIQUE_IDX)
@ -2403,9 +2466,73 @@ _netcmp_verify(ClientData clientData,
Fprintf(stdout, "Property errors were found.\n");
}
}
if ((index == PROP_IDX) && (PropertyErrorDetected != 0)) {
PrintPropertyResults();
#if 0
if (dolist) {
ngood = ListNodeClasses(TRUE); // As Tcl nested list
egood = ListElementClasses(TRUE); // As Tcl nested list
}
#endif
if ((index == PROP_IDX) && (PropertyErrorDetected != 0)) {
PrintPropertyResults(dolist);
}
}
}
/* If "dolist" has been specified, then return the */
/* list-formatted output. For "verify nodes" or */
/* "verify elements", return the associated list. */
/* For "verify" or "verify all", return a nested */
/* list of {node list, element list}. */
if (dolist)
{
if (objc == 1 || index == NODE_IDX || index == ALL_IDX) {
if (nbad == NULL) {
Tcl_Obj *n0, *n1;
nbad = Tcl_NewListObj(0, NULL);
n0 = Tcl_NewStringObj("badnets", -1);
n1 = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(netgeninterp, nbad, n0);
Tcl_ListObjAppendElement(netgeninterp, nbad, n1);
}
Tcl_SetVar2Ex(interp, "lvs_out", NULL, nbad,
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
#if 0
if (ngood == NULL) {
Tcl_Obj *n0, *n1;
ngood = Tcl_NewListObj(0, NULL);
n0 = Tcl_NewStringObj("goodnets", -1);
n1 = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(netgeninterp, ngood, n0);
Tcl_ListObjAppendElement(netgeninterp, ngood, n1);
}
Tcl_SetVar2Ex(interp, "lvs_out", NULL, ngood,
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
#endif
}
if (objc == 1 || index == ELEM_IDX || index == ALL_IDX) {
if (ebad == NULL) {
Tcl_Obj *e0, *e1;
ebad = Tcl_NewListObj(0, NULL);
e0 = Tcl_NewStringObj("badelements", -1);
e1 = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(netgeninterp, ebad, e0);
Tcl_ListObjAppendElement(netgeninterp, ebad, e1);
}
Tcl_SetVar2Ex(interp, "lvs_out", NULL, ebad,
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
#if 0
if (egood == NULL) {
Tcl_Obj *e0, *e1;
ebad = Tcl_NewListObj(0, NULL);
e0 = Tcl_NewStringObj("goodelements", -1);
e1 = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(netgeninterp, egood, e0);
Tcl_ListObjAppendElement(netgeninterp, egood, e1);
}
Tcl_SetVar2Ex(interp, "lvs_out", NULL, egood,
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
#endif
}
}
return TCL_OK;
@ -2566,13 +2693,23 @@ _netcmp_equate(ClientData clientData,
NODE_IDX, ELEM_IDX, CLASS_IDX, PINS_IDX
};
int result, index;
char *name1 = NULL, *name2 = NULL;
char *name1 = NULL, *name2 = NULL, *optstart;
struct nlist *tp1, *tp2;
struct objlist *ob1, *ob2;
int file1, file2;
int i, l1, l2, ltest, lent;
int i, l1, l2, ltest, lent, dolist;
Tcl_Obj *tobj1, *tobj2, *tobj3;
if (objc > 1) {
optstart = Tcl_GetString(objv[1]);
if (*optstart == '-') optstart++;
if (!strcmp(optstart, "list")) {
dolist = 1;
objv++;
objc--;
}
}
if ((objc != 2) && (objc != 4) && (objc != 6)) {
Tcl_WrongNumArgs(interp, 1, objv, "?nodes|elements|classes|pins? name1 name2");
return TCL_ERROR;
@ -2737,7 +2874,8 @@ _netcmp_equate(ClientData clientData,
return TCL_OK;
}
if (tp1 == Circuit1 && tp2 == Circuit2) {
if (MatchPins(tp1, tp2)) {
int result;
if (MatchPins(tp1, tp2, dolist)) {
Fprintf(stdout, "Cell pin lists are equivalent.\n");
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
}
@ -2748,7 +2886,7 @@ _netcmp_equate(ClientData clientData,
}
}
else {
Fprintf(stderr, "Function not yet defined outside of LVS scope.\n");
Fprintf(stderr, "Function not defined outside of LVS scope.\n");
}
break;