Compare commits

...
13 Commits
Author SHA1 Message Date
Tim Edwards 24d98ff0d3 Removed backup file for netgen.tcl.in, and made corrections for
the output JSON format, which was incorrect when some entries
were empty.
2017-01-09 17:06:23 -05:00
Tim Edwards 092c99dc1b Merge branch 'master' into work 2017-01-09 12:53:00 -05:00
Tim Edwards 4659b0795d Update at Mon Jan 9 12:52:59 EST 2017 by tim 2017-01-09 12:52:59 -05:00
Tim Edwards b1924bff65 Finished implementing the Tcl list output format, and added a
routine to convert the list output format to a JSON output file,
for easy readback, parsing, and display using python.
2017-01-09 12:51:31 -05:00
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 8900 additions and 511 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.68
1.5.71
+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;
}
+1727 -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();
+384 -7
View File
@@ -26,6 +26,337 @@ if {${tcl_version} >= 8.6} {
load TCL_DIR/tclnetgenSHDLIB_EXT
}
#----------------------------------------------------------------
# Convert LVS list result into a JSON file
#----------------------------------------------------------------
proc netgen::convert_to_json {filename lvs_final} {
set pidx [string last . $filename]
set jsonname [string replace $filename $pidx end ".json"]
if {![catch {open $jsonname w} fjson]} {
puts $fjson "\["
# Outer list is of each cell compared
set clen [llength $lvs_final]
set cidx 0
foreach circuit $lvs_final {
incr cidx
puts $fjson " \{"
set nkeys [llength $circuit]
set kidx 0
foreach {key value} $circuit {
incr kidx 2
switch $key {
name {
puts $fjson " \"${key}\": \["
set cktval [lindex $value 0]
puts $fjson " \"${cktval}\","
set cktval [lindex $value 1]
puts $fjson " \"${cktval}\""
if {$kidx == $nkeys} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
pins {
puts $fjson " \"${key}\": \["
puts $fjson " \["
set cktval [lindex $value 0]
foreach pin [lrange $cktval 0 end-1] {
puts $fjson " \"$pin\","
}
set pin [lindex $cktval end]
puts $fjson " \"$pin\""
puts $fjson " \], \["
set cktval [lindex $value 1]
foreach pin [lrange $cktval 0 end-1] {
puts $fjson " \"$pin\","
}
set pin [lindex $cktval end]
puts $fjson " \"$pin\""
puts $fjson " \]"
if {$kidx == $nkeys} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
nets {
puts $fjson " \"${key}\": \["
set cktval [lindex $value 0]
puts $fjson " \"$cktval\","
set cktval [lindex $value 1]
puts $fjson " \"$cktval\""
if {$kidx == $nkeys} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
devices {
puts $fjson " \"${key}\": \["
puts $fjson " \["
set cktval [lindex $value 0]
foreach dev [lrange $cktval 0 end-1] {
set devname [lindex $dev 0]
set devnum [lindex $dev 1]
puts $fjson " \[\"${devname}\", ${devnum}\],"
}
set dev [lindex $cktval end]
set devname [lindex $dev 0]
set devnum [lindex $dev 1]
puts $fjson " \[\"${devname}\", ${devnum} \]"
puts $fjson " \], \["
set cktval [lindex $value 1]
foreach dev [lrange $cktval 0 end-1] {
set devname [lindex $dev 0]
set devnum [lindex $dev 1]
puts $fjson " \[\"${devname}\", ${devnum} \],"
}
set dev [lindex $cktval end]
set devname [lindex $dev 0]
set devnum [lindex $dev 1]
puts $fjson " \[\"${devname}\", ${devnum} \]"
puts $fjson " \]"
if {$kidx == $nkeys} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
goodnets -
badnets {
puts $fjson " \"${key}\": \["
set glen [llength $value]
set gidx 0
foreach group $value {
incr gidx
puts $fjson " \["
puts $fjson " \["
set cktval [lindex $group 0]
set nlen [llength $cktval]
set nidx 0
foreach net $cktval {
incr nidx
puts $fjson " \["
set netname [lindex $net 0]
puts $fjson " \"$netname\","
puts $fjson " \["
set netconn [lindex $net 1]
foreach fanout [lrange $netconn 0 end-1] {
set devname [lindex $fanout 0]
set pinname [lindex $fanout 1]
set count [lindex $fanout 2]
if {$count == {}} {set count 0}
puts $fjson " \[ \"$devname\", \"$pinname\", $count \],"
}
set fanout [lindex $netconn end]
set devname [lindex $fanout 0]
set pinname [lindex $fanout 1]
set count [lindex $fanout 2]
if {$count == {}} {set count 0}
puts $fjson " \[ \"$devname\", \"$pinname\", $count \]"
puts $fjson " \]"
if {$nidx == $nlen} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
puts $fjson " \], \["
set cktval [lindex $group 1]
set nlen [llength $cktval]
set nidx 0
foreach net $cktval {
incr nidx
puts $fjson " \["
set netname [lindex $net 0]
puts $fjson " \"$netname\","
puts $fjson " \["
set netconn [lindex $net 1]
foreach fanout [lrange $netconn 0 end-1] {
set devname [lindex $fanout 0]
set pinname [lindex $fanout 1]
set count [lindex $fanout 2]
if {$count == {}} {set count 0}
puts $fjson " \[ \"$devname\", \"$pinname\", $count \],"
}
set fanout [lindex $netconn end]
set devname [lindex $fanout 0]
set pinname [lindex $fanout 1]
set count [lindex $fanout 2]
if {$count == {}} {set count 0}
puts $fjson " \[ \"$devname\", \"$pinname\", $count \]"
puts $fjson " \]"
if {$nidx == $nlen} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
if {$gidx == $glen} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
if {$glen > 0} {
puts $fjson " \]"
}
if {$kidx == $nkeys} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
goodelements -
badelements {
puts $fjson " \"${key}\": \["
set glen [llength $value]
set gidx 0
foreach group $value {
incr gidx
puts $fjson " \["
puts $fjson " \["
set cktval [lindex $group 0]
set ilen [llength $cktval]
set iidx 0
foreach inst $cktval {
incr iidx
puts $fjson " \["
set instname [lindex $inst 0]
puts $fjson " \"$instname\","
puts $fjson " \["
set instpins [lindex $inst 1]
foreach fanout [lrange $instpins 0 end-1] {
set pinname [lindex $fanout 0]
set count [lindex $fanout 1]
if {$count == {}} {set count 0}
puts $fjson " \[ \"$pinname\", $count \],"
}
set fanout [lindex $instpins end]
set pinname [lindex $fanout 0]
set count [lindex $fanout 1]
if {$count == {}} {set count 0}
puts $fjson " \[ \"$pinname\", $count \]"
puts $fjson " \]"
if {$iidx == $ilen} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
puts $fjson " \], \["
set cktval [lindex $group 1]
set ilen [llength $cktval]
set iidx 0
foreach inst $cktval {
incr iidx
puts $fjson " \["
set instname [lindex $inst 0]
puts $fjson " \"$instname\","
puts $fjson " \["
set instpins [lindex $inst 1]
foreach fanout [lrange $instpins 0 end-1] {
set pinname [lindex $fanout 0]
set count [lindex $fanout 1]
if {$count == {}} {set count 0}
puts $fjson " \[ \"$pinname\", $count \],"
}
set fanout [lindex $instpins end]
set pinname [lindex $fanout 0]
set count [lindex $fanout 1]
if {$count == {}} {set count 0}
puts $fjson " \[ \"$pinname\", $count \]"
puts $fjson " \]"
if {$iidx == $ilen} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
if {$gidx == $glen} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
if {$glen > 0} {
puts $fjson " \]"
}
if {$kidx == $nkeys} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
properties {
puts $fjson " \"${key}\": \["
set plen [llength $value]
set pidx 0
foreach instance $value {
incr pidx
puts $fjson " \["
set instnames [lindex $instance 0]
set instname0 [lindex $instnames 0]
puts $fjson " \["
puts $fjson " \"${instname0}\","
puts $fjson " \["
foreach property [lrange $instance 1 end-1] {
set prop0 [lindex $property 0]
set propname [lindex $prop0 0]
set propval [lindex $prop0 1]
puts $fjson " \[\"${propname}\", \"${propval}\"\],"
}
set property [lindex $instance end]
set prop0 [lindex $property 0]
set propname [lindex $prop0 0]
set propval [lindex $prop0 1]
puts $fjson " \[\"${propname}\", \"${propval}\"\]"
puts $fjson " \]"
puts $fjson " \],"
set instname1 [lindex $instnames 1]
puts $fjson " \["
puts $fjson " \"${instname1}\","
puts $fjson " \["
foreach property [lrange $instance 1 end-1] {
set prop1 [lindex $property 1]
set propname [lindex $prop1 0]
set propval [lindex $prop1 1]
puts $fjson " \[\"${propname}\", \"${propval}\"\],"
}
set property [lindex $instance end]
set prop0 [lindex $property 0]
set propname [lindex $prop0 0]
set propval [lindex $prop0 1]
puts $fjson " \[\"${propname}\", \"${propval}\"\]"
puts $fjson " \]"
puts $fjson " \]"
if {$pidx == $plen} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
if {$kidx == $nkeys} {
puts $fjson " \]"
} else {
puts $fjson " \],"
}
}
}
}
if {$cidx == $clen} {
puts $fjson " \}"
} else {
puts $fjson " \},"
}
}
puts $fjson "\]"
}
close $fjson
}
#----------------------------------------------------------------
# Define the "lvs" command as a way of calling the netgen options
# for standard compare, essentially the same as the old "netcomp"
@@ -34,9 +365,28 @@ 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
set dojson 0
puts stdout "Diagnostic version"
foreach arg $args {
if {$arg == "-list"} {
puts stdout "Generating list result"
set dolist 1
set lvs_final {}
} elseif {$arg == "-json"} {
puts stdout "Generating JSON file result"
set dolist 1
set dojson 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 +487,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 +549,28 @@ 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 {$dojson == 1} {
netgen::convert_to_json $logfile $lvs_final
} elseif {$dolist == 1} {
return $lvs_final
}
}
# It is important to make sure no netgen commands overlap with Tcl built-in
+163 -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,57 @@ _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) nbad = Tcl_NewListObj(0, NULL);
Tcl_SetVar2Ex(interp, "lvs_out", NULL,
Tcl_NewStringObj("badnets", -1),
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
Tcl_SetVar2Ex(interp, "lvs_out", NULL, nbad,
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
#if 0
if (ngood == NULL) ngood = Tcl_NewListObj(0, NULL);
Tcl_SetVar2Ex(interp, "lvs_out", NULL,
Tcl_NewStringObj("goodnets", -1),
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
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) ebad = Tcl_NewListObj(0, NULL);
Tcl_SetVar2Ex(interp, "lvs_out", NULL,
Tcl_NewStringObj("badelements", -1),
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
Tcl_SetVar2Ex(interp, "lvs_out", NULL, ebad,
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
#if 0
if (egood == NULL) egood = Tcl_NewListObj(0, NULL);
Tcl_SetVar2Ex(interp, "lvs_out", NULL,
Tcl_NewStringObj("goodelements", -1),
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
Tcl_SetVar2Ex(interp, "lvs_out", NULL, egood,
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
#endif
}
}
return TCL_OK;
@@ -2566,13 +2677,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 +2858,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 +2870,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 +3130,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 +3170,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 +3479,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);
}