mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 22:17:22 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf6dd2a638 | ||
|
|
a332c23524 | ||
|
|
b6d896e73f | ||
|
|
064195ecc9 | ||
|
|
88d53fab15 | ||
|
|
c287b6cd28 | ||
|
|
9251ce2a48 | ||
|
|
0a0a6bcf63 | ||
|
|
72ef2f2637 | ||
|
|
aa82164c08 | ||
|
|
287f5963d1 | ||
|
|
fb7876c7a6 | ||
|
|
a984ac1a4d | ||
|
|
e31caa3500 | ||
|
|
738c1f7b37 | ||
|
|
c3cf6c3765 | ||
|
|
99dcc20c0a | ||
|
|
c1355bee45 | ||
|
|
4bbc496749 | ||
|
|
4fb8b59a2f | ||
|
|
c4f03eabaf | ||
|
|
6a555ad6ed | ||
|
|
626faf22f9 | ||
|
|
1c5457e180 | ||
|
|
7d246c36a6 | ||
|
|
550234dce5 | ||
|
|
92dfa74403 | ||
|
|
a4c0028706 | ||
|
|
d53541d1d3 | ||
|
|
57b2d21221 | ||
|
|
e7ae84bbc8 | ||
|
|
dfabdaa367 | ||
|
|
c5c1306f6a | ||
|
|
43c018f3bc | ||
|
|
0614461c84 | ||
|
|
6e94886b65 | ||
|
|
ca119edc0a | ||
|
|
0556abf3c1 | ||
|
|
84348d2fe1 | ||
|
|
3356dd784e | ||
|
|
813b29cdc4 | ||
|
|
00949970b4 | ||
|
|
ccf4a0a900 | ||
|
|
c83b6def5b | ||
|
|
e34166fdb9 | ||
|
|
8fc2c097d2 | ||
|
|
a13491e358 | ||
|
|
2ac2a3b6f8 | ||
|
|
1d05b8b676 | ||
|
|
759d63cea9 | ||
|
|
476da015f0 | ||
|
|
4aa8a72769 | ||
|
|
e97d6f1aeb | ||
|
|
47e7367c26 | ||
|
|
362fb7120b | ||
|
|
fb4759a8cd | ||
|
|
92e8fed8be | ||
|
|
45d4004d43 | ||
|
|
01b2484be3 | ||
|
|
fe47d84ace | ||
|
|
0b014e6efd | ||
|
|
0a2adeb593 | ||
|
|
330b34139c | ||
|
|
62d0352149 | ||
|
|
9ca713dfd9 | ||
|
|
b1b04b8e87 | ||
|
|
851a1f941e | ||
|
|
6b9d92de65 | ||
|
|
d763ad0e60 | ||
|
|
fd72e24a86 | ||
|
|
20077d3d56 | ||
|
|
fb798d6ce7 | ||
|
|
a21ba820e9 | ||
|
|
792c5e569a | ||
|
|
f92192efd4 | ||
|
|
1f50c7ccc5 | ||
|
|
8282460774 | ||
|
|
a888502038 | ||
|
|
ea07642172 | ||
|
|
e9da037001 | ||
|
|
7ee50a3f8f | ||
|
|
c16258d4d1 | ||
|
|
c7848c9c02 | ||
|
|
5341d7a5fd | ||
|
|
402e1f0f25 |
@@ -12,3 +12,5 @@ scripts/config.status
|
||||
*~
|
||||
*.log
|
||||
UPDATE_ME
|
||||
tcltk/netgen.sh
|
||||
tcltk/netgen.tcl
|
||||
|
||||
+311
-198
@@ -193,17 +193,19 @@ void flattenCell(char *name, int file)
|
||||
if (Debug) Printf("Renaming %s to %s\n", tmp->name, tmpstr);
|
||||
FreeString(tmp->name);
|
||||
tmp->name = strsave(tmpstr);
|
||||
#if OLDPREFIX
|
||||
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
|
||||
tmp->instance.name);
|
||||
#else
|
||||
strcpy(tmpstr+prefixlength,tmp->instance.name);
|
||||
#endif
|
||||
FreeString(tmp->instance.name);
|
||||
tmp->instance.name = strsave(tmpstr);
|
||||
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
|
||||
if (tmp->type == FIRSTPIN)
|
||||
HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict));
|
||||
if ((tmp->type != NODE) && (tmp->instance.name != NULL)) {
|
||||
#if OLDPREFIX
|
||||
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
|
||||
tmp->instance.name);
|
||||
#else
|
||||
strcpy(tmpstr+prefixlength,tmp->instance.name);
|
||||
#endif
|
||||
FreeString(tmp->instance.name);
|
||||
tmp->instance.name = strsave(tmpstr);
|
||||
if (tmp->type == FIRSTPIN)
|
||||
HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict));
|
||||
}
|
||||
}
|
||||
|
||||
/* splice instance out of parent */
|
||||
@@ -252,9 +254,10 @@ void flattenCell(char *name, int file)
|
||||
int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
{
|
||||
struct objlist *ParentParams;
|
||||
struct objlist *ParentProps;
|
||||
struct objlist *NextObj;
|
||||
struct objlist *ChildObjList;
|
||||
struct objlist *ParentProps, *CurrentProp;
|
||||
struct objlist *NextObj, *LastObj, *prepp;
|
||||
struct objlist *ChildObjList, *ChildListEnd;
|
||||
struct objlist *ChildStart, *ChildEnd, *ParentEnd, *ParentNext;
|
||||
struct nlist *ThisCell;
|
||||
struct nlist *ChildCell;
|
||||
struct objlist *tmp, *ob2, *ob3;
|
||||
@@ -296,21 +299,35 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
while (notdone) {
|
||||
notdone = 0;
|
||||
ParentParams = ThisCell->cell;
|
||||
LastObj = NULL;
|
||||
|
||||
for (ParentParams = ThisCell->cell; ParentParams != NULL;
|
||||
ParentParams = NextObj) {
|
||||
ParentParams = NextObj) {
|
||||
if (Debug) Printf("Parent = %s, type = %d\n",
|
||||
ParentParams->name, ParentParams->type);
|
||||
NextObj = ParentParams->next;
|
||||
if (ParentParams->type != FIRSTPIN) continue;
|
||||
if (!(*matchfunc)(ParentParams->model.class, instance)) continue;
|
||||
if (ParentParams->type != FIRSTPIN) {
|
||||
LastObj = ParentParams;
|
||||
continue;
|
||||
}
|
||||
if (!(*matchfunc)(ParentParams->model.class, instance)) {
|
||||
LastObj = ParentParams;
|
||||
continue;
|
||||
}
|
||||
|
||||
ChildCell = LookupCellFile(ParentParams->model.class, ThisCell->file);
|
||||
if (Debug)
|
||||
Printf(" Flattening instance: %s, primitive = %s\n",
|
||||
ParentParams->instance.name, (ChildCell->class ==
|
||||
CLASS_SUBCKT) ? "no" : "yes");
|
||||
if (ChildCell->class != CLASS_SUBCKT) continue;
|
||||
if (ChildCell == ThisCell) continue; // Avoid infinite loop
|
||||
if ((ChildCell->class != CLASS_SUBCKT) && (ChildCell->class != CLASS_MODULE)) {
|
||||
LastObj = ParentParams;
|
||||
continue;
|
||||
}
|
||||
if (ChildCell == ThisCell) {
|
||||
LastObj = ParentParams;
|
||||
continue; // Avoid infinite loop
|
||||
}
|
||||
|
||||
/* Does the parent cell have properties? If so, save a pointer to them */
|
||||
for (ParentProps = ParentParams->next; ParentProps &&
|
||||
@@ -318,202 +335,264 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
ParentProps = ParentProps->next) {
|
||||
if (ParentProps->type == PROPERTY) break;
|
||||
}
|
||||
if (ParentProps && (ParentProps->type != PROPERTY)) ParentProps = NULL;
|
||||
|
||||
/* not primitive, so need to flatten this instance */
|
||||
notdone = 1;
|
||||
/* if this is a new instance, flatten it */
|
||||
/* if (ChildCell->dumped == 0) flattenCell(ParentParams->model.class, file); */
|
||||
|
||||
ChildObjList = CopyObjList(ChildCell->cell, 1);
|
||||
numflat++;
|
||||
|
||||
/* update node numbers in child to unique numbers */
|
||||
oldmax = 0;
|
||||
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next)
|
||||
if (tmp->node > oldmax) oldmax = tmp->node;
|
||||
if (nextnode <= oldmax) nextnode = oldmax + 1;
|
||||
|
||||
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next)
|
||||
if (tmp->node <= oldmax && tmp->node > 0) {
|
||||
if (Debug) Printf("Update node %d --> %d\n", tmp->node, nextnode);
|
||||
UpdateNodeNumbers(ChildObjList, tmp->node, nextnode);
|
||||
nextnode++;
|
||||
}
|
||||
|
||||
/* copy nodenumbers of ports from parent */
|
||||
ob2 = ParentParams;
|
||||
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next)
|
||||
if (IsPort(tmp)) {
|
||||
if (tmp->node > 0) {
|
||||
if (ob2->node == -1) {
|
||||
|
||||
// Before commiting to attaching to a unconnected node, see
|
||||
// if there is another node in ParentParams with the same
|
||||
// name and a valid node number. If so, connect them. In
|
||||
// the broader case, it may be necessary to consider all
|
||||
// nodes, not just those with node == -1, and call join()
|
||||
// here to update all node numbers in the parent cell.
|
||||
// In that case, a more efficient method is needed for
|
||||
// tracking same-name ports.
|
||||
|
||||
for (ob3 = ParentParams; ob3 && ob3->type >= FIRSTPIN; ob3 = ob3->next) {
|
||||
if (ob3 == ob2) continue;
|
||||
if ((*matchfunc)(ob3->name, ob2->name) && ob3->node != -1) {
|
||||
ob2->node = ob3->node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Debug) {
|
||||
// Printf(" Sealing port: %d to node %d\n", tmp->node, ob2->node);
|
||||
Printf("Update node %d --> %d\n", tmp->node, ob2->node);
|
||||
}
|
||||
UpdateNodeNumbers(ChildObjList, tmp->node, ob2->node);
|
||||
}
|
||||
|
||||
/* in pathological cases, the lengths of the port lists may
|
||||
change. This is an error, but that is no reason to allow
|
||||
the code to core dump. We avoid this by placing a
|
||||
superfluous check on ob2->type
|
||||
*/
|
||||
|
||||
if (ob2 != NULL)
|
||||
ob2 = ob2->next;
|
||||
|
||||
if (ob2 == NULL) break;
|
||||
}
|
||||
|
||||
/* Using name == NULL to indicate that a .ext file is being */
|
||||
/* flattened on the fly. This is quick & dirty. */
|
||||
|
||||
if (name != NULL) {
|
||||
/* delete all port elements from child */
|
||||
while ((ChildObjList != NULL) && IsPort(ChildObjList)) {
|
||||
/* delete all ports at beginning of list */
|
||||
if (Debug) Printf("deleting leading port from child\n");
|
||||
tmp = ChildObjList->next;
|
||||
// FreeObjectAndHash(ChildObjList, ChildCell);
|
||||
FreeObject(ChildObjList);
|
||||
ChildObjList = tmp;
|
||||
}
|
||||
tmp = ChildObjList;
|
||||
while (tmp && (tmp->next != NULL)) {
|
||||
if (IsPort(tmp->next)) {
|
||||
ob2 = (tmp->next)->next;
|
||||
if (Debug) Printf("deleting a port from child\n");
|
||||
// FreeObjectAndHash(tmp->next, ChildCell);
|
||||
FreeObject(tmp->next);
|
||||
tmp->next = ob2;
|
||||
}
|
||||
else tmp = tmp->next;
|
||||
}
|
||||
if (ParentProps && (ParentProps->type != PROPERTY)) {
|
||||
ParentProps = NULL;
|
||||
CurrentProp = NULL;
|
||||
}
|
||||
else
|
||||
CurrentProp = ParentProps;
|
||||
|
||||
/* for each element in child, prepend 'prefix' */
|
||||
/* Find the end record of the parent cell and save it */
|
||||
for (ParentEnd = (ParentProps) ? ParentProps : ParentParams;
|
||||
ParentEnd && ParentEnd->next &&
|
||||
/* Stop on a node or the next instance */
|
||||
((ParentEnd->next->type > FIRSTPIN) ||
|
||||
(ParentEnd->next->type == PROPERTY));
|
||||
ParentEnd = ParentEnd->next);
|
||||
|
||||
/* Not primitive, so need to flatten this instance */
|
||||
notdone = 1;
|
||||
|
||||
/* Loop over property records. Need to flatten once per */
|
||||
/* property record (or more, if property has M > 1) */
|
||||
|
||||
ob2 = NULL;
|
||||
ChildObjList = NULL;
|
||||
ChildListEnd = NULL;
|
||||
while (1) {
|
||||
|
||||
ChildStart = CopyObjList(ChildCell->cell, 1);
|
||||
numflat++;
|
||||
|
||||
/* Find the end record of the child cell and save it */
|
||||
for (ChildEnd = ChildStart; ChildEnd && ChildEnd->next;
|
||||
ChildEnd = ChildEnd->next);
|
||||
|
||||
if (ChildListEnd == NULL) ChildListEnd = ChildEnd;
|
||||
|
||||
/* update node numbers in child to unique numbers */
|
||||
oldmax = 0;
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next)
|
||||
if (tmp->node > oldmax) oldmax = tmp->node;
|
||||
if (nextnode <= oldmax) nextnode = oldmax + 1;
|
||||
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next)
|
||||
if (tmp->node <= oldmax && tmp->node > 0) {
|
||||
if (Debug) Printf("Update node %d --> %d\n", tmp->node, nextnode);
|
||||
UpdateNodeNumbers(ChildStart, tmp->node, nextnode);
|
||||
nextnode++;
|
||||
}
|
||||
|
||||
/* copy nodenumbers of ports from parent */
|
||||
ob2 = ParentParams;
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) {
|
||||
if (IsPort(tmp)) {
|
||||
if (tmp->node > 0) {
|
||||
if (ob2->node == -1) {
|
||||
|
||||
// Before commiting to attaching to a unconnected node, see
|
||||
// if there is another node in ParentParams with the same
|
||||
// name and a valid node number. If so, connect them. In
|
||||
// the broader case, it may be necessary to consider all
|
||||
// nodes, not just those with node == -1, and call join()
|
||||
// here to update all node numbers in the parent cell.
|
||||
// In that case, a more efficient method is needed for
|
||||
// tracking same-name ports.
|
||||
|
||||
for (ob3 = ParentParams; ob3 && ob3->type >= FIRSTPIN;
|
||||
ob3 = ob3->next) {
|
||||
if (ob3 == ob2) continue;
|
||||
if ((*matchfunc)(ob3->name, ob2->name) && ob3->node != -1) {
|
||||
ob2->node = ob3->node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Debug) {
|
||||
// Printf(" Sealing port: %d to node %d\n", tmp->node, ob2->node);
|
||||
Printf("Update node %d --> %d\n", tmp->node, ob2->node);
|
||||
}
|
||||
UpdateNodeNumbers(ChildStart, tmp->node, ob2->node);
|
||||
}
|
||||
|
||||
/* in pathological cases, the lengths of the port lists may
|
||||
* change. This is an error, but that is no reason to allow
|
||||
* the code to core dump. We avoid this by placing a
|
||||
* superfluous check on ob2->type
|
||||
*/
|
||||
if (ob2 != NULL) ob2 = ob2->next;
|
||||
|
||||
if (ob2 == NULL) break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Using name == NULL to indicate that a .ext file is being */
|
||||
/* flattened on the fly. This is quick & dirty. */
|
||||
|
||||
if (name != NULL) {
|
||||
/* delete all port elements from child */
|
||||
while ((ChildStart != NULL) && IsPort(ChildStart)) {
|
||||
/* delete all ports at beginning of list */
|
||||
if (Debug) Printf("deleting leading port from child\n");
|
||||
tmp = ChildStart->next;
|
||||
FreeObject(ChildStart);
|
||||
ChildStart = tmp;
|
||||
}
|
||||
tmp = ChildStart;
|
||||
while (tmp && (tmp->next != NULL)) {
|
||||
if (IsPort(tmp->next)) {
|
||||
ob2 = (tmp->next)->next;
|
||||
if (Debug) Printf("deleting a port from child\n");
|
||||
FreeObject(tmp->next);
|
||||
tmp->next = ob2;
|
||||
}
|
||||
else tmp = tmp->next;
|
||||
}
|
||||
if (ChildStart == NULL) {
|
||||
if (ChildListEnd == ChildEnd) ChildListEnd = NULL;
|
||||
ChildEnd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* for each element in child, prepend 'prefix' */
|
||||
#if !OLDPREFIX
|
||||
/* replaces all the sprintf's below */
|
||||
strcpy(tmpstr,ParentParams->instance.name);
|
||||
strcat(tmpstr,SEPARATOR);
|
||||
prefixlength = strlen(tmpstr);
|
||||
/* replaces all the sprintf's below */
|
||||
strcpy(tmpstr,ParentParams->instance.name);
|
||||
strcat(tmpstr,SEPARATOR);
|
||||
prefixlength = strlen(tmpstr);
|
||||
#endif
|
||||
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) {
|
||||
if (tmp->type == PROPERTY)
|
||||
continue;
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) {
|
||||
if (tmp->type == PROPERTY)
|
||||
continue;
|
||||
|
||||
else if (IsGlobal(tmp)) {
|
||||
/* Keep the name but search for node of same name in parent */
|
||||
/* and replace the node number, if found. */
|
||||
else if (IsGlobal(tmp)) {
|
||||
/* Keep the name but search for node of same name in parent */
|
||||
/* and replace the node number, if found. */
|
||||
|
||||
for (ob2 = ThisCell->cell; ob2 != NULL; ob2 = ob2->next) {
|
||||
/* Type in parent may be a port, not a global */
|
||||
if (ob2->type == tmp->type || ob2->type == PORT) {
|
||||
if ((*matchfunc)(tmp->name, ob2->name)) {
|
||||
if (ob2->node >= 0) {
|
||||
// Replace all child objects with this node number
|
||||
rnodenum = tmp->node;
|
||||
for (ob3 = ChildObjList; ob3 != NULL; ob3 = ob3->next) {
|
||||
if (ob3->node == rnodenum)
|
||||
ob3->node = ob2->node;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't hash this if the parent had a port of this name
|
||||
if (!ob2 || ob2->type != PORT)
|
||||
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
|
||||
continue;
|
||||
}
|
||||
for (ob2 = ThisCell->cell; ob2 != NULL; ob2 = ob2->next) {
|
||||
/* Type in parent may be a port, not a global */
|
||||
if (ob2->type == tmp->type || ob2->type == PORT) {
|
||||
if ((*matchfunc)(tmp->name, ob2->name)) {
|
||||
if (ob2->node >= 0) {
|
||||
// Replace all child objects with this node number
|
||||
rnodenum = tmp->node;
|
||||
for (ob3 = ChildStart; ob3 != NULL; ob3 = ob3->next) {
|
||||
if (ob3->node == rnodenum)
|
||||
ob3->node = ob2->node;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't hash this if the parent had a port of this name
|
||||
if (!ob2 || ob2->type != PORT)
|
||||
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
|
||||
continue;
|
||||
}
|
||||
|
||||
#if OLDPREFIX
|
||||
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
|
||||
tmp->name);
|
||||
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
|
||||
tmp->name);
|
||||
#else
|
||||
strcpy(tmpstr+prefixlength,tmp->name);
|
||||
strcpy(tmpstr+prefixlength,tmp->name);
|
||||
#endif
|
||||
if (Debug) Printf("Renaming %s to %s\n", tmp->name, tmpstr);
|
||||
FreeString(tmp->name);
|
||||
tmp->name = strsave(tmpstr);
|
||||
if (Debug) Printf("Renaming %s to %s\n", tmp->name, tmpstr);
|
||||
FreeString(tmp->name);
|
||||
tmp->name = strsave(tmpstr);
|
||||
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
|
||||
if ((tmp->type != NODE) && (tmp->instance.name != NULL)) {
|
||||
#if OLDPREFIX
|
||||
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
|
||||
tmp->instance.name);
|
||||
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
|
||||
tmp->instance.name);
|
||||
#else
|
||||
strcpy(tmpstr+prefixlength,tmp->instance.name);
|
||||
strcpy(tmpstr+prefixlength,tmp->instance.name);
|
||||
#endif
|
||||
FreeString(tmp->instance.name);
|
||||
tmp->instance.name = strsave(tmpstr);
|
||||
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
|
||||
if (tmp->type == FIRSTPIN)
|
||||
HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict));
|
||||
}
|
||||
|
||||
/* Do property inheritance */
|
||||
|
||||
if (ParentProps) {
|
||||
for (ob2 = ChildObjList; ob2 != NULL; ob2=ob2->next) {
|
||||
|
||||
/* If the parent cell has properties to declare, then */
|
||||
/* pass them on to children. Use globals only if the */
|
||||
/* spiceparams dictionary is active (during file reading */
|
||||
/* only). */
|
||||
|
||||
if (ob2->type == PROPERTY)
|
||||
ReduceExpressions(ob2, ParentProps, ChildCell,
|
||||
(spiceparams.hashtab == NULL) ? 0 : 1);
|
||||
FreeString(tmp->instance.name);
|
||||
tmp->instance.name = strsave(tmpstr);
|
||||
if (tmp->type == FIRSTPIN)
|
||||
HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict));
|
||||
}
|
||||
}
|
||||
|
||||
/* Do property inheritance */
|
||||
|
||||
/* NOTE: Need to do: Check properties for M > 1 and decrement
|
||||
* and repeat without moving CurrentProp
|
||||
*/
|
||||
|
||||
if (CurrentProp) {
|
||||
for (ob2 = ChildStart; ob2 != NULL; ob2=ob2->next) {
|
||||
|
||||
/* If the parent cell has properties to declare, then */
|
||||
/* pass them on to children. Use globals only if the */
|
||||
/* spiceparams dictionary is active (during file */
|
||||
/* reading only). */
|
||||
|
||||
if (ob2->type == PROPERTY)
|
||||
ReduceExpressions(ob2, CurrentProp, ChildCell,
|
||||
(spiceparams.hashtab == NULL) ? 0 : 1);
|
||||
}
|
||||
|
||||
/* Repeat for each property record, as each property represents a
|
||||
* unique instance that must be flattened individually.
|
||||
*/
|
||||
|
||||
CurrentProp = CurrentProp->next;
|
||||
if ((CurrentProp == NULL) || (CurrentProp->type != PROPERTY)) break;
|
||||
}
|
||||
else break;
|
||||
|
||||
/* Put the child cell at the start of ChildObjList */
|
||||
ChildEnd->next = ChildObjList;
|
||||
ChildObjList = ChildStart;
|
||||
}
|
||||
|
||||
/* splice instance out of parent */
|
||||
if ((ParentParams == ThisCell->cell) && (ChildObjList == NULL)) {
|
||||
ThisCell->cell = ob2; /* Child cell was empty */
|
||||
tmp = ob2;
|
||||
/* Put the child cell at the start of ChildObjList */
|
||||
if (ChildEnd) {
|
||||
ChildEnd->next = ChildObjList;
|
||||
ChildObjList = ChildStart;
|
||||
}
|
||||
else {
|
||||
|
||||
/* Pull the instance out of the parent */
|
||||
|
||||
if ((ParentParams != ThisCell->cell) || (ChildObjList != NULL)) {
|
||||
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) ;
|
||||
/* ParentParams are the very first thing in the list */
|
||||
ThisCell->cell = ChildObjList;
|
||||
}
|
||||
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) ;
|
||||
else if (ChildObjList) {
|
||||
/* find ParentParams in ThisCell list. In most cases, LastObj */
|
||||
/* should be pointing to it. */
|
||||
if (LastObj && (LastObj->next == ParentParams)) {
|
||||
LastObj->next = ChildObjList;
|
||||
}
|
||||
else {
|
||||
for (ob2 = LastObj; ob2 && ob2->next != ParentParams;
|
||||
ob2 = ob2->next);
|
||||
if (ob2 == NULL) {
|
||||
/* It should not happen that LastObj is ahead of ParentParams */
|
||||
/* but just in case, this long loop will find it. */
|
||||
for (ob2 = ThisCell->cell; ob2 && ob2->next != ParentParams;
|
||||
ob2 = ob2->next);
|
||||
}
|
||||
ob2->next = ChildObjList;
|
||||
}
|
||||
}
|
||||
/* now, ob2 is last element in child list, so skip and reclaim parent */
|
||||
else {
|
||||
/* The child was completely optimized out, so close list around it */
|
||||
LastObj->next = ParentEnd->next;
|
||||
}
|
||||
|
||||
tmp = ParentParams;
|
||||
do {
|
||||
tmp = tmp->next;
|
||||
} while ((tmp != NULL) && ((tmp->type > FIRSTPIN) || (tmp->type == PROPERTY)));
|
||||
if (ob2) ob2->next = tmp;
|
||||
/* Link end of child list into the parent */
|
||||
if (ChildListEnd && ParentEnd)
|
||||
ChildListEnd->next = ParentEnd->next;
|
||||
}
|
||||
while (ParentParams != tmp) {
|
||||
ob2 = ParentParams->next;
|
||||
FreeObjectAndHash(ParentParams, ThisCell);
|
||||
ParentParams = ob2;
|
||||
ParentNext = (ParentEnd) ? ParentEnd->next : NULL;
|
||||
while (ParentParams != ParentNext) {
|
||||
ob2 = ParentParams->next;
|
||||
FreeObjectAndHash(ParentParams, ThisCell);
|
||||
ParentParams = ob2;
|
||||
}
|
||||
NextObj = ParentParams;
|
||||
} /* repeat until no more instances found */
|
||||
@@ -1136,9 +1215,10 @@ int UniquePins(char *name, int filenum)
|
||||
struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct objlist *ob, *obt, *lob, *nob, *firstpin;
|
||||
struct objlist *ob, *obt, *lob, *nob, *firstpin, *pob;
|
||||
struct nlist *tc = (struct nlist *)clientdata;
|
||||
int pinnum;
|
||||
char *saveinst = NULL;
|
||||
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if (tc->file != ptr->file) return NULL;
|
||||
@@ -1186,13 +1266,44 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
|
||||
}
|
||||
|
||||
FREE(ob->name);
|
||||
if (ob->instance.name != NULL) FREE(ob->instance.name);
|
||||
if (ob->instance.name != NULL) {
|
||||
/* Keep a copy of the instance name (see below) */
|
||||
if (saveinst != NULL) FREE(saveinst);
|
||||
saveinst = ob->instance.name;
|
||||
}
|
||||
if (ob->model.class != NULL) FREE(ob->model.class);
|
||||
FREE(ob);
|
||||
}
|
||||
else {
|
||||
lob = ob;
|
||||
ob->type = pinnum++; // Renumber pins in order
|
||||
if ((ob->type == PROPERTY) && (pinnum == 1))
|
||||
{
|
||||
/* If this happens, then all the pins got removed,
|
||||
* and there is probably something very much wrong
|
||||
* with the setup. However, to keep netgen from
|
||||
* blowing up, add back a "proxy(no pins)" record
|
||||
* in front; otherwise we'd have an orphaned
|
||||
* property record.
|
||||
*/
|
||||
pob = GetObject();
|
||||
pob->name = (char *)MALLOC(15);
|
||||
sprintf(pob->name, "proxy(no pins)");
|
||||
pob->model.class = strsave(ob->model.class);
|
||||
if (saveinst != NULL)
|
||||
pob->instance.name = strsave(saveinst);
|
||||
else
|
||||
/* This should never happen */
|
||||
pob->instance.name = strsave("error");
|
||||
pob->type = pinnum++;
|
||||
pob->node = -1;
|
||||
pob->next = ob;
|
||||
lob->next = pob;
|
||||
lob = ob;
|
||||
}
|
||||
else
|
||||
{
|
||||
lob = ob;
|
||||
ob->type = pinnum++; // Renumber pins in order
|
||||
}
|
||||
}
|
||||
ob = nob;
|
||||
obt = obt->next;
|
||||
@@ -1203,6 +1314,8 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
|
||||
HashPtrInstall(firstpin->instance.name, firstpin, &(ptr->instdict));
|
||||
}
|
||||
}
|
||||
|
||||
if (saveinst != NULL) FREE(saveinst);
|
||||
return NULL; /* Keep the search going */
|
||||
}
|
||||
|
||||
@@ -1475,13 +1588,13 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
if (ecomp->cell1) {
|
||||
if (ecomp->cell1 && (ecomp->num1 > 0)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
" makes a better match\n", ecomp->cell1->name,
|
||||
name1);
|
||||
flattenInstancesOf(name1, file1, ecomp->cell1->name);
|
||||
}
|
||||
if (ecomp->cell2) {
|
||||
if (ecomp->cell2 && (ecomp->num2 > 0)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
" makes a better match\n", ecomp->cell2->name,
|
||||
name2);
|
||||
|
||||
+726
-382
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,6 @@ extern struct nlist *Circuit1;
|
||||
extern struct nlist *Circuit2;
|
||||
|
||||
extern int ExhaustiveSubdivision;
|
||||
extern int FastSymmetryBreaking;
|
||||
|
||||
extern int left_col_end;
|
||||
extern int right_col_end;
|
||||
|
||||
+3
-1
@@ -896,7 +896,9 @@ char *ReadNetlist(char *fname, int *fnum)
|
||||
|
||||
/* make first pass looking for extension */
|
||||
for (index = 0; formats[index].extension != NULL; index++) {
|
||||
if (strstr(fname, formats[index].extension) != NULL) {
|
||||
int extlen = strlen(formats[index].extension);
|
||||
int flen = strlen(fname);
|
||||
if (!strcmp(fname + flen - extlen, formats[index].extension)) {
|
||||
return (*(formats[index].proc))(fname, fnum);
|
||||
}
|
||||
}
|
||||
|
||||
+617
-529
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -43,7 +43,8 @@ extern int PropertyMerge(char *name, int fnum, char *key, int merge_type,
|
||||
int merge_mask);
|
||||
extern void ResolveProperties(char *name1, int file1, char *name2, int file2);
|
||||
extern void CopyProperties(struct objlist *obj_to, struct objlist *obj_from);
|
||||
extern int PromoteProperty(struct property *, struct valuelist *);
|
||||
extern int PromoteProperty(struct property *, struct valuelist *,
|
||||
struct objlist *, struct nlist *);
|
||||
extern int SetPropertyDefault(struct property *, struct valuelist *);
|
||||
extern struct objlist *LinkProperties(char *model, struct keyvalue *topptr);
|
||||
extern int ReduceExpressions(struct objlist *instprop, struct objlist *parprops,
|
||||
@@ -149,6 +150,7 @@ 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 */
|
||||
extern int GlobalParallelOpen; /* If TRUE, parallel combine cells w/no-connects */
|
||||
/* 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??? */
|
||||
|
||||
@@ -975,6 +975,7 @@ struct objlist *CopyObjList(struct objlist *oldlist, unsigned char doforall)
|
||||
newob->model.class = NULL;
|
||||
else
|
||||
newob->model.class = strsave(tmp->model.class);
|
||||
newob->flags = tmp->flags;
|
||||
newob->instance.name = (tmp->instance.name) ?
|
||||
strsave(tmp->instance.name) : NULL;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#define PROXY (0) /* Used in model.port record of ports */
|
||||
|
||||
#define NO_CONNECT 1 /* Use in object list to flag an isolated net */
|
||||
|
||||
/* Lists of device properties. Order is defined at the time of */
|
||||
/* the cell definition; values are sorted at the time instances */
|
||||
/* are read. */
|
||||
@@ -162,6 +164,7 @@ struct objlist {
|
||||
/* (string) value of property for properties */
|
||||
struct valuelist *props; /* Property record */
|
||||
} instance;
|
||||
unsigned char flags; /* Used by NODE type to flag isolated net */
|
||||
int node; /* the electrical node number of the port/node/pin */
|
||||
struct objlist *next;
|
||||
};
|
||||
|
||||
+1
-1
@@ -1186,7 +1186,7 @@ skip_ends:
|
||||
else if (CountPorts(model, filenum) != 2) {
|
||||
/* Modeled device: Make sure it has the right number of ports */
|
||||
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a "
|
||||
"resistor.\n");
|
||||
"resistor.\n", model);
|
||||
goto baddevice;
|
||||
}
|
||||
usemodel = 1;
|
||||
|
||||
@@ -63,6 +63,10 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#define VLOG_PIN_NAME_DELIMITERS "X///**/(**)X()"
|
||||
#define VLOG_PIN_CHECK_DELIMITERS "X///**/(**)X,;(){}"
|
||||
|
||||
// Used by portelement structure "flags" record.
|
||||
#define PORT_NOT_FOUND 0
|
||||
#define PORT_FOUND 1
|
||||
|
||||
// Global storage for verilog parameters
|
||||
struct hashdict verilogparams;
|
||||
// Global storage for verilog definitions
|
||||
@@ -1404,6 +1408,7 @@ skip_endmodule:
|
||||
char *name; // Name of port in subcell
|
||||
char *net; // Name of net connecting to port in the parent
|
||||
int width; // Width of port, if port is a bus
|
||||
char flags; // Used for marking if port was added into netlist
|
||||
struct portelement *next;
|
||||
};
|
||||
|
||||
@@ -1530,6 +1535,7 @@ nextinst:
|
||||
new_port = (struct portelement *)CALLOC(1, sizeof(struct portelement));
|
||||
new_port->name = strsave(nexttok + 1);
|
||||
new_port->width = -1;
|
||||
new_port->flags = PORT_NOT_FOUND;
|
||||
SkipTokComments(VLOG_DELIMITERS);
|
||||
if (!match(nexttok, "(")) {
|
||||
Printf("Badly formed subcircuit pin line at \"%s\"\n", nexttok);
|
||||
@@ -1571,6 +1577,14 @@ nextinst:
|
||||
}
|
||||
new_port->net = wire_bundle;
|
||||
}
|
||||
else if (nexttok[0] == '~' || nexttok[0] == '!' || nexttok[0] == '-') {
|
||||
/* All of these imply that the signal is logically manipulated */
|
||||
/* in turn implying behavioral code. */
|
||||
Printf("Module '%s' is not structural verilog, "
|
||||
"making black-box.\n", model);
|
||||
SetClass(CLASS_MODULE);
|
||||
goto skip_endmodule;
|
||||
}
|
||||
else
|
||||
new_port->net = strsave(nexttok);
|
||||
|
||||
@@ -1964,6 +1978,7 @@ nextinst:
|
||||
obpinidx = -1;
|
||||
while (scan != NULL) {
|
||||
if (match(obpinname, scan->name)) {
|
||||
scan->flags |= PORT_FOUND;
|
||||
break;
|
||||
}
|
||||
scan = scan->next;
|
||||
@@ -2056,6 +2071,89 @@ nextinst:
|
||||
if (LookupObject(scan->net, CurrentCell) == NULL) Node(scan->net);
|
||||
join(scan->net, obptr->name);
|
||||
}
|
||||
|
||||
/* Before exiting the loop, check if all ports in the */
|
||||
/* scan list were handled. */
|
||||
|
||||
if ((obptr->next == NULL) || (obptr->next->type <= FIRSTPIN)) {
|
||||
for (scan = head; scan; scan = scan->next) {
|
||||
if (!(scan->flags & PORT_FOUND)) {
|
||||
if (tp->flags & CELL_PLACEHOLDER) {
|
||||
char tempname[128];
|
||||
int maxnode;
|
||||
|
||||
/* This pin was probably implicit in the first call */
|
||||
/* and so it needs to be added to the definition. */
|
||||
|
||||
ReopenCellDef(modulename, filenum);
|
||||
Port(scan->name);
|
||||
ReopenCellDef((*CellStackPtr)->cellname, filenum);
|
||||
|
||||
/* obptr->next now gets the new port. Update the */
|
||||
/* port number, and copy class and instance name. */
|
||||
nobj = GetObject();
|
||||
sprintf(tempname, "%s%s%s", obptr->instance.name,
|
||||
SEPARATOR, scan->name);
|
||||
nobj->name = strsave(tempname);
|
||||
nobj->model.class = strsave(obptr->model.class);
|
||||
nobj->instance.name = strsave(obptr->instance.name);
|
||||
nobj->type = obptr->type + 1;
|
||||
nobj->next = obptr->next;
|
||||
nobj->node = -1;
|
||||
obptr->next = nobj;
|
||||
HashPtrInstall(nobj->name, nobj, &(CurrentCell->objdict));
|
||||
|
||||
if (LookupObject(scan->net, CurrentCell) == NULL)
|
||||
Node(scan->net);
|
||||
join(scan->net, nobj->name);
|
||||
scan->flags |= PORT_FOUND;
|
||||
|
||||
/* Now any previous instance of the same cell must */
|
||||
/* insert the same additional pin as a no-connect. */
|
||||
/* NOTE: This should be running a callback on all */
|
||||
/* cells in the file, not just CurrentCell. */
|
||||
|
||||
for (sobj = CurrentCell->cell; sobj && (sobj != obptr);
|
||||
sobj = sobj->next) {
|
||||
if (sobj->type == FIRSTPIN) {
|
||||
if (match(sobj->model.class, obptr->model.class)) {
|
||||
while (sobj->next->type > FIRSTPIN)
|
||||
sobj = sobj->next;
|
||||
/* Stop when reaching the current instance */
|
||||
if (sobj->type == obptr->type + 1) break;
|
||||
nobj = GetObject();
|
||||
sprintf(tempname, "%s%s%s", sobj->instance.name,
|
||||
SEPARATOR, scan->name);
|
||||
nobj->name = strsave(tempname);
|
||||
nobj->model.class = strsave(sobj->model.class);
|
||||
nobj->instance.name = strsave(sobj->instance.name);
|
||||
nobj->type = obptr->type + 1;
|
||||
nobj->node = -1;
|
||||
nobj->next = sobj->next;
|
||||
sobj->next = nobj;
|
||||
HashPtrInstall(nobj->name, nobj,
|
||||
&(CurrentCell->objdict));
|
||||
|
||||
sprintf(tempname, "_noconnect_%d_", localcount++);
|
||||
Node(tempname);
|
||||
join(tempname, nobj->name);
|
||||
Fprintf(stderr, "Note: Implicit pin %s in instance "
|
||||
"%s of %s in cell %s\n",
|
||||
scan->name, sobj->instance.name,
|
||||
modulename, CurrentCell->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Fprintf(stderr, "Error: Instance %s has pin %s which is "
|
||||
"not in the %s cell definition.\n",
|
||||
locinst, scan->name, modulename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obptr = obptr->next;
|
||||
} while (obptr != NULL && obptr->type > FIRSTPIN);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ SCRIPTINSTALL = $(DESTDIR)${INSTALL_PYDIR}
|
||||
|
||||
include ${NETGENDIR}/defs.mak
|
||||
|
||||
CLEANS += lvs_manager.py
|
||||
|
||||
main: lvs_manager.py
|
||||
|
||||
tcl-main: lvs_manager.py
|
||||
|
||||
Executable → Regular
+108
-36
@@ -343,7 +343,7 @@ class LVSManager(ttk.Frame):
|
||||
techbase = os.path.split(techname)[1]
|
||||
self.tech = os.path.splitext(techbase)[0]
|
||||
self.lvs_setup = techname
|
||||
self.toppane.title2_frame.layout_select.config(text = self.tech)
|
||||
self.toppane.title2_frame.tech_select.config(text = self.tech)
|
||||
|
||||
def choose_layout(self):
|
||||
try:
|
||||
@@ -358,30 +358,37 @@ class LVSManager(ttk.Frame):
|
||||
title = "Choose a layout cell to compare.")
|
||||
if cellname != '':
|
||||
print("Selected compare cell " + cellname)
|
||||
self.layout = cellname
|
||||
cellbase = os.path.split(cellname)[1]
|
||||
self.layout = os.path.splitext(cellbase)[0]
|
||||
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||
layoutname = os.path.splitext(cellbase)[0]
|
||||
self.toppane.title2_frame.layout_select.config(text = layoutname)
|
||||
fileext = os.path.splitext(cellbase)[1]
|
||||
if fileext == '.mag':
|
||||
self.toppane.title2_frame.layout_label.config(text = 'Layout:')
|
||||
else:
|
||||
self.toppane.title2_frame.layout_label.config(text = 'Layout netlist:')
|
||||
|
||||
def choose_netlist(self):
|
||||
try:
|
||||
project_path = self.rootpath
|
||||
initdirname = self.rootpath + '/netlist/' + self.project + '.spi'
|
||||
initdirname = self.rootpath + '/netlist/' + self.project + '.spice'
|
||||
except:
|
||||
print('Must choose a project first.')
|
||||
return
|
||||
cellname = filedialog.askopenfilename(multiple=False,
|
||||
initialdir = initdirname,
|
||||
filetypes = (("Spice netlist", "*.spi"),("Verilog netlist", "*.v")),
|
||||
filetypes = (("Spice netlist", "*.spice"),("Verilog netlist", "*.v"),("All Files","*.*")),
|
||||
title = "Choose a netlist to compare.")
|
||||
if cellname != '':
|
||||
print("Selected compare cell " + cellname)
|
||||
self.schematic = cellname
|
||||
cellbase = os.path.split(cellname)[1]
|
||||
self.schematic = os.path.splitext(cellbase)[0]
|
||||
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||
schematic_name = os.path.splitext(cellbase)[0]
|
||||
self.toppane.title2_frame.schem_select.config(text = schematic_name)
|
||||
fileext = os.path.splitext(cellbase)[1]
|
||||
if fileext == '.v':
|
||||
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||
elif fileext == '.sp' or fileext == '.spi' or fileext == '.spice' or fileext == '.spc' or fileext == '.ckt':
|
||||
elif fileext == '.sp' or fileext == '.spice' or fileext == '.spi' or fileext == '.spc' or fileext == '.ckt':
|
||||
self.toppane.title2_frame.schem_label.config(text = 'SPICE netlist:')
|
||||
elif fileext == '.cdl':
|
||||
self.toppane.title2_frame.schem_label.config(text = 'CDL netlist:')
|
||||
@@ -433,7 +440,10 @@ class LVSManager(ttk.Frame):
|
||||
self.logfile = None
|
||||
|
||||
# Put new log file called 'lvs.log' in the mag/ subdirectory
|
||||
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
|
||||
if os.path.exists(rootpath + '/layout'):
|
||||
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
|
||||
else:
|
||||
self.logfile = open(rootpath + '/lvs.log', 'w')
|
||||
# Print some initial information to the logfile.
|
||||
self.logprint('Starting new log file ' + datetime.datetime.now().strftime('%c'),
|
||||
doflush=True)
|
||||
@@ -444,15 +454,23 @@ class LVSManager(ttk.Frame):
|
||||
# Cell name is the same as project name initially
|
||||
self.layout = self.project
|
||||
self.schematic = self.project
|
||||
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||
layname = os.path.splitext(os.path.split(self.layout)[1])[0]
|
||||
self.toppane.title2_frame.layout_select.config(text = layname)
|
||||
schemname = os.path.splitext(os.path.split(self.schematic)[1])[0]
|
||||
self.toppane.title2_frame.schem_select.config(text = schemname)
|
||||
|
||||
# Update schematic button
|
||||
if os.path.isfile(rootpath + '/verilog/' + self.schematic + '.v'):
|
||||
if os.path.splitext(self.schematic)[1] == '.v':
|
||||
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||
else:
|
||||
self.toppane.title2_frame.schem_label.config(text = 'Schematic netlist:')
|
||||
|
||||
# Update layout button
|
||||
if os.path.splitext(self.layout)[1] == '.mag':
|
||||
self.toppane.title2_frame.schem_label.config(text = 'Layout:')
|
||||
else:
|
||||
self.toppane.title2_frame.schem_label.config(text = 'Layout netlist:')
|
||||
|
||||
# If there is a comparison file that post-dates both netlists, load it.
|
||||
self.check_lvs()
|
||||
return True
|
||||
@@ -567,8 +585,8 @@ class LVSManager(ttk.Frame):
|
||||
# load LVS results from comp.json
|
||||
project_path = self.rootpath
|
||||
project_name = self.project
|
||||
layout_path = project_path + '/layout/' + project_name + '.spc'
|
||||
net_path = project_path + '/netlist/' + project_name + '.spi'
|
||||
layout_path = project_path + '/layout/' + project_name + '.spice'
|
||||
net_path = project_path + '/netlist/' + project_name + '.spice'
|
||||
comp_path = project_path + '/layout/comp.json'
|
||||
|
||||
if os.path.exists(layout_path) and os.path.exists(net_path) and os.path.exists(comp_path):
|
||||
@@ -599,7 +617,7 @@ class LVSManager(ttk.Frame):
|
||||
mproc.stdin.write("ext2spice cthresh infinite\n")
|
||||
mproc.stdin.write("ext2spice rthresh infinite\n")
|
||||
mproc.stdin.write("ext2spice blackbox on\n")
|
||||
mproc.stdin.write("ext2spice -o " + self.layout + ".spi\n")
|
||||
mproc.stdin.write("ext2spice -o " + self.layout + ".spice\n")
|
||||
mproc.stdin.write("quit -noprompt\n")
|
||||
magicout = mproc.communicate()[0]
|
||||
self.printwarn(magicout)
|
||||
@@ -607,8 +625,8 @@ class LVSManager(ttk.Frame):
|
||||
print('Failure to generate new layout netlist.')
|
||||
return False
|
||||
|
||||
# Move .spi netlist to project_dir/netlist/lvs/
|
||||
shutil.move(project_path + '/layout/' + self.layout + '.spi', layout_path)
|
||||
# Move .spice netlist to project_dir/netlist/lvs/
|
||||
shutil.move(project_path + '/layout/' + self.layout + '.spice', layout_path)
|
||||
# Remove extraction files
|
||||
for file in os.listdir(project_path + '/layout'):
|
||||
if os.path.splitext(file)[1] == '.ext':
|
||||
@@ -625,17 +643,37 @@ class LVSManager(ttk.Frame):
|
||||
|
||||
project_path = self.rootpath
|
||||
project_name = self.project
|
||||
comp_path = project_path + '/layout/comp.json'
|
||||
|
||||
# Diagnostic:
|
||||
print('project_name is ' + project_name)
|
||||
print('project_path is ' + project_path)
|
||||
print('self.layout is ' + self.layout)
|
||||
print('self.schematic is ' + self.schematic)
|
||||
print('self.lvs_setup is ' + self.lvs_setup)
|
||||
|
||||
has_vlog = False
|
||||
vlog_path = project_path + '/verilog/' + project_name + '.v'
|
||||
|
||||
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spi'
|
||||
net_path = project_path + '/netlist/schem/' + self.schematic + '.spi'
|
||||
layout_src = project_path + '/layout/' + self.layout + '.mag'
|
||||
if os.path.isfile(self.layout):
|
||||
layout_path = self.layout
|
||||
layout_src = None
|
||||
else:
|
||||
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spice'
|
||||
layout_src = project_path + '/layout/' + self.layout + '.mag'
|
||||
|
||||
comp_dir = os.path.split(layout_path)[0]
|
||||
comp_path = comp_dir + '/comp.json'
|
||||
|
||||
if os.path.isfile(self.schematic):
|
||||
net_path = self.schematic
|
||||
else:
|
||||
net_path = project_path + '/netlist/schem/' + self.schematic + '.spice'
|
||||
|
||||
# Does the setup file exist (this is optional)?
|
||||
if self.lvs_setup != '' and not os.path.isfile('setup.tcl'):
|
||||
if self.lvs_setup == '' and not os.path.isfile('setup.tcl'):
|
||||
print('No technology setup file selected.')
|
||||
elif not os.path.isfile(self.lvs_setup):
|
||||
print("Can't find technology setup file " + self.lvs_setup)
|
||||
|
||||
# Does schematic netlist exist?
|
||||
if not os.path.isfile(vlog_path) and not os.path.isfile(net_path):
|
||||
@@ -643,14 +681,16 @@ class LVSManager(ttk.Frame):
|
||||
return
|
||||
|
||||
# Does LVS netlist subdirectory exist?
|
||||
if not os.path.exists(project_path + '/netlist/lvs'):
|
||||
os.makedirs(project_path + '/netlist/lvs')
|
||||
if os.path.exists(project_path + '/netlist'):
|
||||
if not os.path.exists(project_path + '/netlist/lvs'):
|
||||
os.makedirs(project_path + '/netlist/lvs')
|
||||
|
||||
# Does layout netlist exist and is it current?
|
||||
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
|
||||
return False
|
||||
if layout_src:
|
||||
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
|
||||
return False
|
||||
|
||||
# Final check
|
||||
# Final checks
|
||||
if not os.path.isfile(layout_path):
|
||||
print('Error: No netlist generated from magic.')
|
||||
return
|
||||
@@ -662,26 +702,27 @@ class LVSManager(ttk.Frame):
|
||||
with open(layout_path) as ifile:
|
||||
spitext = ifile.read()
|
||||
|
||||
# spilines = spitext.replace(',', '|')
|
||||
# with open(layout_path, 'w') as ofile:
|
||||
# ofile.write(spilines)
|
||||
|
||||
# Check the netlist to see if the cell to match is a subcircuit. If
|
||||
# not, then assume it is the top level.
|
||||
|
||||
layoutcell = os.path.splitext(os.path.split(self.layout)[1])[0]
|
||||
is_subckt = False
|
||||
subname = None
|
||||
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||
dutlines = spitext.replace('\n+', ' ').splitlines()
|
||||
for line in dutlines:
|
||||
lmatch = subrex.match(line)
|
||||
if lmatch:
|
||||
subname = lmatch.group(1)
|
||||
if subname == self.layout:
|
||||
if subname == layoutcell:
|
||||
is_subckt = True
|
||||
break
|
||||
|
||||
if is_subckt:
|
||||
layout_arg = layout_path + ' ' + self.layout
|
||||
layout_arg = self.layout + ' ' + layoutcell
|
||||
layout_text = '"' + layout_arg + '"'
|
||||
elif subname:
|
||||
layout_arg = self.layout + ' ' + subname
|
||||
layout_text = '"' + layout_arg + '"'
|
||||
else:
|
||||
layout_arg = layout_path
|
||||
@@ -690,8 +731,39 @@ class LVSManager(ttk.Frame):
|
||||
if has_vlog:
|
||||
schem_arg = vlog_path + ' ' + self.schematic
|
||||
else:
|
||||
schem_arg = net_path + ' ' + self.schematic
|
||||
schem_text = '"' + schem_arg + '"'
|
||||
# Final checks
|
||||
if not os.path.isfile(net_path):
|
||||
print('Error: No netlist from schematic.')
|
||||
return
|
||||
|
||||
with open(net_path) as ifile:
|
||||
spitext = ifile.read()
|
||||
|
||||
# Check the netlist to see if the cell to match is a subcircuit. If
|
||||
# not, then assume it is the top level.
|
||||
|
||||
schemcell = os.path.splitext(os.path.split(self.schematic)[1])[0]
|
||||
subname = None
|
||||
is_subckt = False
|
||||
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||
dutlines = spitext.replace('\n+', ' ').splitlines()
|
||||
for line in dutlines:
|
||||
lmatch = subrex.match(line)
|
||||
if lmatch:
|
||||
subname = lmatch.group(1)
|
||||
if subname == schemcell:
|
||||
is_subckt = True
|
||||
break
|
||||
|
||||
if is_subckt:
|
||||
schem_arg = self.schematic + ' ' + schemcell
|
||||
schem_text = '"' + schem_arg + '"'
|
||||
elif subname:
|
||||
schem_arg = self.schematic + ' ' + subname
|
||||
schem_text = '"' + schem_arg + '"'
|
||||
else:
|
||||
schem_arg = net_path
|
||||
schem_text = schem_arg
|
||||
|
||||
# Remove any previous comparison output file
|
||||
comp_out_path = os.path.splitext(comp_path)[0] + '.out'
|
||||
@@ -708,7 +780,7 @@ class LVSManager(ttk.Frame):
|
||||
self.lvsproc = subprocess.Popen(['netgen', '-batch', 'lvs',
|
||||
layout_arg, schem_arg,
|
||||
self.lvs_setup, comp_out_path, '-json', '-blackbox'],
|
||||
cwd=project_path + '/layout',
|
||||
cwd=comp_dir,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)
|
||||
# This is largely unnecessary as netgen usually runs to completion very quickly.
|
||||
self.watchclock(comp_path)
|
||||
|
||||
+108
-36
@@ -343,7 +343,7 @@ class LVSManager(ttk.Frame):
|
||||
techbase = os.path.split(techname)[1]
|
||||
self.tech = os.path.splitext(techbase)[0]
|
||||
self.lvs_setup = techname
|
||||
self.toppane.title2_frame.layout_select.config(text = self.tech)
|
||||
self.toppane.title2_frame.tech_select.config(text = self.tech)
|
||||
|
||||
def choose_layout(self):
|
||||
try:
|
||||
@@ -358,30 +358,37 @@ class LVSManager(ttk.Frame):
|
||||
title = "Choose a layout cell to compare.")
|
||||
if cellname != '':
|
||||
print("Selected compare cell " + cellname)
|
||||
self.layout = cellname
|
||||
cellbase = os.path.split(cellname)[1]
|
||||
self.layout = os.path.splitext(cellbase)[0]
|
||||
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||
layoutname = os.path.splitext(cellbase)[0]
|
||||
self.toppane.title2_frame.layout_select.config(text = layoutname)
|
||||
fileext = os.path.splitext(cellbase)[1]
|
||||
if fileext == '.mag':
|
||||
self.toppane.title2_frame.layout_label.config(text = 'Layout:')
|
||||
else:
|
||||
self.toppane.title2_frame.layout_label.config(text = 'Layout netlist:')
|
||||
|
||||
def choose_netlist(self):
|
||||
try:
|
||||
project_path = self.rootpath
|
||||
initdirname = self.rootpath + '/netlist/' + self.project + '.spi'
|
||||
initdirname = self.rootpath + '/netlist/' + self.project + '.spice'
|
||||
except:
|
||||
print('Must choose a project first.')
|
||||
return
|
||||
cellname = filedialog.askopenfilename(multiple=False,
|
||||
initialdir = initdirname,
|
||||
filetypes = (("Spice netlist", "*.spi"),("Verilog netlist", "*.v")),
|
||||
filetypes = (("Spice netlist", "*.spice"),("Verilog netlist", "*.v"),("All Files","*.*")),
|
||||
title = "Choose a netlist to compare.")
|
||||
if cellname != '':
|
||||
print("Selected compare cell " + cellname)
|
||||
self.schematic = cellname
|
||||
cellbase = os.path.split(cellname)[1]
|
||||
self.schematic = os.path.splitext(cellbase)[0]
|
||||
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||
schematic_name = os.path.splitext(cellbase)[0]
|
||||
self.toppane.title2_frame.schem_select.config(text = schematic_name)
|
||||
fileext = os.path.splitext(cellbase)[1]
|
||||
if fileext == '.v':
|
||||
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||
elif fileext == '.sp' or fileext == '.spi' or fileext == '.spice' or fileext == '.spc' or fileext == '.ckt':
|
||||
elif fileext == '.sp' or fileext == '.spice' or fileext == '.spi' or fileext == '.spc' or fileext == '.ckt':
|
||||
self.toppane.title2_frame.schem_label.config(text = 'SPICE netlist:')
|
||||
elif fileext == '.cdl':
|
||||
self.toppane.title2_frame.schem_label.config(text = 'CDL netlist:')
|
||||
@@ -433,7 +440,10 @@ class LVSManager(ttk.Frame):
|
||||
self.logfile = None
|
||||
|
||||
# Put new log file called 'lvs.log' in the mag/ subdirectory
|
||||
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
|
||||
if os.path.exists(rootpath + '/layout'):
|
||||
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
|
||||
else:
|
||||
self.logfile = open(rootpath + '/lvs.log', 'w')
|
||||
# Print some initial information to the logfile.
|
||||
self.logprint('Starting new log file ' + datetime.datetime.now().strftime('%c'),
|
||||
doflush=True)
|
||||
@@ -444,15 +454,23 @@ class LVSManager(ttk.Frame):
|
||||
# Cell name is the same as project name initially
|
||||
self.layout = self.project
|
||||
self.schematic = self.project
|
||||
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||
layname = os.path.splitext(os.path.split(self.layout)[1])[0]
|
||||
self.toppane.title2_frame.layout_select.config(text = layname)
|
||||
schemname = os.path.splitext(os.path.split(self.schematic)[1])[0]
|
||||
self.toppane.title2_frame.schem_select.config(text = schemname)
|
||||
|
||||
# Update schematic button
|
||||
if os.path.isfile(rootpath + '/verilog/' + self.schematic + '.v'):
|
||||
if os.path.splitext(self.schematic)[1] == '.v':
|
||||
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||
else:
|
||||
self.toppane.title2_frame.schem_label.config(text = 'Schematic netlist:')
|
||||
|
||||
# Update layout button
|
||||
if os.path.splitext(self.layout)[1] == '.mag':
|
||||
self.toppane.title2_frame.schem_label.config(text = 'Layout:')
|
||||
else:
|
||||
self.toppane.title2_frame.schem_label.config(text = 'Layout netlist:')
|
||||
|
||||
# If there is a comparison file that post-dates both netlists, load it.
|
||||
self.check_lvs()
|
||||
return True
|
||||
@@ -567,8 +585,8 @@ class LVSManager(ttk.Frame):
|
||||
# load LVS results from comp.json
|
||||
project_path = self.rootpath
|
||||
project_name = self.project
|
||||
layout_path = project_path + '/layout/' + project_name + '.spc'
|
||||
net_path = project_path + '/netlist/' + project_name + '.spi'
|
||||
layout_path = project_path + '/layout/' + project_name + '.spice'
|
||||
net_path = project_path + '/netlist/' + project_name + '.spice'
|
||||
comp_path = project_path + '/layout/comp.json'
|
||||
|
||||
if os.path.exists(layout_path) and os.path.exists(net_path) and os.path.exists(comp_path):
|
||||
@@ -599,7 +617,7 @@ class LVSManager(ttk.Frame):
|
||||
mproc.stdin.write("ext2spice cthresh infinite\n")
|
||||
mproc.stdin.write("ext2spice rthresh infinite\n")
|
||||
mproc.stdin.write("ext2spice blackbox on\n")
|
||||
mproc.stdin.write("ext2spice -o " + self.layout + ".spi\n")
|
||||
mproc.stdin.write("ext2spice -o " + self.layout + ".spice\n")
|
||||
mproc.stdin.write("quit -noprompt\n")
|
||||
magicout = mproc.communicate()[0]
|
||||
self.printwarn(magicout)
|
||||
@@ -607,8 +625,8 @@ class LVSManager(ttk.Frame):
|
||||
print('Failure to generate new layout netlist.')
|
||||
return False
|
||||
|
||||
# Move .spi netlist to project_dir/netlist/lvs/
|
||||
shutil.move(project_path + '/layout/' + self.layout + '.spi', layout_path)
|
||||
# Move .spice netlist to project_dir/netlist/lvs/
|
||||
shutil.move(project_path + '/layout/' + self.layout + '.spice', layout_path)
|
||||
# Remove extraction files
|
||||
for file in os.listdir(project_path + '/layout'):
|
||||
if os.path.splitext(file)[1] == '.ext':
|
||||
@@ -625,17 +643,37 @@ class LVSManager(ttk.Frame):
|
||||
|
||||
project_path = self.rootpath
|
||||
project_name = self.project
|
||||
comp_path = project_path + '/layout/comp.json'
|
||||
|
||||
# Diagnostic:
|
||||
print('project_name is ' + project_name)
|
||||
print('project_path is ' + project_path)
|
||||
print('self.layout is ' + self.layout)
|
||||
print('self.schematic is ' + self.schematic)
|
||||
print('self.lvs_setup is ' + self.lvs_setup)
|
||||
|
||||
has_vlog = False
|
||||
vlog_path = project_path + '/verilog/' + project_name + '.v'
|
||||
|
||||
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spi'
|
||||
net_path = project_path + '/netlist/schem/' + self.schematic + '.spi'
|
||||
layout_src = project_path + '/layout/' + self.layout + '.mag'
|
||||
if os.path.isfile(self.layout):
|
||||
layout_path = self.layout
|
||||
layout_src = None
|
||||
else:
|
||||
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spice'
|
||||
layout_src = project_path + '/layout/' + self.layout + '.mag'
|
||||
|
||||
comp_dir = os.path.split(layout_path)[0]
|
||||
comp_path = comp_dir + '/comp.json'
|
||||
|
||||
if os.path.isfile(self.schematic):
|
||||
net_path = self.schematic
|
||||
else:
|
||||
net_path = project_path + '/netlist/schem/' + self.schematic + '.spice'
|
||||
|
||||
# Does the setup file exist (this is optional)?
|
||||
if self.lvs_setup != '' and not os.path.isfile('setup.tcl'):
|
||||
if self.lvs_setup == '' and not os.path.isfile('setup.tcl'):
|
||||
print('No technology setup file selected.')
|
||||
elif not os.path.isfile(self.lvs_setup):
|
||||
print("Can't find technology setup file " + self.lvs_setup)
|
||||
|
||||
# Does schematic netlist exist?
|
||||
if not os.path.isfile(vlog_path) and not os.path.isfile(net_path):
|
||||
@@ -643,14 +681,16 @@ class LVSManager(ttk.Frame):
|
||||
return
|
||||
|
||||
# Does LVS netlist subdirectory exist?
|
||||
if not os.path.exists(project_path + '/netlist/lvs'):
|
||||
os.makedirs(project_path + '/netlist/lvs')
|
||||
if os.path.exists(project_path + '/netlist'):
|
||||
if not os.path.exists(project_path + '/netlist/lvs'):
|
||||
os.makedirs(project_path + '/netlist/lvs')
|
||||
|
||||
# Does layout netlist exist and is it current?
|
||||
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
|
||||
return False
|
||||
if layout_src:
|
||||
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
|
||||
return False
|
||||
|
||||
# Final check
|
||||
# Final checks
|
||||
if not os.path.isfile(layout_path):
|
||||
print('Error: No netlist generated from magic.')
|
||||
return
|
||||
@@ -662,26 +702,27 @@ class LVSManager(ttk.Frame):
|
||||
with open(layout_path) as ifile:
|
||||
spitext = ifile.read()
|
||||
|
||||
# spilines = spitext.replace(',', '|')
|
||||
# with open(layout_path, 'w') as ofile:
|
||||
# ofile.write(spilines)
|
||||
|
||||
# Check the netlist to see if the cell to match is a subcircuit. If
|
||||
# not, then assume it is the top level.
|
||||
|
||||
layoutcell = os.path.splitext(os.path.split(self.layout)[1])[0]
|
||||
is_subckt = False
|
||||
subname = None
|
||||
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||
dutlines = spitext.replace('\n+', ' ').splitlines()
|
||||
for line in dutlines:
|
||||
lmatch = subrex.match(line)
|
||||
if lmatch:
|
||||
subname = lmatch.group(1)
|
||||
if subname == self.layout:
|
||||
if subname == layoutcell:
|
||||
is_subckt = True
|
||||
break
|
||||
|
||||
if is_subckt:
|
||||
layout_arg = layout_path + ' ' + self.layout
|
||||
layout_arg = self.layout + ' ' + layoutcell
|
||||
layout_text = '"' + layout_arg + '"'
|
||||
elif subname:
|
||||
layout_arg = self.layout + ' ' + subname
|
||||
layout_text = '"' + layout_arg + '"'
|
||||
else:
|
||||
layout_arg = layout_path
|
||||
@@ -690,8 +731,39 @@ class LVSManager(ttk.Frame):
|
||||
if has_vlog:
|
||||
schem_arg = vlog_path + ' ' + self.schematic
|
||||
else:
|
||||
schem_arg = net_path + ' ' + self.schematic
|
||||
schem_text = '"' + schem_arg + '"'
|
||||
# Final checks
|
||||
if not os.path.isfile(net_path):
|
||||
print('Error: No netlist from schematic.')
|
||||
return
|
||||
|
||||
with open(net_path) as ifile:
|
||||
spitext = ifile.read()
|
||||
|
||||
# Check the netlist to see if the cell to match is a subcircuit. If
|
||||
# not, then assume it is the top level.
|
||||
|
||||
schemcell = os.path.splitext(os.path.split(self.schematic)[1])[0]
|
||||
subname = None
|
||||
is_subckt = False
|
||||
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||
dutlines = spitext.replace('\n+', ' ').splitlines()
|
||||
for line in dutlines:
|
||||
lmatch = subrex.match(line)
|
||||
if lmatch:
|
||||
subname = lmatch.group(1)
|
||||
if subname == schemcell:
|
||||
is_subckt = True
|
||||
break
|
||||
|
||||
if is_subckt:
|
||||
schem_arg = self.schematic + ' ' + schemcell
|
||||
schem_text = '"' + schem_arg + '"'
|
||||
elif subname:
|
||||
schem_arg = self.schematic + ' ' + subname
|
||||
schem_text = '"' + schem_arg + '"'
|
||||
else:
|
||||
schem_arg = net_path
|
||||
schem_text = schem_arg
|
||||
|
||||
# Remove any previous comparison output file
|
||||
comp_out_path = os.path.splitext(comp_path)[0] + '.out'
|
||||
@@ -708,7 +780,7 @@ class LVSManager(ttk.Frame):
|
||||
self.lvsproc = subprocess.Popen(['netgen', '-batch', 'lvs',
|
||||
layout_arg, schem_arg,
|
||||
self.lvs_setup, comp_out_path, '-json', '-blackbox'],
|
||||
cwd=project_path + '/layout',
|
||||
cwd=comp_dir,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)
|
||||
# This is largely unnecessary as netgen usually runs to completion very quickly.
|
||||
self.watchclock(comp_path)
|
||||
|
||||
+97
-18
@@ -352,7 +352,7 @@ proc netgen::convert_to_json {filename lvs_final} {
|
||||
close $fjson
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------
|
||||
#-----------------------------------------------------------------------
|
||||
# Define the "lvs" command as a way of calling the netgen options
|
||||
# for standard compare, essentially the same as the old "netcomp"
|
||||
# standalone program.
|
||||
@@ -361,14 +361,20 @@ proc netgen::convert_to_json {filename lvs_final} {
|
||||
# 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.
|
||||
#----------------------------------------------------------------
|
||||
# "args" may be "-list", "-json", or "-blackbox".
|
||||
# "-list" returns output as a nested list.
|
||||
# "-json" creates a .json-format output file in addition to stdout.
|
||||
# "-blackbox" treats empty cells as black-box entries.
|
||||
# "-noflatten={list}" is a list of cells not to flatten if mismatched.
|
||||
# i.e., the cells are expected to match and any mismatch cannot be
|
||||
# expected to be resolved by flattening the contents of the mismatched
|
||||
# cells.
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
set dolist 0
|
||||
set dojson 0
|
||||
set noflat {}
|
||||
foreach arg $args {
|
||||
if {$arg == "-list"} {
|
||||
puts stdout "Generating list result"
|
||||
@@ -382,9 +388,30 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
} elseif {$arg == "-blackbox"} {
|
||||
puts stdout "Treating empty subcircuits as black-box cells"
|
||||
netgen::model blackbox on
|
||||
} elseif {$arg == "-full"} {
|
||||
puts stdout "Using full symmetry breaking method"
|
||||
netgen::symmetry full
|
||||
} elseif {[string first "-noflatten=" $arg] == 0} {
|
||||
set value [string range $arg 11 end]
|
||||
# If argument is a filename then read the list of cells from it;
|
||||
# otherwise, argument is the list of files itself in quotes or
|
||||
# braces.
|
||||
if {![catch {file exists $value}]} {
|
||||
if {![catch {open $value r} fnf]} {
|
||||
while {[gets $fnf line] >= 0} {
|
||||
if {[lindex $line 0] != "#"} {
|
||||
foreach cell $line {
|
||||
lappend noflat $cell
|
||||
}
|
||||
}
|
||||
}
|
||||
close $fnf
|
||||
} else {
|
||||
puts stderr "Cannot open file $value for reading cell list."
|
||||
}
|
||||
} else {
|
||||
set noflat [string trim $value \"\{\}]
|
||||
}
|
||||
if {[llength $noflat] > 0} {
|
||||
puts stdout "Will not flatten these subcells: $noflat"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,7 +531,8 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
return
|
||||
}
|
||||
set properr {}
|
||||
set pinsgood 0
|
||||
set matcherr {}
|
||||
set pinsgood -1
|
||||
while {$endval != {}} {
|
||||
if {$dolist == 1} {
|
||||
netgen::run -list converge
|
||||
@@ -532,12 +560,32 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
|
||||
# Flatten the non-matching subcircuit (but not the top-level cells)
|
||||
if {[netgen::print queue] != {}} {
|
||||
netgen::log put " Flattening non-matched subcircuits $endval"
|
||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||
if {([lsearch $noflat [lindex $endval 0]] == -1) &&
|
||||
([lsearch $noflat [lindex $endval 1]] == -1)} {
|
||||
netgen::log put " Flattening non-matched subcircuits $endval"
|
||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||
} else {
|
||||
netgen::log put " Continuing with black-boxed subcircuits $endval"
|
||||
lappend matcherr [lindex $endval 0]
|
||||
# Match pins
|
||||
netgen::log echo off
|
||||
if {$dolist == 1} {
|
||||
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
} else {
|
||||
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
}
|
||||
if {$result != 0} {
|
||||
equate classes "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"
|
||||
}
|
||||
set pinsgood $result
|
||||
netgen::log echo on
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# Match pins
|
||||
netgen::log echo off
|
||||
if {$dolist == 1} {
|
||||
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
|
||||
@@ -550,16 +598,43 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
equate classes "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"
|
||||
}
|
||||
set pinsgood $result
|
||||
# If $uresult == -1 then these are black-box entries and
|
||||
# $pinsgood should not be set to the resulting value.
|
||||
if {$uresult > 0} {
|
||||
set pinsgood $result
|
||||
}
|
||||
netgen::log echo on
|
||||
}
|
||||
if {$uresult == 2} {lappend properr [lindex $endval 0]}
|
||||
} else {
|
||||
# Flatten the non-matching subcircuit (but not the top-level cells)
|
||||
if {[netgen::print queue] != {}} {
|
||||
netgen::log put " Flattening non-matched subcircuits $endval"
|
||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||
if {([lsearch $noflat [lindex $endval 1]] == -1) &&
|
||||
([lsearch $noflat [lindex $endval 1]] == -1)} {
|
||||
netgen::log put " Flattening non-matched subcircuits $endval"
|
||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||
} else {
|
||||
netgen::log put " Continuing with black-boxed subcircuits $endval"
|
||||
lappend matcherr [lindex $endval 0]
|
||||
netgen::log put " Continuing with black-boxed subcircuits $endval"
|
||||
lappend matcherr [lindex $endval 0]
|
||||
# Match pins
|
||||
netgen::log echo off
|
||||
if {$dolist == 1} {
|
||||
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
} else {
|
||||
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
}
|
||||
if {$result != 0} {
|
||||
equate classes "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"
|
||||
}
|
||||
set pinsgood $result
|
||||
netgen::log echo on
|
||||
}
|
||||
}
|
||||
}
|
||||
netgen::log echo off
|
||||
@@ -575,13 +650,17 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
puts stdout "Result: " nonewline
|
||||
netgen::log echo on
|
||||
if {$pinsgood == 0} {
|
||||
netgen::log put "The top level cell failed pin matching.\n"
|
||||
# NOTE: Need to disambiguate these two cases. . .
|
||||
netgen::log put "Cells failed matching, or top level cell failed pin matching.\n"
|
||||
} else {
|
||||
verify only
|
||||
}
|
||||
if {$properr != {}} {
|
||||
netgen::log put "The following cells had property errors: $properr\n"
|
||||
}
|
||||
if {$matcherr != {}} {
|
||||
netgen::log put "The following subcells failed to match: $matcherr\n"
|
||||
}
|
||||
if {$dolog} {
|
||||
netgen::log end
|
||||
}
|
||||
|
||||
+53
-41
@@ -246,8 +246,7 @@ Command netcmp_cmds[] = {
|
||||
"\n "
|
||||
"toggle exhaustive subdivision"},
|
||||
{"symmetry", _netcmp_symmetry,
|
||||
"[fast|full]\n "
|
||||
"apply method for symmetry breaking"},
|
||||
"(deprecated)"},
|
||||
{"restart", _netcmp_restart,
|
||||
"\n "
|
||||
"start over (reset data structures)"},
|
||||
@@ -2429,6 +2428,8 @@ _netcmp_run(ClientData clientData,
|
||||
else {
|
||||
enable_interrupt();
|
||||
while (!Iterate() && !InterruptPending);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && !InterruptPending);
|
||||
if (dolist) {
|
||||
result = _netcmp_verify(clientData, interp, 2, objv - 1);
|
||||
}
|
||||
@@ -2447,6 +2448,8 @@ _netcmp_run(ClientData clientData,
|
||||
else {
|
||||
enable_interrupt();
|
||||
while (!Iterate() && !InterruptPending);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && !InterruptPending);
|
||||
automorphisms = VerifyMatching();
|
||||
if (automorphisms == -1)
|
||||
Fprintf(stdout, "Netlists do not match.\n");
|
||||
@@ -2458,8 +2461,7 @@ _netcmp_run(ClientData clientData,
|
||||
automorphisms = ResolveAutomorphsByProperty();
|
||||
if (automorphisms == 0)
|
||||
Fprintf(stdout, "Netlists match uniquely.\n");
|
||||
else {
|
||||
|
||||
else if (automorphisms > 0) {
|
||||
// Next, attempt to resolve automorphisms uniquely by
|
||||
// using the pin names
|
||||
automorphisms = ResolveAutomorphsByPin();
|
||||
@@ -2467,14 +2469,17 @@ _netcmp_run(ClientData clientData,
|
||||
|
||||
if (automorphisms == 0)
|
||||
Fprintf(stdout, "Netlists match uniquely.\n");
|
||||
else
|
||||
else if (automorphisms > 0) {
|
||||
// Anything left is truly indistinguishable
|
||||
Fprintf(stdout, "Netlists match with %d symmetr%s.\n",
|
||||
automorphisms, (automorphisms == 1) ? "y" : "ies");
|
||||
|
||||
while ((automorphisms = ResolveAutomorphisms()) > 0);
|
||||
if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n");
|
||||
else Fprintf(stdout, "Circuits match correctly.\n");
|
||||
while ((automorphisms = ResolveAutomorphisms()) > 0);
|
||||
}
|
||||
if (automorphisms == -1)
|
||||
Fprintf(stdout, "Netlists do not match.\n");
|
||||
else
|
||||
Fprintf(stdout, "Circuits match correctly.\n");
|
||||
}
|
||||
if (PropertyErrorDetected) {
|
||||
Fprintf(stdout, "There were property errors.\n");
|
||||
@@ -2828,11 +2833,13 @@ _netcmp_equate(ClientData clientData,
|
||||
char *name1 = NULL, *name2 = NULL, *optstart;
|
||||
struct nlist *tp1, *tp2, *SaveC1, *SaveC2;
|
||||
struct objlist *ob1, *ob2;
|
||||
struct ElementClass *saveEclass = NULL;
|
||||
struct NodeClass *saveNclass = NULL;
|
||||
int file1, file2;
|
||||
int i, l1, l2, ltest, lent, dolist = 0;
|
||||
int i, l1, l2, ltest, lent, dolist = 0, doforce = 0;
|
||||
Tcl_Obj *tobj1, *tobj2, *tobj3;
|
||||
|
||||
if (objc > 1) {
|
||||
while (objc > 1) {
|
||||
optstart = Tcl_GetString(objv[1]);
|
||||
if (*optstart == '-') optstart++;
|
||||
if (!strcmp(optstart, "list")) {
|
||||
@@ -2840,6 +2847,13 @@ _netcmp_equate(ClientData clientData,
|
||||
objv++;
|
||||
objc--;
|
||||
}
|
||||
else if (!strcmp(optstart, "force")) {
|
||||
doforce = 1;
|
||||
objv++;
|
||||
objc--;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if ((objc != 2) && (objc != 4) && (objc != 6)) {
|
||||
@@ -2997,6 +3011,12 @@ _netcmp_equate(ClientData clientData,
|
||||
break;
|
||||
|
||||
case PINS_IDX:
|
||||
if ((ElementClasses != NULL) && (doforce == TRUE)) {
|
||||
saveEclass = ElementClasses;
|
||||
saveNclass = NodeClasses;
|
||||
ElementClasses = NULL;
|
||||
NodeClasses = NULL;
|
||||
}
|
||||
if ((ElementClasses == NULL) && (auto_blackbox == FALSE)) {
|
||||
if (CurrentCell == NULL) {
|
||||
Fprintf(stderr, "Equate elements: no current cell.\n");
|
||||
@@ -3059,6 +3079,12 @@ _netcmp_equate(ClientData clientData,
|
||||
/* Recover temporarily set global variables (see above) */
|
||||
Circuit1 = SaveC1;
|
||||
Circuit2 = SaveC2;
|
||||
|
||||
/* Recover ElementClasses if forcing pins on mismatched circuits */
|
||||
if (doforce == TRUE) {
|
||||
ElementClasses = saveEclass;
|
||||
NodeClasses = saveNclass;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3321,10 +3347,10 @@ _netcmp_property(ClientData clientData,
|
||||
int result, index, idx2;
|
||||
|
||||
char *suboptions[] = {
|
||||
"integer", "double", "value", "string", NULL
|
||||
"integer", "double", "value", "string", "expression", NULL
|
||||
};
|
||||
enum SubOptionIdx {
|
||||
INTEGER_IDX, DOUBLE_IDX, VALUE_IDX, STRING_IDX
|
||||
INTEGER_IDX, DOUBLE_IDX, VALUE_IDX, STRING_IDX, EXPRESSION_IDX
|
||||
};
|
||||
|
||||
/* Note: "merge" has been deprecated, but kept for backwards compatibility. */
|
||||
@@ -3418,9 +3444,15 @@ _netcmp_property(ClientData clientData,
|
||||
GlobalParallelNone = FALSE;
|
||||
SetParallelCombine(TRUE);
|
||||
}
|
||||
else if (!strcmp(Tcl_GetString(objv[2]), "connected")) {
|
||||
GlobalParallelOpen = FALSE;
|
||||
}
|
||||
else if (!strcmp(Tcl_GetString(objv[2]), "open")) {
|
||||
GlobalParallelOpen = TRUE;
|
||||
}
|
||||
else {
|
||||
Tcl_SetResult(interp, "Bad option, should be property parallel none|all",
|
||||
NULL);
|
||||
Tcl_SetResult(interp, "Bad option, should be property parallel "
|
||||
"none|all|connected", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
@@ -3707,6 +3739,11 @@ _netcmp_property(ClientData clientData,
|
||||
PropertyString(tp->name, fnum,
|
||||
Tcl_GetString(tobj1), ival, NULL);
|
||||
break;
|
||||
case EXPRESSION_IDX:
|
||||
PropertyString(tp->name, fnum,
|
||||
Tcl_GetString(tobj1), 0,
|
||||
Tcl_GetString(tobj3));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3982,39 +4019,14 @@ _netcmp_permute(ClientData clientData,
|
||||
/* Formerly: x */
|
||||
/* Results: */
|
||||
/* Side Effects: */
|
||||
/* Notes: Deprecated, retained for compatibility. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
int
|
||||
_netcmp_symmetry(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
|
||||
{
|
||||
char *fastfull[] = {
|
||||
"fast", "full", NULL
|
||||
};
|
||||
enum OptionIdx {
|
||||
FAST_IDX, FULL_IDX
|
||||
};
|
||||
int result, index;
|
||||
|
||||
if (objc == 1)
|
||||
index = -1;
|
||||
else {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)fastfull,
|
||||
"option", 0, &index) != TCL_OK)
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
switch(index) {
|
||||
case FAST_IDX:
|
||||
FastSymmetryBreaking = TRUE;
|
||||
break;
|
||||
case FULL_IDX:
|
||||
FastSymmetryBreaking = FALSE;
|
||||
break;
|
||||
}
|
||||
Printf("Symmetry breaking method: %s.\n",
|
||||
FastSymmetryBreaking ? "FAST" : "FULL");
|
||||
|
||||
Printf("Symmetry breaking method has been deprecated.\n");
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user