mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 14:07:07 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ace1c28507 | ||
|
|
5e9635e05f | ||
|
|
5c168946e3 | ||
|
|
1471f0c09f | ||
|
|
73b81fcfe3 | ||
|
|
b083a6df7c | ||
|
|
2b5a96500c | ||
|
|
66f94b47e6 | ||
|
|
09532ee628 | ||
|
|
2b7d416a41 | ||
|
|
090e9e122a | ||
|
|
67f1c1a2e9 | ||
|
|
a7dcb4ef45 | ||
|
|
a0f1b4cc92 | ||
|
|
b5d5496e40 | ||
|
|
7cac67c81b | ||
|
|
ede7406b08 | ||
|
|
516d1c33fb | ||
|
|
0ad5730701 | ||
|
|
24d98ff0d3 | ||
|
|
092c99dc1b | ||
|
|
4659b0795d | ||
|
|
b1924bff65 | ||
|
|
bd356553fd | ||
|
|
46458f2836 | ||
|
|
8deccaad9c | ||
|
|
4f24915661 | ||
|
|
fdab366627 | ||
|
|
310d7512a0 | ||
|
|
86f52b164a | ||
|
|
4a47c3076d | ||
|
|
777498b30e |
+11
-10
@@ -1,12 +1,13 @@
|
||||
*.*%
|
||||
*.cdslck
|
||||
.inca.db.*
|
||||
inca.*.pak
|
||||
*.swp
|
||||
*.log
|
||||
netgen
|
||||
netgenexec
|
||||
defs.mak
|
||||
Depend
|
||||
config.cache
|
||||
config.log
|
||||
config.status
|
||||
*.o
|
||||
*.so
|
||||
*~
|
||||
*/av_extracted*/
|
||||
.nfs*
|
||||
*.cd-
|
||||
*/mommdl/
|
||||
*.log
|
||||
UPDATE_ME
|
||||
VERSION
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
TO_DO list for version 1.5
|
||||
------------------------------
|
||||
|
||||
1) Parallel (transistors and capacitors) and serial (resistors)
|
||||
device merging, plus methods for describing how any device
|
||||
class may be merged.
|
||||
As of version 1.5.70, the major to-do item list is complete.
|
||||
|
||||
Possible useful additions (not critical)
|
||||
----------------------
|
||||
|
||||
1) Add new output style allowing netlists to be described by Tcl scripts
|
||||
(similar to the C-Code format, but does not require compiling).
|
||||
(similar to the C-Code format, but does not require compiling) (this
|
||||
was done in 1.5.72, but now needs some scripts to make use of it.)
|
||||
2) Add automatic file format guessing from file extension for "write" command
|
||||
3) Add Tk GUI to match (and improve upon!) the original X11 GUI.
|
||||
4) Incorporate into Tcl-based xcircuit
|
||||
@@ -33,5 +32,7 @@ Possible useful additions (not critical)
|
||||
ntk and ext formats, SPICE format writing, and sim format reading).
|
||||
11) Add a "property" command to add/remove properties to check, and change
|
||||
the slop values (done).
|
||||
12) Add a "subcircuit" command to mimic a SPICE ".SUBCKT ... .ENDS" card.
|
||||
12) Add a "subcircuit" command to mimic a SPICE ".SUBCKT ... .ENDS" card
|
||||
(i.e., the ability to add subcircuit "stub" definitions from the
|
||||
command line or from a setup file).
|
||||
|
||||
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
|
||||
+1747
-341
File diff suppressed because it is too large
Load Diff
+6423
File diff suppressed because it is too large
Load Diff
+9
-3
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+179
-135
@@ -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,77 @@ 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 > 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 != PROPERTY) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3419,10 +3462,11 @@ int CombineSerial(char *model, int file)
|
||||
|
||||
/* Excise the 2nd instance. instlist[i][1] remains as the */
|
||||
/* only pointer to it. */
|
||||
for (obp = instlist[i][0]; obp->next->type != FIRSTPIN; obp = obp->next);
|
||||
for (obp = instlist[i][0]; obp->next->type > FIRSTPIN ||
|
||||
obp->next->type == PROPERTY; obp = obp->next);
|
||||
for (ob2 = obp; ob2->next != instlist[i][1]; ob2 = ob2->next);
|
||||
for (obs = ob2->next; obs->next && obs->next->type != FIRSTPIN;
|
||||
obs = obs->next);
|
||||
for (obs = ob2->next; obs->next && (obs->next->type > FIRSTPIN
|
||||
|| obs->next->type == PROPERTY); obs = obs->next);
|
||||
ob2->next = obs->next;
|
||||
if (obs->next) obs->next = NULL; // Terminate 2nd instance record
|
||||
|
||||
|
||||
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
+380
-7
@@ -26,6 +26,333 @@ 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 " \],"
|
||||
}
|
||||
}
|
||||
puts $fjson " \]"
|
||||
if {$gidx == $glen} {
|
||||
puts $fjson " \]"
|
||||
} else {
|
||||
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 " \],"
|
||||
}
|
||||
}
|
||||
puts $fjson " \]"
|
||||
if {$gidx == $glen} {
|
||||
puts $fjson " \]"
|
||||
} else {
|
||||
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 prop1 [lindex $property 1]
|
||||
set propname [lindex $prop1 0]
|
||||
set propval [lindex $prop1 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 +361,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 +483,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 +545,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
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user