Compare commits

...
9 Commits
Author SHA1 Message Date
Tim Edwards bd356553fd Merge branch 'master' into work 2017-01-07 06:57:27 -05:00
Tim Edwards 46458f2836 Update at Sat Jan 7 06:57:25 EST 2017 by tim 2017-01-07 06:57:25 -05:00
Tim Edwards 8deccaad9c Fixed a bug in the combine routine that causes a segfault; added
preliminary support for a Tcl list output format.
2017-01-07 06:56:51 -05:00
Tim Edwards 4f24915661 Correction to device property matching code to fix a problem that
caused LVS(A, B) to give different results for property errors
than LVS(B, A).
2016-12-12 13:31:56 -05:00
Tim Edwards fdab366627 Corrected typo with == vs. = 2016-12-12 11:51:24 -05:00
Tim Edwards 310d7512a0 Removed backup file. 2016-12-12 11:32:52 -05:00
Tim Edwards 86f52b164a Merge branch 'master' into work 2016-12-12 11:32:44 -05:00
Tim Edwards 4a47c3076d Update at Mon Dec 12 11:32:42 EST 2016 by tim 2016-12-12 11:32:42 -05:00
Tim Edwards 777498b30e Completed the implementation of serial/parallel device network
matching.
2016-12-12 11:32:07 -05:00
14 changed files with 8537 additions and 511 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.68
1.5.70
+2 -2
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;
}
+1687 -329
View File
File diff suppressed because it is too large Load Diff
+6423
View File
File diff suppressed because it is too large Load Diff
+9 -3
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,8 @@ 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);
extern int GetCompareQueueTop(char **, int *, char **, int *);
@@ -50,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
+5 -4
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;
}
}
+176 -132
View File
@@ -948,10 +948,10 @@ PropertyTolerance(char *name, int fnum, char *key, int ival, double dval)
switch (kl->type) {
case PROP_DOUBLE:
case PROP_VALUE:
case PROP_STRING:
kl->slop.dval = dval;
break;
case PROP_INTEGER:
case PROP_STRING:
case PROP_EXPRESSION:
kl->slop.ival = ival;
break;
@@ -1103,15 +1103,15 @@ struct property *PropertyInteger(char *name, int fnum, char *key,
/*----------------------------------------------------------------------*/
struct property *PropertyString(char *name, int fnum, char *key, int range,
struct property *PropertyString(char *name, int fnum, char *key, double dval,
char *pdefault)
{
struct property *kl = NULL;
struct nlist *tc;
if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
PropertyString(name, Circuit1->file, key, range, pdefault);
PropertyString(name, Circuit2->file, key, range, pdefault);
PropertyString(name, Circuit1->file, key, dval, pdefault);
PropertyString(name, Circuit2->file, key, dval, pdefault);
return;
}
@@ -1127,7 +1127,7 @@ struct property *PropertyString(char *name, int fnum, char *key, int range,
kl->idx = 0;
kl->merge = MERGE_NONE;
kl->type = PROP_STRING;
kl->slop.ival = (range >= 0) ? range : 0;
kl->slop.dval = dval;
if (pdefault != NULL)
kl->pdefault.string = strsave(pdefault);
else
@@ -2054,7 +2054,7 @@ struct objlist *LinkProperties(char *model, struct keyvalue *topptr)
kl->idx = 0;
kl->merge = MERGE_NONE;
kl->type = PROP_STRING;
kl->slop.ival = 0;
kl->slop.dval = 0.0;
kl->pdefault.string = NULL;
HashPtrInstall(kl->key, kl, &(cell->propdict));
}
@@ -2318,7 +2318,7 @@ void ResolveProperties(char *name1, int file1, char *name2, int file2)
switch (kl1->type) {
case PROP_STRING:
kl2 = PropertyString(tp2->name, tp2->file, kl1->key,
kl1->slop.ival, kl1->pdefault.string);
kl1->slop.dval, kl1->pdefault.string);
break;
case PROP_INTEGER:
kl2 = PropertyInteger(tp2->name, tp2->file, kl1->key,
@@ -2350,7 +2350,7 @@ void ResolveProperties(char *name1, int file1, char *name2, int file2)
switch (kl2->type) {
case PROP_STRING:
kl1 = PropertyString(tp1->name, tp1->file, kl2->key,
kl2->slop.ival, kl2->pdefault.string);
kl2->slop.dval, kl2->pdefault.string);
break;
case PROP_INTEGER:
kl1 = PropertyInteger(tp1->name, tp1->file, kl2->key,
@@ -2884,10 +2884,10 @@ void ConnectAllNodes(char *model, int file)
/* 2) Always tag B with "serial". */
/* */
/* Tags are indicated by a property named "_tag" which has a string */
/* value of ordered characters, "S" for serial, "O" for open, and "C" */
/* value of ordered characters, "+" for serial, "(" for open, and ")" */
/* for close. A device with only one property record has no "_tag" */
/* record. A device which is in parallel with the device(s) in front */
/* of it is implicitly parallel by not having an "S" tag, and may not */
/* of it is implicitly parallel by not having an "+" tag, and may not */
/* have a tag at all. */
/* */
/* The property check routine is responsible for comparing device */
@@ -2979,9 +2979,9 @@ void add_balancing_close(struct objlist *ob1, struct objlist *ob2)
if (kv->type == PROP_ENDLIST) break;
if (kv->type == PROP_STRING) {
if (!strcmp(kv->key, "_tag")) {
for (tag == kv->value.string; *tag != '\0'; tag++) {
if (*tag == 'O') opentags++;
else if (*tag == 'C') opentags--;
for (tag = kv->value.string; *tag != '\0'; tag++) {
if (*tag == '(') opentags++;
else if (*tag == ')') opentags--;
}
break;
}
@@ -2997,7 +2997,7 @@ void add_balancing_close(struct objlist *ob1, struct objlist *ob2)
if (nob->type != PROPERTY) return; // shouldn't happen
// This is slow but it's the easiest way to do it
while (opentags-- > 0) add_prop_tag(nob, 'C');
while (opentags-- > 0) add_prop_tag(nob, ')');
}
/*----------------------------------------------------------------------*/
@@ -3024,7 +3024,8 @@ int CombineParallel(char *model, int file)
{
struct nlist *tp, *tsub;
struct objlist *ob, *ob2, *nextob;
struct objlist *sob, *lob, *tlob, *nob, *pob, *obr;
struct objlist *sob, *lob, *nob, *pob, *obr;
struct objlist *propfirst, *proplast, *spropfirst, *sproplast;
struct hashdict devdict;
struct Permutation *perm;
size_t pcnt;
@@ -3048,6 +3049,7 @@ int CombineParallel(char *model, int file)
tsub = LookupCellFile(ob->model.class, file);
if ((tsub != NULL) && (tsub->flags & COMB_NO_PARALLEL)) {
lob = ob;
ob = ob->next;
continue;
}
@@ -3064,14 +3066,17 @@ int CombineParallel(char *model, int file)
pcnt = strlen(ob->model.class) + 2;
pptr = (char *)pcnt;
propfirst = proplast = NULL;
for (ob2 = ob; ob2 && (ob2->type > FIRSTPIN || ob2 == ob); ob2 = ob2->next) {
tlob = ob2;
pob = ob2;
pcnt += 10;
}
if (ob2 && (ob2->type == PROPERTY)) propfirst = ob2;
/* Find last record in device and first record in next object */
while (ob2 && ob2->type == PROPERTY) {
tlob = ob2;
proplast = ob2;
ob2 = ob2->next;
}
nextob = ob2;
@@ -3128,73 +3133,117 @@ int CombineParallel(char *model, int file)
FREE((char *)p2str);
}
/* Set last object ptr to end of this record */
lob = tlob;
/* Move last object marker to end of sob record */
if (proplast != NULL)
lob = proplast;
else
lob = pob;
}
else {
/* Find parallel device "ob" and append properties of */
/* "sob" to it. If "ob" does not have properties, then */
/* create a property record and set property "M" to 2. */
for (obr = ob; obr != ob2 ; ) {
/* Find last non-property record of sob ( = pob) */
/* Find first property record of sob ( = spropfirst) */
/* Find last property record of sob ( = sproplast) */
spropfirst = sproplast = NULL;
for (ob2 = sob; ob2->type > FIRSTPIN || ob2 == sob; ob2 = ob2->next)
pob = ob2;
if (ob2->type == PROPERTY) spropfirst = ob2;
for (; ob2->type == PROPERTY; ob2 = ob2->next)
sproplast = ob2;
if (spropfirst == NULL) {
/* Create new property instance record if one doesn't exist */
nob = GetObject();
nob->type = PROPERTY;
nob->name = strsave("properties");
nob->node = -2; /* Don't report as disconnected node */
nob->model.class = strsave(sob->model.class);
nob->instance.props = NewPropValue(2);
/* Create property record for property "M" and set to 1 */
kv = &(nob->instance.props[0]);
kv->key = strsave("M");
kv->type = PROP_INTEGER;
kv->value.ival = 1;
/* End of property list */
kv = &(nob->instance.props[1]);
kv->key = NULL;
kv->type = PROP_ENDLIST;
kv->value.ival = 0;
nob->next = pob->next;
pob->next = nob;
if (lob == pob) lob = nob;
spropfirst = sproplast = nob;
}
if (propfirst == NULL) {
/* Create new property instance record if one doesn't exist */
nob = GetObject();
nob->type = PROPERTY;
nob->name = strsave("properties");
nob->node = -2; /* Don't report as disconnected node */
nob->model.class = strsave(ob->model.class);
nob->instance.props = NewPropValue(2);
/* Create property record for property "M" and set to 1 */
kv = &(nob->instance.props[0]);
kv->key = strsave("M");
kv->type = PROP_INTEGER;
kv->value.ival = 1;
/* End of property list */
kv = &(nob->instance.props[1]);
kv->key = NULL;
kv->type = PROP_ENDLIST;
kv->value.ival = 0;
/* Append to sob's property list */
nob->next = sproplast->next;
sproplast->next = nob;
if (lob == sproplast) lob = nob;
}
if (propfirst != NULL) {
// Serial/Parallel logic:
// If propfirst has _tag in properties,
// then add an "open" tag at propfirst
add_prop_tag(propfirst, '(');
// if spropfirst has _tag in properties then add an "open" tag
// to spropfirst and a "close" tag to propfirst
if (add_prop_tag(spropfirst, '(')) add_prop_tag(propfirst, ')');
/* Append ob's property list to sob */
proplast->next = sproplast->next;
sproplast->next = propfirst;
if (lob == sproplast) lob = proplast;
}
/* Link up around object to be removed */
lob->next = nextob;
/* Remove the object */
for (obr = ob; obr != propfirst && obr != nextob; ) {
nob = obr->next;
FreeObjectAndHash(obr, tp);
obr = nob;
}
dcnt++;
/* Find (first) property record of sob */
for (pob = sob->next; pob->type > FIRSTPIN; pob = pob->next) {
if (pob->next->type == PROPERTY)
break;
else if (pob->next->type == FIRSTPIN) {
/* Create new property instance record if one doesn't exist */
nob = GetObject();
nob->type = PROPERTY;
nob->name = strsave("properties");
nob->node = -2; /* Don't report as disconnected node */
nob->model.class = strsave(sob->model.class);
nob->instance.props = NewPropValue(2);
/* Create property record for property "M" and set to 1 */
kv = &(nob->instance.props[0]);
kv->key = strsave("M");
kv->type = PROP_INTEGER;
kv->value.ival = (obr->type != PROPERTY) ? 2 : 1;
/* End of property list */
kv = &(nob->instance.props[1]);
kv->key = NULL;
kv->type = PROP_ENDLIST;
kv->value.ival = 0;
nob->next = pob->next;
pob->next = nob;
break;
}
}
if (lob == pob) lob = tlob;
if (obr->type == PROPERTY) {
/* Pull out property records and append to sob's */
/* property list */
tlob->next = pob->next;
pob->next = obr;
}
lob->next = nextob;
// Serial/Parallel logic:
// If obr has _tag in properties, then add an "open" tag at obr
add_prop_tag(obr, 'O');
// if ob2 has _tag in properties then add an "open" tag to ob2
// and a "close" tag to obr
if (add_prop_tag(ob2, 'O')) add_prop_tag(obr, 'C');
}
FREE((char *)pstr);
}
else
else {
lob = ob;
nextob = ob->next;
}
ob = nextob;
}
HashKill(&devdict);
@@ -3260,7 +3309,7 @@ int CombineSerial(char *model, int file)
// To avoid posting a non-working version, serial combination is
// disabled here until code is finished to compare the serial/parallel
// property networks.
return 0;
// return 0;
if ((tp = LookupCellFile(model, file)) == NULL) {
Printf("Cell: %s does not exist.\n", model);
@@ -3325,83 +3374,78 @@ int CombineSerial(char *model, int file)
for (i = 0; i <= tp->nodename_cache_maxnodenum; i++) {
if (instlist[i] != NULL) {
if ((instlist[i][0] != NULL) && (instlist[i][1] != NULL)) {
Fprintf(stdout, "Found serial instances %s and %s\n",
int k, l;
struct valuelist *kv2;
/* Diagnostic */
/* Fprintf(stdout, "Found serial instances %s and %s\n",
instlist[i][0]->instance.name,
instlist[i][1]->instance.name);
instlist[i][1]->instance.name); */
scnt++;
/* Diagnostic */
/* Printf("CombineSerial: Merging serial instances %s (0x%x) and %s (0x%x)"
", remove node %s (%d)\n",
instlist[i][0]->instance.name,
instlist[i][0],
instlist[i][1]->instance.name,
instlist[i][1],
tp->nodename_cache[i]->name, i); */
/* To maintain knowledge of the topology, each device gets */
/* a parameter '_tag', string value set to "S". */
/* To maintain knowledge of the topology, 2nd device gets */
/* a parameter '_tag', string value set to "+". */
for (j = 0; j <= 1; j++) {
for (obp = instlist[i][j]; ; obp = obp->next) {
int found = FALSE;
int k, l;
char *nodename1, *nodename2;
struct valuelist *kv2;
for (obn = instlist[i][1]; obn->next &&
obn->next->type != PROPERTY &&
obn->next->type != FIRSTPIN; obn = obn->next);
obp = obn->next;
nodename1 = tp->nodename_cache[instlist[i][j]->node]->name;
nodename2 = tp->nodename_cache[instlist[i][j]->next->node]->name;
if (obp->type == PROPERTY) {
/* Add to properties */
k = 0;
for (k = 0; ; k++) {
kv = &(obp->instance.props[k]);
if (kv->type == PROP_ENDLIST)
break;
}
if (obp == NULL || obp->type == FIRSTPIN) {
struct objlist *nob;
/* No property record, so insert one */
nob = GetObject();
nob->type = PROPERTY;
nob->name = strsave("properties");
nob->node = -2; /* Don't report as disconnected node */
nob->model.class = (obp->model.class == NULL) ? NULL :
strsave(obp->model.class);
nob->instance.props = NewPropValue(2);
/* Create property record for property "_tag" */
kv = &(nob->instance.props[0]);
kv->key = strsave("_tag");
kv->type = PROP_STRING;
/* Value is set to "+" */
kv->value.string = (char *)MALLOC(2);
sprintf(kv->value.string, "+");
/* End of property list */
kv = &(nob->instance.props[1]);
kv->key = NULL;
kv->type = PROP_ENDLIST;
kv->value.ival = 0;
nob->next = obp;
obn->next = nob;
}
else if (obp->type == PROPERTY) {
/* Add to properties */
k = 0;
for (k = 0; ; k++) {
kv = &(obp->instance.props[k]);
if (kv->type == PROP_ENDLIST) {
kv2 = (struct valuelist *)MALLOC((k + 2) *
sizeof(struct valuelist));
kv2->key = strsave("_tag");
kv2->type = PROP_STRING;
/* Value is set to "S" */
/* Value is set to "+" */
kv2->value.string = (char *)MALLOC(2);
sprintf(kv2->value.string, "S");
sprintf(kv2->value.string, "+");
for (l = 0; l <= k; l++)
kv2[l + 1] = obp->instance.props[l];
kv2[l + 1] = obp->instance.props[l];
FREE(obp->instance.props);
obp->instance.props = kv2;
found = TRUE;
}
if (obp->next == NULL || obp->next->type == FIRSTPIN) {
struct objlist *nob;
/* No property record, so insert one */
if (found == FALSE) {
nob = GetObject();
nob->type = PROPERTY;
nob->name = strsave("properties");
nob->node = -2; /* Don't report as disconnected node */
nob->model.class = (obp->model.class == NULL) ? NULL :
strsave(obp->model.class);
nob->instance.props = NewPropValue(2);
/* Create property record for property "_tag" */
kv = &(nob->instance.props[0]);
kv->key = strsave("_tag");
kv->type = PROP_STRING;
/* Value is set to "S" */
kv->value.string = (char *)MALLOC(2);
sprintf(kv->value.string, "S");
/* End of property list */
kv = &(nob->instance.props[1]);
kv->key = NULL;
kv->type = PROP_ENDLIST;
kv->value.ival = 0;
nob->next = obp->next;
obp->next = nob;
}
break;
}
}
else if (!strcmp(kv->key, "_tag")) {
int l = strlen(kv->value.string);
char *newstr = (char *)MALLOC(l + 2);
sprintf(newstr, "S%s", kv->value.string);
FREE(kv->value.string);
kv->value.string = newstr;
break;
}
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ extern struct property *PropertyDouble(char *name, int fnum, char *key,
extern struct property *PropertyInteger(char *name, int fnum, char *key,
int slop, int pdefault);
extern struct property *PropertyString(char *name, int fnum, char *key,
int range, char *pdefault);
double slop, char *pdefault);
extern int PropertyDelete(char *name, int fnum, char *key);
extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
double dval);
+1 -1
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;
}
+4 -2
View File
@@ -104,10 +104,12 @@ struct valuelist {
/* Part 3: Keys & Defaults (kept in the cell record as a hash table) */
#define MERGE_NONE 0 /* Property does not change when devices merge */
#define MERGE_ADD 1 /* Properties sum with device merge */
#define MERGE_ADD_CRIT 2 /* Properties sum with device merge */
#define MERGE_ADD 1 /* Properties sum with device parallel merge */
#define MERGE_ADD_CRIT 2 /* Properties sum with device parallel merge */
#define MERGE_PAR 3 /* Properties add in parallel with device merge */
#define MERGE_PAR_CRIT 4 /* Properties add in parallel with device merge */
#define MERGE_SER 5 /* Properties sum with device parallel merge */
#define MERGE_SER_CRIT 6 /* Properties sum with device parallel merge */
/* Note: A "critical" merge means that the property causes the number of */
/* devices to change. e.g., transistor width is critical; transistor drain */
+3 -3
View File
@@ -795,7 +795,7 @@ skip_ends:
kl->key = strsave(nexttok);
kl->idx = 0;
kl->type = PROP_STRING;
kl->slop.ival = 0;
kl->slop.dval = 0.0;
kl->pdefault.string = strsave(eqptr + 1);
HashPtrInstall(nexttok, kl, &spiceparams);
}
@@ -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;
}
}
+1 -1
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();
+45 -7
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
+179 -25
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;
@@ -3008,13 +3146,18 @@ _netcmp_property(ClientData clientData,
};
char *mergeoptions[] = {
"none", "add", "add_critical", "par", "par_critical", NULL
"none", "add", "add_critical", "par", "par_critical",
"parallel", "parallel_critical", "ser_critical", "ser",
"serial_critical", "serial", NULL
};
enum MergeOptionIdx {
NONE_IDX, ADD_ONLY_IDX, ADD_CRIT_IDX, PAR_ONLY_IDX, PAR_CRIT_IDX
NONE_IDX, ADD_ONLY_IDX, ADD_CRIT_IDX,
PAR_ONLY_IDX, PAR_CRIT_IDX, PAR2_ONLY_IDX, PAR2_CRIT_IDX,
SER_CRIT_IDX, SER_IDX, SER2_CRIT_IDX, SER2_IDX
};
char *yesno[] = {
"on", "yes", "true", "enable", "allow", "off", "no", "false", "disable", "prohibit", NULL
"on", "yes", "true", "enable", "allow",
"off", "no", "false", "disable", "prohibit", NULL
};
if (objc < 2) {
@@ -3043,7 +3186,8 @@ _netcmp_property(ClientData clientData,
PropertyDelete(tp->name, tp->file, "pd");
break;
case CLASS_RES: case CLASS_RES3:
PropertyMerge(tp->name, tp->file, "l", MERGE_PAR_CRIT);
PropertyMerge(tp->name, tp->file, "w", MERGE_ADD_CRIT);
PropertyMerge(tp->name, tp->file, "l", MERGE_SER_CRIT);
tp->flags |= COMB_SERIAL;
break;
case CLASS_CAP: case CLASS_ECAP: case CLASS_CAP3:
@@ -3351,11 +3495,21 @@ _netcmp_property(ClientData clientData,
mergeval = MERGE_ADD_CRIT;
break;
case PAR_ONLY_IDX:
case PAR2_ONLY_IDX:
mergeval = MERGE_PAR;
break;
case PAR_CRIT_IDX:
case PAR2_CRIT_IDX:
mergeval = MERGE_PAR_CRIT;
break;
case SER_CRIT_IDX:
case SER2_CRIT_IDX:
mergeval = MERGE_SER_CRIT;
break;
case SER_IDX:
case SER2_IDX:
mergeval = MERGE_SER;
break;
}
PropertyMerge(tp->name, fnum, Tcl_GetString(tobj1), mergeval);
}