mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 14:07:07 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41939adb84 | ||
|
|
39573981be | ||
|
|
b9e26f6fce | ||
|
|
78779ce2e9 | ||
|
|
70bb33cc62 | ||
|
|
fdf2f32654 | ||
|
|
05d4225e97 | ||
|
|
b6218699a9 | ||
|
|
d7927ef547 | ||
|
|
af7bc39bbf | ||
|
|
5cd68b9ef1 | ||
|
|
07788e7501 | ||
|
|
24cc7d0c94 | ||
|
|
dbcd36d3ec | ||
|
|
25c17abb70 | ||
|
|
fd019b4afd | ||
|
|
cdfd74bac4 | ||
|
|
dd9e02c5f3 | ||
|
|
26cd16f3ff | ||
|
|
ccdd47bc0b | ||
|
|
ace1c28507 | ||
|
|
5e9635e05f | ||
|
|
5c168946e3 | ||
|
|
1471f0c09f | ||
|
|
73b81fcfe3 | ||
|
|
b083a6df7c | ||
|
|
2b5a96500c | ||
|
|
66f94b47e6 | ||
|
|
09532ee628 | ||
|
|
2b7d416a41 | ||
|
|
090e9e122a | ||
|
|
67f1c1a2e9 | ||
|
|
a7dcb4ef45 | ||
|
|
a0f1b4cc92 | ||
|
|
b5d5496e40 | ||
|
|
7cac67c81b | ||
|
|
ede7406b08 | ||
|
|
516d1c33fb | ||
|
|
0ad5730701 | ||
|
|
24d98ff0d3 | ||
|
|
092c99dc1b | ||
|
|
4659b0795d | ||
|
|
b1924bff65 |
+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).
|
||||
|
||||
|
||||
+25
-15
@@ -486,24 +486,30 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
}
|
||||
|
||||
/* splice instance out of parent */
|
||||
if (ParentParams == ThisCell->cell) {
|
||||
/* ParentParams are the very first thing in the list */
|
||||
ThisCell->cell = ChildObjList;
|
||||
for (ob2 = ChildObjList; ob2 && ob2->next != NULL; ob2 = ob2->next) ;
|
||||
if ((ParentParams == ThisCell->cell) && (ChildObjList == NULL)) {
|
||||
ThisCell->cell = ob2; /* Child cell was empty */
|
||||
tmp = ob2;
|
||||
}
|
||||
else {
|
||||
/* find ParentParams in ThisCell list */
|
||||
for (ob2 = ThisCell->cell; ob2 && ob2->next != ParentParams; ob2=ob2->next);
|
||||
if (ob2)
|
||||
for (ob2->next = ChildObjList; ob2->next != NULL; ob2 = ob2->next) ;
|
||||
}
|
||||
/* now, ob2 is last element in child list, so skip and reclaim parent */
|
||||
if (ParentParams == ThisCell->cell) {
|
||||
/* ParentParams are the very first thing in the list */
|
||||
ThisCell->cell = ChildObjList;
|
||||
for (ob2 = ChildObjList; ob2 && ob2->next != NULL; ob2 = ob2->next) ;
|
||||
}
|
||||
else {
|
||||
/* find ParentParams in ThisCell list */
|
||||
for (ob2 = ThisCell->cell; ob2 && ob2->next != ParentParams; ob2=ob2->next);
|
||||
if (ob2)
|
||||
for (ob2->next = ChildObjList; ob2->next != NULL; ob2 = ob2->next) ;
|
||||
}
|
||||
/* now, ob2 is last element in child list, so skip and reclaim parent */
|
||||
|
||||
tmp = ParentParams;
|
||||
do {
|
||||
tmp = tmp->next;
|
||||
} while ((tmp != NULL) && ((tmp->type > FIRSTPIN) || (tmp->type == PROPERTY)));
|
||||
if (ob2) ob2->next = tmp;
|
||||
tmp = ParentParams;
|
||||
do {
|
||||
tmp = tmp->next;
|
||||
} while ((tmp != NULL) && ((tmp->type > FIRSTPIN) || (tmp->type == PROPERTY)));
|
||||
if (ob2) ob2->next = tmp;
|
||||
}
|
||||
while (ParentParams != tmp) {
|
||||
ob2 = ParentParams->next;
|
||||
FreeObjectAndHash(ParentParams, ThisCell);
|
||||
@@ -1224,6 +1230,10 @@ int CleanupPins(char *name, int filenum)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If cell is type MODULE, this is a black-box circuit and
|
||||
// pins are expected to be disconnected (so don't remove them).
|
||||
if (ThisCell->class == CLASS_MODULE) return 0;
|
||||
|
||||
// Avoid a loop through all cells unless we have to do it.
|
||||
|
||||
for (ob = ThisCell->cell; ob != NULL; ob = ob->next) {
|
||||
|
||||
+203
-133
@@ -998,15 +998,17 @@ Tcl_Obj *ListElementClasses(int legal)
|
||||
int numlists1, numlists2, n1, n2, n, f1, f2, i, maxf;
|
||||
char *estr;
|
||||
|
||||
Tcl_Obj *dobj, *lobj, *e1obj, *e2obj, *sobj, *gobj;
|
||||
Tcl_Obj *lobj, *c1obj, *c2obj, *e1obj, *e2obj, *sobj;
|
||||
Tcl_Obj *g1obj, *g2obj, *dobj;
|
||||
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
dobj = Tcl_NewListObj(0, NULL);
|
||||
for (escan = ElementClasses; escan != NULL; escan = escan->next) {
|
||||
if (legal == escan->legalpartition) {
|
||||
struct Element *E;
|
||||
|
||||
e1obj = Tcl_NewListObj(0, NULL);
|
||||
e2obj = Tcl_NewListObj(0, NULL);
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
g1obj = Tcl_NewListObj(0, NULL);
|
||||
g2obj = Tcl_NewListObj(0, NULL);
|
||||
|
||||
numlists1 = numlists2 = 0;
|
||||
for (E = escan->elements; E != NULL; E = E->next)
|
||||
@@ -1035,22 +1037,30 @@ Tcl_Obj *ListElementClasses(int legal)
|
||||
}
|
||||
|
||||
for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) {
|
||||
c1obj = Tcl_NewListObj(0, NULL);
|
||||
c2obj = Tcl_NewListObj(0, NULL);
|
||||
|
||||
e1obj = Tcl_NewListObj(0, NULL);
|
||||
e2obj = Tcl_NewListObj(0, NULL);
|
||||
|
||||
if (n < n1) {
|
||||
estr = elist1[n]->name;
|
||||
if (*estr == '/') estr++; // Remove leading slash, if any
|
||||
Tcl_ListObjAppendElement(netgeninterp, e1obj, Tcl_NewStringObj(estr, -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, c1obj, Tcl_NewStringObj(estr, -1));
|
||||
}
|
||||
else
|
||||
Tcl_ListObjAppendElement(netgeninterp, e1obj,
|
||||
Tcl_ListObjAppendElement(netgeninterp, c1obj,
|
||||
Tcl_NewStringObj("(no matching instance)", -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, c1obj, e1obj);
|
||||
if (n < n2) {
|
||||
estr = elist2[n]->name;
|
||||
if (*estr == '/') estr++; // Remove leading slash, if any
|
||||
Tcl_ListObjAppendElement(netgeninterp, e2obj, Tcl_NewStringObj(estr, -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, c2obj, Tcl_NewStringObj(estr, -1));
|
||||
}
|
||||
else
|
||||
Tcl_ListObjAppendElement(netgeninterp, e2obj,
|
||||
Tcl_ListObjAppendElement(netgeninterp, c2obj,
|
||||
Tcl_NewStringObj("(no matching instance)", -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, c2obj, e2obj);
|
||||
|
||||
if (n >= n1)
|
||||
maxf = elist2[n]->fanout;
|
||||
@@ -1111,24 +1121,17 @@ Tcl_Obj *ListElementClasses(int legal)
|
||||
}
|
||||
f2++;
|
||||
}
|
||||
Tcl_ListObjAppendElement(netgeninterp, g1obj, c1obj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, g2obj, c2obj);
|
||||
}
|
||||
Tcl_ListObjAppendElement(netgeninterp, lobj, g1obj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, lobj, g2obj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, dobj, lobj);
|
||||
|
||||
FreeFormattedLists(elist1, numlists1);
|
||||
FreeFormattedLists(elist2, numlists2);
|
||||
|
||||
gobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, gobj, e1obj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, gobj, e2obj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, lobj, gobj);
|
||||
}
|
||||
}
|
||||
|
||||
dobj = Tcl_NewListObj(0, NULL);
|
||||
if (legal)
|
||||
Tcl_ListObjAppendElement(netgeninterp, dobj, Tcl_NewStringObj("goodelements", -1));
|
||||
else
|
||||
Tcl_ListObjAppendElement(netgeninterp, dobj, Tcl_NewStringObj("badelements", -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, dobj, lobj);
|
||||
return dobj;
|
||||
}
|
||||
|
||||
@@ -1375,15 +1378,17 @@ Tcl_Obj *ListNodeClasses(int legal)
|
||||
struct NodeClass *nscan;
|
||||
int numlists1, numlists2, n1, n2, n, f, i, maxf;
|
||||
|
||||
Tcl_Obj *dobj, *lobj, *e1obj, *e2obj, *sobj, *gobj;
|
||||
Tcl_Obj *lobj, *c1obj, *c2obj, *n1obj, *n2obj, *sobj;
|
||||
Tcl_Obj *dobj, *g1obj, *g2obj;
|
||||
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
dobj = Tcl_NewListObj(0, NULL);
|
||||
for (nscan = NodeClasses; nscan != NULL; nscan = nscan->next) {
|
||||
if (legal == nscan->legalpartition) {
|
||||
struct Node *N;
|
||||
|
||||
e1obj = Tcl_NewListObj(0, NULL);
|
||||
e2obj = Tcl_NewListObj(0, NULL);
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
g1obj = Tcl_NewListObj(0, NULL);
|
||||
g2obj = Tcl_NewListObj(0, NULL);
|
||||
|
||||
numlists1 = numlists2 = 0;
|
||||
for (N = nscan->nodes; N != NULL; N = N->next) {
|
||||
@@ -1410,18 +1415,27 @@ Tcl_Obj *ListNodeClasses(int legal)
|
||||
}
|
||||
|
||||
for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) {
|
||||
c1obj = Tcl_NewListObj(0, NULL);
|
||||
c2obj = Tcl_NewListObj(0, NULL);
|
||||
|
||||
n1obj = Tcl_NewListObj(0, NULL);
|
||||
n2obj = Tcl_NewListObj(0, NULL);
|
||||
|
||||
if (n < n1)
|
||||
Tcl_ListObjAppendElement(netgeninterp, e1obj,
|
||||
Tcl_ListObjAppendElement(netgeninterp, c1obj,
|
||||
Tcl_NewStringObj(nlists1[n]->name, -1));
|
||||
else
|
||||
Tcl_ListObjAppendElement(netgeninterp, e1obj,
|
||||
Tcl_ListObjAppendElement(netgeninterp, c1obj,
|
||||
Tcl_NewStringObj("(no matching net)", -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, c1obj, n1obj);
|
||||
|
||||
if (n < n2)
|
||||
Tcl_ListObjAppendElement(netgeninterp, e2obj,
|
||||
Tcl_ListObjAppendElement(netgeninterp, c2obj,
|
||||
Tcl_NewStringObj(nlists2[n]->name, -1));
|
||||
else
|
||||
Tcl_ListObjAppendElement(netgeninterp, e2obj,
|
||||
Tcl_ListObjAppendElement(netgeninterp, c2obj,
|
||||
Tcl_NewStringObj("(no matching net)", -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, c2obj, n2obj);
|
||||
|
||||
if (n >= n1)
|
||||
maxf = nlists2[n]->fanout;
|
||||
@@ -1445,7 +1459,7 @@ Tcl_Obj *ListNodeClasses(int legal)
|
||||
if (nlists1[n]->flist[f].permute > 1)
|
||||
FREE(nlists1[n]->flist[f].name);
|
||||
|
||||
Tcl_ListObjAppendElement(netgeninterp, e1obj, sobj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, n1obj, sobj);
|
||||
}
|
||||
if (n < n2)
|
||||
if (f < nlists2[n]->fanout) {
|
||||
@@ -1459,26 +1473,20 @@ Tcl_Obj *ListNodeClasses(int legal)
|
||||
|
||||
if (nlists2[n]->flist[f].permute > 1)
|
||||
FREE(nlists2[n]->flist[f].name);
|
||||
Tcl_ListObjAppendElement(netgeninterp, e2obj, sobj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, n2obj, sobj);
|
||||
}
|
||||
}
|
||||
Tcl_ListObjAppendElement(netgeninterp, g1obj, c1obj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, g2obj, c2obj);
|
||||
}
|
||||
Tcl_ListObjAppendElement(netgeninterp, lobj, g1obj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, lobj, g2obj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, dobj, lobj);
|
||||
|
||||
FreeFormattedLists(nlists1, numlists1);
|
||||
FreeFormattedLists(nlists2, numlists2);
|
||||
|
||||
gobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, gobj, e1obj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, gobj, e2obj);
|
||||
Tcl_ListObjAppendElement(netgeninterp, lobj, gobj);
|
||||
}
|
||||
}
|
||||
dobj = Tcl_NewListObj(0, NULL);
|
||||
if (legal)
|
||||
Tcl_ListObjAppendElement(netgeninterp, dobj, Tcl_NewStringObj("goodnets", -1));
|
||||
else
|
||||
Tcl_ListObjAppendElement(netgeninterp, dobj, Tcl_NewStringObj("badnets", -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, dobj, lobj);
|
||||
return dobj;
|
||||
}
|
||||
|
||||
@@ -2957,16 +2965,16 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist) {
|
||||
Tcl_Obj *dlist, *mlist;
|
||||
Tcl_Obj *mlist;
|
||||
|
||||
dlist = Tcl_NewListObj(0, NULL);
|
||||
mlist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, mlist, clist1);
|
||||
Tcl_ListObjAppendElement(netgeninterp, mlist, clist2);
|
||||
Tcl_ListObjAppendElement(netgeninterp, dlist,
|
||||
Tcl_NewStringObj("devices", -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, dlist, mlist);
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, dlist,
|
||||
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL,
|
||||
Tcl_NewStringObj("devices", -1),
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, mlist,
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
}
|
||||
#endif
|
||||
@@ -3016,16 +3024,15 @@ void FirstNodePass(struct Node *N, int dolist)
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist) {
|
||||
Tcl_Obj *dlist, *nlist;
|
||||
Tcl_Obj *nlist;
|
||||
|
||||
dlist = Tcl_NewListObj(0, NULL);
|
||||
nlist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, dlist,
|
||||
Tcl_NewStringObj("nets", -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, dlist, nlist);
|
||||
Tcl_ListObjAppendElement(netgeninterp, nlist, Tcl_NewIntObj(C1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, nlist, Tcl_NewIntObj(C2));
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, dlist,
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL,
|
||||
Tcl_NewStringObj("nets", -1),
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, nlist,
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
}
|
||||
#endif
|
||||
@@ -3483,16 +3490,16 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist)
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist) {
|
||||
Tcl_Obj *dlist, *nlist;
|
||||
Tcl_Obj *nlist;
|
||||
|
||||
dlist = Tcl_NewListObj(0, NULL);
|
||||
nlist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, dlist,
|
||||
Tcl_NewStringObj("name", -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, dlist, nlist);
|
||||
Tcl_ListObjAppendElement(netgeninterp, nlist, Tcl_NewStringObj(name1, -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, nlist, Tcl_NewStringObj(name2, -1));
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, dlist,
|
||||
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL,
|
||||
Tcl_NewStringObj("name", -1),
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, nlist,
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
}
|
||||
#endif
|
||||
@@ -4489,21 +4496,38 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int serial)
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Property list starts with a pair of instance names, followed */
|
||||
/* by a list of corresponding but mismatched properties. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
Tcl_Obj *NewPropertyList(char *inst1, char *inst2)
|
||||
{
|
||||
Tcl_Obj *proplist;
|
||||
Tcl_Obj *mpair, *instobj;
|
||||
|
||||
mpair = Tcl_NewListObj(0, NULL);
|
||||
instobj = Tcl_NewStringObj(inst1, -1);
|
||||
Tcl_ListObjAppendElement(netgeninterp, mpair, instobj);
|
||||
instobj = Tcl_NewStringObj(inst2, -1);
|
||||
Tcl_ListObjAppendElement(netgeninterp, mpair, instobj);
|
||||
|
||||
proplist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
return proplist;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Generate a Tcl list entry for a property mismatching pair */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
Tcl_Obj *PropertyList(char *inst1, struct valuelist *vl1,
|
||||
char *inst2, struct valuelist *vl2)
|
||||
Tcl_Obj *PropertyList(struct valuelist *vl1, struct valuelist *vl2)
|
||||
{
|
||||
Tcl_Obj *mobj, *mpair, *propobj;
|
||||
|
||||
mpair = Tcl_NewListObj(0, NULL);
|
||||
|
||||
mobj = Tcl_NewListObj(0, NULL);
|
||||
propobj = Tcl_NewStringObj(inst1, -1);
|
||||
Tcl_ListObjAppendElement(netgeninterp, mobj, propobj);
|
||||
|
||||
if (vl1 == NULL)
|
||||
propobj = Tcl_NewStringObj("(no matching parameter)", -1);
|
||||
else
|
||||
@@ -4523,9 +4547,6 @@ Tcl_Obj *PropertyList(char *inst1, struct valuelist *vl1,
|
||||
Tcl_ListObjAppendElement(netgeninterp, mpair, mobj);
|
||||
|
||||
mobj = Tcl_NewListObj(0, NULL);
|
||||
propobj = Tcl_NewStringObj(inst2, -1);
|
||||
Tcl_ListObjAppendElement(netgeninterp, mobj, propobj);
|
||||
|
||||
if (vl2 == NULL)
|
||||
propobj = Tcl_NewStringObj("(no matching parameter)", -1);
|
||||
else
|
||||
@@ -4540,6 +4561,8 @@ Tcl_Obj *PropertyList(char *inst1, struct valuelist *vl1,
|
||||
propobj = Tcl_NewDoubleObj(vl2->value.dval);
|
||||
else if (vl2->type == PROP_STRING)
|
||||
propobj = Tcl_NewStringObj(vl2->value.string, -1);
|
||||
else if (vl2->type == PROP_EXPRESSION)
|
||||
propobj = Tcl_NewStringObj("(unresolved expression)", -1);
|
||||
Tcl_ListObjAppendElement(netgeninterp, mobj, propobj);
|
||||
|
||||
Tcl_ListObjAppendElement(netgeninterp, mpair, mobj);
|
||||
@@ -4582,9 +4605,8 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
static struct property klm, kls;
|
||||
static char mkey[2], skey[2];
|
||||
|
||||
#ifdef TCL_NETLIST
|
||||
Tcl_Obj *proplist;
|
||||
proplist = Tcl_NewListObj(0, NULL);
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_Obj *proplist = NULL;
|
||||
#endif
|
||||
|
||||
// Set up static records representing property M = 1 and S = 1
|
||||
@@ -4648,9 +4670,10 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
Fprintf(stdout, "Property %s in circuit2 has no matching "
|
||||
"property in circuit1\n", vl2->key);
|
||||
}
|
||||
#ifdef TCL_NETLIST
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list) {
|
||||
Tcl_Obj *mpair = PropertyList(inst1, vl1, inst2, vl2);
|
||||
Tcl_Obj *mpair = PropertyList(NULL, vl2);
|
||||
if (!proplist) proplist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
}
|
||||
#endif
|
||||
@@ -4703,9 +4726,10 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
Fprintf(stdout, "Property %s in circuit1 has no matching "
|
||||
"property in circuit2\n", vl1->key);
|
||||
}
|
||||
#ifdef TCL_NETLIST
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list) {
|
||||
Tcl_Obj *mpair = PropertyList(inst1, vl1, inst2, vl2);
|
||||
Tcl_Obj *mpair = PropertyList(vl1, NULL);
|
||||
if (!proplist) proplist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
}
|
||||
#endif
|
||||
@@ -4785,9 +4809,10 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
}
|
||||
Fprintf(stdout, " (property type mismatch)\n");
|
||||
}
|
||||
#ifdef TCL_NETLIST
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list) {
|
||||
Tcl_Obj *mpair = PropertyList(inst1, vl1, inst2, vl2);
|
||||
Tcl_Obj *mpair = PropertyList(vl1, vl2);
|
||||
if (!proplist) proplist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
}
|
||||
#endif
|
||||
@@ -4814,9 +4839,10 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
else
|
||||
Fprintf(stdout, "\n");
|
||||
}
|
||||
#ifdef TCL_NETLIST
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list) {
|
||||
Tcl_Obj *mpair = PropertyList(inst1, vl1, inst2, vl2);
|
||||
Tcl_Obj *mpair = PropertyList(vl1, vl2);
|
||||
if (!proplist) proplist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
}
|
||||
#endif
|
||||
@@ -4840,9 +4866,10 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
else
|
||||
Fprintf(stdout, "\n");
|
||||
}
|
||||
#ifdef TCL_NETLIST
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list) {
|
||||
Tcl_Obj *mpair = PropertyList(inst1, vl1, inst2, vl2);
|
||||
Tcl_Obj *mpair = PropertyList(vl1, vl2);
|
||||
if (!proplist) proplist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
}
|
||||
#endif
|
||||
@@ -4867,9 +4894,10 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
kl1->key, vl1->value.string,
|
||||
vl2->value.string);
|
||||
}
|
||||
#ifdef TCL_NETLIST
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list) {
|
||||
Tcl_Obj *mpair = PropertyList(inst1, vl1, inst2, vl2);
|
||||
Tcl_Obj *mpair = PropertyList(vl1, vl2);
|
||||
if (!proplist) proplist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
}
|
||||
#endif
|
||||
@@ -4886,9 +4914,10 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
kl1->key, vl1->value.string,
|
||||
vl2->value.string, islop);
|
||||
}
|
||||
#ifdef TCL_NETLIST
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list) {
|
||||
Tcl_Obj *mpair = PropertyList(inst1, vl1, inst2, vl2);
|
||||
Tcl_Obj *mpair = PropertyList(vl1, vl2);
|
||||
if (!proplist) proplist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
}
|
||||
#endif
|
||||
@@ -4900,9 +4929,10 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
/* Expressions could potentially be compared. . . */
|
||||
if (do_print)
|
||||
Fprintf(stdout, " %s (unresolved expressions.)\n", kl1->key);
|
||||
#ifdef TCL_NETLIST
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list) {
|
||||
Tcl_Obj *mpair = PropertyList(inst1, vl1, inst2, vl2);
|
||||
Tcl_Obj *mpair = PropertyList(vl1, vl2);
|
||||
if (!proplist) proplist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
}
|
||||
#endif
|
||||
@@ -4917,8 +4947,8 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
if (len2 > 0) FREE(check2);
|
||||
*count = mismatches;
|
||||
|
||||
#ifdef TCL_NETLIST
|
||||
if (dolist) return proplist;
|
||||
#ifdef TCL_NETGEN
|
||||
return proplist;
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -4955,7 +4985,7 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
int rval = 1;
|
||||
char *inst1, *inst2;
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_Obj *proplist, *mpair;
|
||||
Tcl_Obj *proplist = NULL, *mpair, *mlist;
|
||||
#endif
|
||||
|
||||
tc1 = LookupCellFile(ob1->model.class, Circuit1->file);
|
||||
@@ -4972,10 +5002,12 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
|
||||
/* Find the first property record of each circuit. obn1, obn2 are */
|
||||
/* the last device record before the properties for each device. */
|
||||
for (tp1 = ob1; (tp1 != NULL) && tp1->type >= FIRSTPIN; tp1 = tp1->next)
|
||||
for (tp1 = ob1->next; (tp1 != NULL) && tp1->type > FIRSTPIN; tp1 = tp1->next)
|
||||
obn1 = tp1;
|
||||
for (tp2 = ob2; (tp2 != NULL) && tp2->type >= FIRSTPIN; tp2 = tp2->next)
|
||||
for (tp2 = ob2->next; (tp2 != NULL) && tp2->type > FIRSTPIN; tp2 = tp2->next)
|
||||
obn2 = tp2;
|
||||
if (tp1 && (tp1->type == FIRSTPIN)) tp1 = NULL; /* tp1 had no properties */
|
||||
if (tp2 && (tp2->type == FIRSTPIN)) tp2 = NULL; /* tp2 had no properties */
|
||||
|
||||
/* Check if there are any properties to match */
|
||||
|
||||
@@ -5041,14 +5073,11 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
inst2 = ob2->instance.name;
|
||||
if (*inst2 == '/') inst2++;
|
||||
|
||||
proplist = Tcl_NewListObj(0, NULL);
|
||||
|
||||
while(1) {
|
||||
if (t1type != PROPERTY) {
|
||||
// t1 has no properties. See if t2's properties are required
|
||||
// to be checked. If so, flag t2 instance as unmatched
|
||||
|
||||
mismatches++;
|
||||
for (i = 0;; i++) {
|
||||
vl2 = &(tp2->instance.props[i]);
|
||||
if (vl2->type == PROP_ENDLIST) break;
|
||||
@@ -5058,13 +5087,17 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
if (kl2 != NULL) break; // Property is required
|
||||
}
|
||||
if (vl2->type != PROP_ENDLIST) {
|
||||
mismatches++;
|
||||
if (do_print) Fprintf(stdout, "Circuit 2 %s instance %s has no"
|
||||
" property match in circuit 1.\n",
|
||||
Circuit2->name, inst2);
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list) {
|
||||
mpair = PropertyList(inst1, NULL, inst2, vl2);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
mpair = PropertyList(NULL, vl2);
|
||||
if (mpair) {
|
||||
if (!proplist) proplist = NewPropertyList(inst1, inst2);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
rval = -1;
|
||||
@@ -5091,8 +5124,11 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
Circuit1->name, inst1);
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list) {
|
||||
mpair = PropertyList(inst1, vl1, inst2, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
mpair = PropertyList(vl1, NULL);
|
||||
if (mpair) {
|
||||
if (!proplist) proplist = NewPropertyList(inst1, inst2);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
rval = -1;
|
||||
@@ -5115,13 +5151,16 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
PropertyOptimize(tp2, tc2, 1, TRUE);
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
mpair =
|
||||
mlist =
|
||||
#endif
|
||||
PropertyCheckMismatch(tp1, tc1, inst1, tp2, tc2,
|
||||
inst2, do_print, do_list, &count, &rval);
|
||||
mismatches += count;
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, mpair);
|
||||
if (do_list && (mlist != NULL)) {
|
||||
if (!proplist) proplist = NewPropertyList(inst1, inst2);
|
||||
Tcl_ListObjAppendList(netgeninterp, proplist, mlist);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5204,7 +5243,7 @@ void PrintPropertyResults(int do_list)
|
||||
#ifdef TCL_NETGEN
|
||||
|
||||
if (do_list) {
|
||||
Tcl_Obj *proprec, *proplist, *eprop;
|
||||
Tcl_Obj *proplist, *eprop;
|
||||
|
||||
proplist = Tcl_NewListObj(0, NULL);
|
||||
for (EC = ElementClasses; EC != NULL; EC = EC->next) {
|
||||
@@ -5212,11 +5251,10 @@ void PrintPropertyResults(int do_list)
|
||||
if (eprop != NULL)
|
||||
Tcl_ListObjAppendElement(netgeninterp, proplist, eprop);
|
||||
}
|
||||
proprec = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, proprec,
|
||||
Tcl_NewStringObj("properties", -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, proprec, proplist);
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, proprec,
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL,
|
||||
Tcl_NewStringObj("properties", -1),
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, proplist,
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
}
|
||||
else {
|
||||
@@ -6236,6 +6274,7 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
|
||||
int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
{
|
||||
char *cover, *ctemp;
|
||||
char *bangptr1, *bangptr2;
|
||||
struct objlist *ob1, *ob2, *obn, *obp, *ob1s, *ob2s, *obt;
|
||||
struct NodeClass *NC;
|
||||
struct Node *N1, *N2;
|
||||
@@ -6245,7 +6284,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
int needclean1 = 0, needclean2 = 0;
|
||||
char ostr[89];
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_Obj *dlist, *mlist, *plist1, *plist2;
|
||||
Tcl_Obj *mlist, *plist1, *plist2;
|
||||
#endif
|
||||
|
||||
if (tc1 == NULL) tc1 = Circuit1;
|
||||
@@ -6274,11 +6313,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist) {
|
||||
dlist = Tcl_NewListObj(0, NULL);
|
||||
mlist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, dlist,
|
||||
Tcl_NewStringObj("pins", -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, dlist, mlist);
|
||||
plist1 = Tcl_NewListObj(0, NULL);
|
||||
plist2 = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, mlist, plist1);
|
||||
@@ -6322,9 +6357,13 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
}
|
||||
if (N2 == NULL) {
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist)
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, dlist,
|
||||
if (dolist) {
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL,
|
||||
Tcl_NewStringObj("pins", -1),
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, mlist,
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
@@ -6337,11 +6376,11 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < 43; m++) *(ostr + m) = ' ';
|
||||
for (m = 44; m < 87; m++) *(ostr + m) = ' ';
|
||||
sprintf(ostr, "%s", obn->name);
|
||||
snprintf(ostr, 43, "%s", obn->name);
|
||||
if (!strcasecmp(obn->name, obp->name))
|
||||
sprintf(ostr + 44, "%s", obp->name);
|
||||
snprintf(ostr + 44, 43, "%s", obp->name);
|
||||
else
|
||||
sprintf(ostr + 44, "%s **Mismatch**", obp->name);
|
||||
snprintf(ostr + 44, 43, "%s **Mismatch**", obp->name);
|
||||
for (m = 0; m < 88; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
@@ -6375,8 +6414,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (strcmp(obn->name, "(no pins)")) {
|
||||
for (m = 0; m < 43; m++) *(ostr + m) = ' ';
|
||||
for (m = 44; m < 87; m++) *(ostr + m) = ' ';
|
||||
sprintf(ostr, "%s", obn->name);
|
||||
sprintf(ostr + 44, "(no matching pin)");
|
||||
snprintf(ostr, 32, "%s", obn->name);
|
||||
snprintf(ostr + 44, 43, "(no matching pin)");
|
||||
for (m = 0; m < 88; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
@@ -6420,8 +6459,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < 43; m++) *(ostr + m) = ' ';
|
||||
for (m = 44; m < 87; m++) *(ostr + m) = ' ';
|
||||
sprintf(ostr, "%s", obn->name);
|
||||
sprintf(ostr + 44, "(no matching pin)");
|
||||
snprintf(ostr, 43, "%s", obn->name);
|
||||
snprintf(ostr + 44, 43, "(no matching pin)");
|
||||
for (m = 0; m < 88; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
@@ -6448,13 +6487,25 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
|
||||
/* Do any unmatched pins have the same name? */
|
||||
/* (This should not happen if unconnected pins are eliminated) */
|
||||
/* (Semi-hack: Allow "!" global flag) */
|
||||
|
||||
ob1 = tc1->cell;
|
||||
bangptr1 = strrchr(ob1->name, '!');
|
||||
if (bangptr1 && (*(bangptr1 + 1) == '\0'))
|
||||
*bangptr1 = '\0';
|
||||
else bangptr1 = NULL;
|
||||
|
||||
for (i = 0; i < numorig; i++) {
|
||||
if (*(cover + i) == (char)0) {
|
||||
j = 0;
|
||||
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
|
||||
if (!IsPort(ob2)) break;
|
||||
|
||||
bangptr2 = strrchr(ob2->name, '!');
|
||||
if (bangptr2 && (*(bangptr2 + 1) == '\0'))
|
||||
*bangptr2 = '\0';
|
||||
else bangptr2 = NULL;
|
||||
|
||||
if ((*matchfunc)(ob1->name, ob2->name)) {
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
@@ -6462,8 +6513,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < 43; m++) *(ostr + m) = ' ';
|
||||
for (m = 44; m < 87; m++) *(ostr + m) = ' ';
|
||||
sprintf(ostr, "%s", ob1->name);
|
||||
sprintf(ostr + 44, "%s", ob2->name);
|
||||
snprintf(ostr, 43, "%s", ob1->name);
|
||||
snprintf(ostr + 44, 43, "%s", ob2->name);
|
||||
for (m = 0; m < 88; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
@@ -6483,11 +6534,13 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
j++;
|
||||
}
|
||||
}
|
||||
ob1 = ob1->next;
|
||||
}
|
||||
if (bangptr1) *bangptr1 = '!';
|
||||
|
||||
/* Find the end of the pin list in tc1, for adding proxy pins */
|
||||
|
||||
@@ -6509,8 +6562,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (strcmp(ob2->name, "(no pins)")) {
|
||||
for (m = 0; m < 43; m++) *(ostr + m) = ' ';
|
||||
for (m = 44; m < 87; m++) *(ostr + m) = ' ';
|
||||
sprintf(ostr, "(no matching pin)");
|
||||
sprintf(ostr + 44, "%s", ob2->name);
|
||||
snprintf(ostr, 43, "(no matching pin)");
|
||||
snprintf(ostr + 44, 43, "%s", ob2->name);
|
||||
for (m = 0; m < 88; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
@@ -6559,8 +6612,14 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
obn->model.port = -1;
|
||||
obn->instance.name = NULL;
|
||||
obn->node = -1;
|
||||
obn->next = ob1->next;
|
||||
ob1->next = obn;
|
||||
if (ob1 == tc1->cell) {
|
||||
obn->next = ob1;
|
||||
tc1->cell = obn;
|
||||
}
|
||||
else {
|
||||
obn->next = ob1->next;
|
||||
ob1->next = obn;
|
||||
}
|
||||
ob1 = obn;
|
||||
hasproxy1 = 1;
|
||||
|
||||
@@ -6617,8 +6676,15 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
obn->model.port = (i - j);
|
||||
obn->instance.name = NULL;
|
||||
obn->node = -1;
|
||||
obn->next = ob2->next;
|
||||
ob2->next = obn;
|
||||
|
||||
if (ob2 == tc2->cell) {
|
||||
obn->next = ob2;
|
||||
tc2->cell = obn;
|
||||
}
|
||||
else {
|
||||
obn->next = ob2->next;
|
||||
ob2->next = obn;
|
||||
}
|
||||
ob2 = obn;
|
||||
hasproxy2 = 1;
|
||||
|
||||
@@ -6658,7 +6724,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
|
||||
/* Clean up "UNKNOWN" records from Circuit1 */
|
||||
|
||||
for (obn = tc1->cell; ; obn = obn->next) {
|
||||
for (obn = tc1->cell; obn; obn = obn->next) {
|
||||
if (obn->type == UNKNOWN) obn->type = PORT;
|
||||
else if (obn->type != PORT) break;
|
||||
}
|
||||
@@ -6677,13 +6743,13 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
|
||||
/* Clean up "UNKNOWN" records from Circuit2 */
|
||||
|
||||
for (obn = tc2->cell; ; obn = obn->next) {
|
||||
for (obn = tc2->cell; obn; obn = obn->next) {
|
||||
if (obn->type == UNKNOWN) obn->type = PORT;
|
||||
else if (obn->type != PORT) break;
|
||||
}
|
||||
|
||||
/* Check for ports that did not get ordered */
|
||||
for (obn = tc2->cell; obn->type == PORT; obn = obn->next) {
|
||||
for (obn = tc2->cell; obn && (obn->type == PORT); obn = obn->next) {
|
||||
if (obn->model.port == -1) {
|
||||
if (obn->node == -1) {
|
||||
// This only happens when pins have become separated from any net.
|
||||
@@ -6738,9 +6804,13 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
#ifdef TCL_NETGEN
|
||||
/* Handle list output */
|
||||
|
||||
if (dolist)
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, dlist,
|
||||
if (dolist) {
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL,
|
||||
Tcl_NewStringObj("pins", -1),
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, mlist,
|
||||
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
|
||||
+34
-12
@@ -49,6 +49,7 @@ int NextNode;
|
||||
|
||||
int Composition = NONE;
|
||||
int QuickSearch = 0;
|
||||
int GlobalParallelNone = FALSE;
|
||||
|
||||
int AddToExistingDefinition = 0; /* default: overwrite cell when reopened */
|
||||
|
||||
@@ -870,6 +871,32 @@ int ReduceExpressions(struct objlist *instprop, struct objlist *parprops,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Set/clear the flag bit COMB_NO_PARALLEL on all cells. Note that the */
|
||||
/* function is called with value for enabling combine parallel, so */
|
||||
/* value TRUE means clear bit, value FALSE means set bit. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
struct nlist *SetParallelCombineFlag(struct hashlist *p, void *clientdata)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
int *value = (int *)clientdata;
|
||||
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if (*value == TRUE)
|
||||
ptr->flags &= (~COMB_NO_PARALLEL);
|
||||
else
|
||||
ptr->flags |= COMB_NO_PARALLEL;
|
||||
|
||||
return NULL; /* NULL keeps search alive */
|
||||
}
|
||||
|
||||
void SetParallelCombine(int value)
|
||||
{
|
||||
ClearDumpedList();
|
||||
RecurseCellHashTable2(SetParallelCombineFlag, (void *)(&value));
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Delete a property from the master cell record. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
@@ -1192,7 +1219,7 @@ void CellDef(char *name, int fnum)
|
||||
np = InstallInCellHashTable(name, fnum);
|
||||
CurrentCell = LookupCellFile(name, fnum);
|
||||
CurrentCell->class = CLASS_SUBCKT; /* default */
|
||||
CurrentCell->flags = 0;
|
||||
CurrentCell->flags = (GlobalParallelNone) ? COMB_NO_PARALLEL : 0;
|
||||
|
||||
LastPlaced = NULL;
|
||||
CurrentTail = NULL;
|
||||
@@ -3306,11 +3333,6 @@ int CombineSerial(char *model, int file)
|
||||
int i, j, scnt = 0;
|
||||
struct valuelist *kv;
|
||||
|
||||
// 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;
|
||||
|
||||
if ((tp = LookupCellFile(model, file)) == NULL) {
|
||||
Printf("Cell: %s does not exist.\n", model);
|
||||
return -1;
|
||||
@@ -3387,11 +3409,10 @@ int CombineSerial(char *model, int file)
|
||||
/* a parameter '_tag', string value set to "+". */
|
||||
|
||||
for (obn = instlist[i][1]; obn->next &&
|
||||
obn->next->type != PROPERTY &&
|
||||
obn->next->type != FIRSTPIN; obn = obn->next);
|
||||
obn->next->type > FIRSTPIN; obn = obn->next);
|
||||
obp = obn->next;
|
||||
|
||||
if (obp == NULL || obp->type == FIRSTPIN) {
|
||||
if (obp == NULL || obp->type != PROPERTY) {
|
||||
struct objlist *nob;
|
||||
/* No property record, so insert one */
|
||||
nob = GetObject();
|
||||
@@ -3463,10 +3484,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
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ extern struct property *PropertyInteger(char *name, int fnum, char *key,
|
||||
extern struct property *PropertyString(char *name, int fnum, char *key,
|
||||
double slop, char *pdefault);
|
||||
extern int PropertyDelete(char *name, int fnum, char *key);
|
||||
extern void SetParallelCombine(int value);
|
||||
extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
|
||||
double dval);
|
||||
extern int PropertyMerge(char *name, int fnum, char *key, int merge_type);
|
||||
@@ -53,6 +54,8 @@ extern void PortList(char *prefix, char *list_template);
|
||||
extern char *Cell(char *inststr, char *model, ...);
|
||||
extern int IsIgnored(char *, int);
|
||||
|
||||
extern int auto_blackbox; /* For handling empty subcircuits */
|
||||
|
||||
/* netcmp.c */
|
||||
extern struct nlist *LookupClassEquivalent(char *model, int file1, int file2);
|
||||
extern void AssignCircuits(char *name1, int file1, char *name2, int file2);
|
||||
@@ -132,6 +135,7 @@ extern int IgnoreRC; /* set this to 1 to ignore capacitance and resistance */
|
||||
extern int NoOutput; /* set this to 1 to disable stdout output */
|
||||
extern int Composition; /* direction of composition */
|
||||
extern int UnixWildcards; /* TRUE if *,?,{},[] only; false if full REGEXP */
|
||||
extern int GlobalParallelNone; /* If TRUE, don't parallel combine any cells */
|
||||
/* magic internal flag to restrict searches to recently placed cells */
|
||||
extern int QuickSearch;
|
||||
/* does re"CellDef"ing a cell add to it or overwrite it??? */
|
||||
|
||||
+6
-3
@@ -563,8 +563,11 @@ static int PrintCellHashTableElement(struct hashlist *p)
|
||||
/* only print primitive cells if Debug is enabled */
|
||||
if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n",
|
||||
ptr->name, ptr->number);
|
||||
else if (Debug == 3) { /* list */
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
}
|
||||
}
|
||||
else if (Debug == 2) { /* list only */
|
||||
else if ((Debug == 2) || (Debug == 3)) { /* list only */
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
#else
|
||||
@@ -595,7 +598,7 @@ void PrintCellHashTable(int full, int filenum)
|
||||
|
||||
bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed);
|
||||
total = RecurseHashTable(&cell_dict, CountHashTableEntries);
|
||||
if (full != 2)
|
||||
if (full < 2)
|
||||
Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n",
|
||||
bins, CELLHASHSIZE, total, (bins == 0) ? 0 :
|
||||
(float)((float)total / (float)bins));
|
||||
@@ -605,7 +608,7 @@ void PrintCellHashTable(int full, int filenum)
|
||||
RecurseHashTable(&cell_dict, PrintCellHashTableElement);
|
||||
Debug = OldDebug;
|
||||
#ifndef TCL_NETGEN
|
||||
if (full == 2) Printf("\n");
|
||||
if (full >= 2) Printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+48
-5
@@ -25,8 +25,10 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include <stdarg.h> /* what about varargs, like in pdutils.c ??? */
|
||||
#endif
|
||||
|
||||
#ifdef IBMPC
|
||||
#include <stdlib.h> /* for calloc(), free() */
|
||||
#include <stdlib.h> /* for calloc(), free(), getenv() */
|
||||
#ifndef IBMPC
|
||||
#include <sys/types.h> /* for getpwnam() tilde expansion */
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
@@ -42,6 +44,10 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
// Global storage for parameters from .PARAM
|
||||
struct hashdict spiceparams;
|
||||
|
||||
// Global setting for auto-detect of empty subcircuits as
|
||||
// black-box subcells.
|
||||
int auto_blackbox = FALSE;
|
||||
|
||||
// Check if a token represents a numerical value (with
|
||||
// units) or an expression. This is basically a hack
|
||||
// to see if it either passes StringIsValue() or is
|
||||
@@ -398,6 +404,7 @@ int renamepins(struct hashlist *p, int file)
|
||||
|
||||
void CleanupSubcell() {
|
||||
int maxnode = 0;
|
||||
int has_devices = FALSE;
|
||||
struct objlist *sobj, *nobj, *lobj, *pobj;
|
||||
|
||||
if (CurrentCell == NULL) return;
|
||||
@@ -409,6 +416,8 @@ void CleanupSubcell() {
|
||||
lobj = NULL;
|
||||
for (sobj = CurrentCell->cell; sobj != NULL;) {
|
||||
nobj = sobj->next;
|
||||
if (sobj->type == FIRSTPIN)
|
||||
has_devices = TRUE;
|
||||
if (sobj->node < 0) {
|
||||
if (IsGlobal(sobj)) {
|
||||
if (lobj != NULL)
|
||||
@@ -437,6 +446,8 @@ void CleanupSubcell() {
|
||||
lobj = sobj;
|
||||
sobj = nobj;
|
||||
}
|
||||
if ((has_devices == FALSE) && (auto_blackbox == TRUE))
|
||||
SetClass(CLASS_MODULE);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
@@ -615,7 +626,7 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
}
|
||||
SpiceTokNoNewline();
|
||||
}
|
||||
SetClass((blackbox) ? CLASS_MODULE : CLASS_SUBCKT);
|
||||
SetClass((blackbox) ? CLASS_MODULE : CLASS_SUBCKT);
|
||||
|
||||
if (hasports == 0) {
|
||||
// If the cell defines no ports, then create a proxy
|
||||
@@ -743,7 +754,7 @@ skip_ends:
|
||||
SpiceSkipNewLine();
|
||||
}
|
||||
else if (matchnocase(nexttok, ".INCLUDE")) {
|
||||
char *iname, *iptr, *quotptr, *pathend;
|
||||
char *iname, *iptr, *quotptr, *pathend, *userpath = NULL;
|
||||
|
||||
SpiceTokNoNewline();
|
||||
if (nexttok == NULL) continue; /* Ignore if no filename */
|
||||
@@ -755,12 +766,44 @@ skip_ends:
|
||||
pathend = strrchr(fname, '/');
|
||||
iptr = nexttok;
|
||||
while (*iptr == '\'' || *iptr == '\"' || *iptr == '`') iptr++;
|
||||
if ((pathend != NULL) && (*iptr != '/')) {
|
||||
if ((pathend != NULL) && (*iptr != '/') && (*iptr != '~')) {
|
||||
*pathend = '\0';
|
||||
iname = (char *)MALLOC(strlen(fname) + strlen(iptr) + 2);
|
||||
sprintf(iname, "%s/%s", fname, iptr);
|
||||
*pathend = '/';
|
||||
}
|
||||
#ifndef IBMPC
|
||||
else if ((*iptr == '~') && (*(iptr + 1) == '/')) {
|
||||
/* For ~/<path>, substitute tilde from $HOME */
|
||||
userpath = getenv("HOME");
|
||||
iname = (char *)MALLOC(strlen(userpath) + strlen(iptr));
|
||||
sprintf(fname, "%s%s", userpath, iptr + 1);
|
||||
}
|
||||
else if (*iptr == '~') {
|
||||
/* For ~<user>/<path>, substitute tilde from getpwnam() */
|
||||
struct passwd *passwd;
|
||||
char *pathstart;
|
||||
pathstart = strchr(iptr, '/');
|
||||
if (pathstart) *pathstart = '\0';
|
||||
passwd = getpwnam(iptr + 1);
|
||||
if (passwd != NULL) {
|
||||
userpath = passwd->pw_dir;
|
||||
if (pathstart) {
|
||||
*pathstart = '/';
|
||||
iname = (char *)MALLOC(strlen(userpath) + strlen(pathstart) + 1);
|
||||
sprintf(fname, "%s%s", userpath, pathstart);
|
||||
}
|
||||
else {
|
||||
/* Almost certainly an error, but make the substitution anyway */
|
||||
iname = STRDUP(userpath);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Probably an error, but copy the filename verbatim */
|
||||
iname = STRDUP(iptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
iname = STRDUP(iptr);
|
||||
|
||||
|
||||
+339
-2
@@ -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"
|
||||
@@ -42,12 +369,20 @@ if {${tcl_version} >= 8.6} {
|
||||
|
||||
proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
set dolist 0
|
||||
puts stdout "Diagnostic version"
|
||||
set dojson 0
|
||||
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 {}
|
||||
} elseif {$arg == "-blackbox"} {
|
||||
puts stdout "Treating empty subcircuits as black-box cells"
|
||||
netgen::model blackbox on
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +564,9 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
}
|
||||
netgen::log end
|
||||
puts stdout "LVS Done."
|
||||
if {$dolist == 1} {
|
||||
if {$dojson == 1} {
|
||||
netgen::convert_to_json $logfile $lvs_final
|
||||
} elseif {$dolist == 1} {
|
||||
return $lvs_final
|
||||
}
|
||||
}
|
||||
|
||||
+119
-63
@@ -1437,9 +1437,9 @@ _netgen_cells(ClientData clientData,
|
||||
char *optstart;
|
||||
int filenum = -1;
|
||||
struct nlist *np = NULL;
|
||||
int result, dolist = 0;
|
||||
int result, printopt, dolist = 0, doall = 0, dotop = 0;
|
||||
|
||||
if (objc > 1) {
|
||||
while (objc > 1) {
|
||||
optstart = Tcl_GetString(objv[1]);
|
||||
if (*optstart == '-') optstart++;
|
||||
if (!strcmp(optstart, "list")) {
|
||||
@@ -1447,27 +1447,41 @@ _netgen_cells(ClientData clientData,
|
||||
objv++;
|
||||
objc--;
|
||||
}
|
||||
else if (!strcmp(optstart, "all")) {
|
||||
doall = 1;
|
||||
objv++;
|
||||
objc--;
|
||||
}
|
||||
else if (!strcmp(optstart, "top")) {
|
||||
dotop = 1;
|
||||
objv++;
|
||||
objc--;
|
||||
}
|
||||
else {
|
||||
result = CommonParseCell(interp, objv[1], &np, &filenum);
|
||||
if (result != TCL_OK) return result;
|
||||
objv++;
|
||||
objc--;
|
||||
}
|
||||
}
|
||||
|
||||
if (objc == 1) {
|
||||
PrintCellHashTable((dolist) ? 2 : 0, -1);
|
||||
}
|
||||
else if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "[list] [-all|-top|valid_filename]");
|
||||
if (objc != 1) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "[list] [-top] [-all] [valid_filename]");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
else {
|
||||
Tcl_Obj *lobj;
|
||||
|
||||
repstr = Tcl_GetString(objv[1]);
|
||||
if (!strncmp(repstr, "-top", 4)) {
|
||||
if (dotop) {
|
||||
if (dolist)
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
else
|
||||
Fprintf(stdout, "Top level cells: ");
|
||||
np = FirstCell();
|
||||
while (np != NULL) {
|
||||
if (np->flags & CELL_TOP) {
|
||||
if ((np->flags & CELL_TOP) && ((filenum == -1) ||
|
||||
(np->file == filenum))) {
|
||||
|
||||
if (dolist)
|
||||
Tcl_ListObjAppendElement(interp, lobj,
|
||||
Tcl_NewStringObj(np->name, -1));
|
||||
@@ -1483,11 +1497,13 @@ _netgen_cells(ClientData clientData,
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
else if (strncmp(repstr, "-all", 4)) {
|
||||
result = CommonParseCell(interp, objv[1], &np, &filenum);
|
||||
if (result != TCL_OK) return result;
|
||||
else {
|
||||
if (dolist)
|
||||
printopt = (doall) ? 3 : 2;
|
||||
else
|
||||
printopt = (doall) ? 1 : 0;
|
||||
PrintCellHashTable(printopt, filenum);
|
||||
}
|
||||
PrintCellHashTable((dolist) ? 2 : 1, filenum);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
@@ -1528,8 +1544,27 @@ _netgen_model(ClientData clientData,
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* Check for "model blackbox on|off" */
|
||||
/* Behavior is to treat empty subcircuits as blackbox cells */
|
||||
|
||||
if ((objc > 1) && !strcmp(Tcl_GetString(objv[1]), "blackbox")) {
|
||||
if ((objc > 2) && !strcmp(Tcl_GetString(objv[2]), "on")) {
|
||||
auto_blackbox = TRUE;
|
||||
return TCL_OK;
|
||||
}
|
||||
else if ((objc > 2) && !strcmp(Tcl_GetString(objv[2]), "off")) {
|
||||
auto_blackbox = FALSE;
|
||||
return TCL_OK;
|
||||
}
|
||||
else if (objc == 2) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(auto_blackbox));
|
||||
return TCL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
result = CommonParseCell(interp, objv[1], &tp, &fnum);
|
||||
if (result != TCL_OK) return result;
|
||||
if (result != TCL_OK)
|
||||
return result;
|
||||
|
||||
if (objc == 3) {
|
||||
model = Tcl_GetString(objv[2]);
|
||||
@@ -1641,6 +1676,13 @@ _netgen_model(ClientData clientData,
|
||||
retclass = modelclasses[SUBCKT_IDX];
|
||||
break;
|
||||
|
||||
case CLASS_MODULE:
|
||||
if (auto_blackbox)
|
||||
retclass = modelclasses[BLACKBOX_IDX];
|
||||
else
|
||||
retclass = modelclasses[MODULE_IDX];
|
||||
break;
|
||||
|
||||
default: /* (includes case CLASS_UNDEF) */
|
||||
retclass = modelclasses[UNDEF_IDX];
|
||||
break;
|
||||
@@ -2487,49 +2529,33 @@ _netcmp_verify(ClientData clientData,
|
||||
if (dolist)
|
||||
{
|
||||
if (objc == 1 || index == NODE_IDX || index == ALL_IDX) {
|
||||
if (nbad == NULL) {
|
||||
Tcl_Obj *n0, *n1;
|
||||
nbad = Tcl_NewListObj(0, NULL);
|
||||
n0 = Tcl_NewStringObj("badnets", -1);
|
||||
n1 = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, nbad, n0);
|
||||
Tcl_ListObjAppendElement(netgeninterp, nbad, n1);
|
||||
}
|
||||
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) {
|
||||
Tcl_Obj *n0, *n1;
|
||||
ngood = Tcl_NewListObj(0, NULL);
|
||||
n0 = Tcl_NewStringObj("goodnets", -1);
|
||||
n1 = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, ngood, n0);
|
||||
Tcl_ListObjAppendElement(netgeninterp, ngood, n1);
|
||||
}
|
||||
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) {
|
||||
Tcl_Obj *e0, *e1;
|
||||
ebad = Tcl_NewListObj(0, NULL);
|
||||
e0 = Tcl_NewStringObj("badelements", -1);
|
||||
e1 = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, ebad, e0);
|
||||
Tcl_ListObjAppendElement(netgeninterp, ebad, e1);
|
||||
}
|
||||
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) {
|
||||
Tcl_Obj *e0, *e1;
|
||||
ebad = Tcl_NewListObj(0, NULL);
|
||||
e0 = Tcl_NewStringObj("goodelements", -1);
|
||||
e1 = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(netgeninterp, egood, e0);
|
||||
Tcl_ListObjAppendElement(netgeninterp, egood, e1);
|
||||
}
|
||||
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
|
||||
@@ -2694,10 +2720,10 @@ _netcmp_equate(ClientData clientData,
|
||||
};
|
||||
int result, index;
|
||||
char *name1 = NULL, *name2 = NULL, *optstart;
|
||||
struct nlist *tp1, *tp2;
|
||||
struct nlist *tp1, *tp2, *SaveC1, *SaveC2;
|
||||
struct objlist *ob1, *ob2;
|
||||
int file1, file2;
|
||||
int i, l1, l2, ltest, lent, dolist;
|
||||
int i, l1, l2, ltest, lent, dolist = 0;
|
||||
Tcl_Obj *tobj1, *tobj2, *tobj3;
|
||||
|
||||
if (objc > 1) {
|
||||
@@ -2865,7 +2891,7 @@ _netcmp_equate(ClientData clientData,
|
||||
break;
|
||||
|
||||
case PINS_IDX:
|
||||
if (ElementClasses == NULL) {
|
||||
if ((ElementClasses == NULL) && (auto_blackbox == FALSE)) {
|
||||
if (CurrentCell == NULL)
|
||||
Fprintf(stderr, "Equate elements: no current cell.\n");
|
||||
Fprintf(stderr, "Equate pins: cell %s and/or %s has no elements.\n",
|
||||
@@ -2873,20 +2899,30 @@ _netcmp_equate(ClientData clientData,
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
|
||||
return TCL_OK;
|
||||
}
|
||||
if (tp1 == Circuit1 && tp2 == Circuit2) {
|
||||
int result;
|
||||
if (MatchPins(tp1, tp2, dolist)) {
|
||||
Fprintf(stdout, "Cell pin lists are equivalent.\n");
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, "Cell pin lists for %s and %s altered to match.\n",
|
||||
name1, name2);
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
|
||||
}
|
||||
else if (ElementClasses == NULL) {
|
||||
/* This has been called outside of a netlist compare, */
|
||||
/* probably to force name matching of pins on black-box */
|
||||
/* devices. But MatchPins only works if tp1 == Circuit1 */
|
||||
/* and tp2 == Circuit2, so preserve these values and */
|
||||
/* recover afterward (what a hack). */
|
||||
SaveC1 = Circuit1;
|
||||
SaveC2 = Circuit2;
|
||||
Circuit1 = tp1;
|
||||
Circuit2 = tp2;
|
||||
}
|
||||
if (MatchPins(tp1, tp2, dolist)) {
|
||||
Fprintf(stdout, "Cell pin lists are equivalent.\n");
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
|
||||
}
|
||||
else {
|
||||
Fprintf(stderr, "Function not defined outside of LVS scope.\n");
|
||||
Fprintf(stdout, "Cell pin lists for %s and %s altered to match.\n",
|
||||
name1, name2);
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
|
||||
}
|
||||
if (ElementClasses == NULL) {
|
||||
/* Recover temporarily set global variables (see above) */
|
||||
Circuit1 = SaveC1;
|
||||
Circuit2 = SaveC2;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3109,8 +3145,12 @@ _netcmp_equate(ClientData clientData,
|
||||
/* netgen::property <device>|<model> <option> */
|
||||
/* yes|no */
|
||||
/* Where <option> is one of: */
|
||||
/* serial --- allow/prohibit serial combination */
|
||||
/* serial --- allow/prohibit serial combination */
|
||||
/* parallel --- allow/prohibit parallel combination */
|
||||
/* or */
|
||||
/* netgen::property parallel none */
|
||||
/* --- prohibit parallel combinations by */
|
||||
/* default. */
|
||||
/* */
|
||||
/* Formerly: (none) */
|
||||
/* Results: */
|
||||
@@ -3204,6 +3244,22 @@ _netcmp_property(ClientData clientData,
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
else if ((objc == 3) && (!strcmp(Tcl_GetString(objv[1]), "parallel"))) {
|
||||
if (!strcmp(Tcl_GetString(objv[2]), "none")) {
|
||||
GlobalParallelNone = TRUE;
|
||||
SetParallelCombine(FALSE);
|
||||
}
|
||||
else if (!strcmp(Tcl_GetString(objv[2]), "all")) {
|
||||
GlobalParallelNone = FALSE;
|
||||
SetParallelCombine(TRUE);
|
||||
}
|
||||
else {
|
||||
Tcl_SetResult(interp, "Bad option, should be property parallel none|all",
|
||||
NONE);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
result = CommonParseCell(interp, objv[1], &tp, &fnum);
|
||||
if (result != TCL_OK) return result;
|
||||
|
||||
Reference in New Issue
Block a user