mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-24 23:17:28 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb798d6ce7 | ||
|
|
a21ba820e9 | ||
|
|
792c5e569a | ||
|
|
f92192efd4 | ||
|
|
1f50c7ccc5 | ||
|
|
8282460774 | ||
|
|
a888502038 | ||
|
|
ea07642172 | ||
|
|
e9da037001 | ||
|
|
7ee50a3f8f | ||
|
|
c16258d4d1 | ||
|
|
c7848c9c02 | ||
|
|
5341d7a5fd | ||
|
|
402e1f0f25 | ||
|
|
8395df633c | ||
|
|
19471275df | ||
|
|
e75f5661e2 | ||
|
|
6554063df3 | ||
|
|
a034fc16d6 | ||
|
|
62fbd422e2 | ||
|
|
4416a380b3 | ||
|
|
d0bae6aff4 | ||
|
|
8a7bb7f2ca | ||
|
|
46394b2000 | ||
|
|
0df6c83df5 | ||
|
|
8996fe03dc | ||
|
|
3fe3bc4cfa | ||
|
|
f3cebd9099 | ||
|
|
6661910672 | ||
|
|
920c6e6928 | ||
|
|
e7a36630f6 | ||
|
|
69780aa048 | ||
|
|
f32b0b34a3 | ||
|
|
2a0ebfde93 | ||
|
|
6e9e6abe98 | ||
|
|
6b731ddd7a | ||
|
|
b9769b9f55 | ||
|
|
7e42483986 | ||
|
|
97b0d08e4f | ||
|
|
99e35d8b11 | ||
|
|
d2c356f9e2 | ||
|
|
5e99fd5ef9 | ||
|
|
65b542f0ab | ||
|
|
04dd4a64d5 | ||
|
|
b826870be9 | ||
|
|
50b0e9cb65 | ||
|
|
ed5276d67b | ||
|
|
82be18ec4b | ||
|
|
4ee3a1464b | ||
|
|
69c9d85be7 | ||
|
|
8e215d3b66 | ||
|
|
c45d51e950 | ||
|
|
ad05d059c7 | ||
|
|
85eb34c01e | ||
|
|
8a24c6c3ca | ||
|
|
46cdf48bc4 | ||
|
|
9d542b92b0 |
@@ -12,3 +12,5 @@ scripts/config.status
|
||||
*~
|
||||
*.log
|
||||
UPDATE_ME
|
||||
tcltk/netgen.sh
|
||||
tcltk/netgen.tcl
|
||||
|
||||
+119
-47
@@ -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 */
|
||||
@@ -253,7 +255,7 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
{
|
||||
struct objlist *ParentParams;
|
||||
struct objlist *ParentProps;
|
||||
struct objlist *NextObj;
|
||||
struct objlist *NextObj, *LastObj, *prepp;
|
||||
struct objlist *ChildObjList;
|
||||
struct nlist *ThisCell;
|
||||
struct nlist *ChildCell;
|
||||
@@ -296,21 +298,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) {
|
||||
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 &&
|
||||
@@ -373,10 +389,10 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
* 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;
|
||||
@@ -456,17 +472,19 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/* Do property inheritance */
|
||||
@@ -497,10 +515,21 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
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);
|
||||
/* find ParentParams in ThisCell list. In most cases, LastObj */
|
||||
/* should be pointing to it. */
|
||||
if (LastObj && (LastObj->next == ParentParams)) {
|
||||
ob2 = LastObj;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (ob2)
|
||||
for (ob2->next = ChildObjList; ob2->next != NULL; ob2 = ob2->next) ;
|
||||
for (ob2->next = ChildObjList; ob2->next != NULL; ob2 = ob2->next) ;
|
||||
}
|
||||
/* now, ob2 is last element in child list, so skip and reclaim parent */
|
||||
|
||||
@@ -1136,9 +1165,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 +1216,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 +1264,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 */
|
||||
}
|
||||
|
||||
@@ -1660,7 +1723,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
while (ecomp != NULL) {
|
||||
if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) &&
|
||||
((ecomp->cell1->class == CLASS_RES) ||
|
||||
(ecomp->cell1->class == CLASS_VSOURCE))) {
|
||||
(ecomp->cell1->class == CLASS_VSOURCE) ||
|
||||
(ecomp->cell1->class == CLASS_ISOURCE))) {
|
||||
int node1 = -1, node2 = -1;
|
||||
lob = NULL;
|
||||
for (ob1 = tc1->cell; ob1; ) {
|
||||
@@ -1709,11 +1773,16 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
tsub1->name,
|
||||
tc1->name);
|
||||
|
||||
/* merge node of endpoints */
|
||||
for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
|
||||
if (ob2->node == node2)
|
||||
ob2->node = node1;
|
||||
}
|
||||
/* A current source is an open, while a */
|
||||
/* resistor or voltage source is a short. */
|
||||
|
||||
if (ecomp->cell1->class != CLASS_ISOURCE) {
|
||||
/* merge node of endpoints */
|
||||
for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
|
||||
if (ob2->node == node2)
|
||||
ob2->node = node1;
|
||||
}
|
||||
}
|
||||
|
||||
/* snip, snip. Excise this device */
|
||||
if (lob == NULL) {
|
||||
@@ -1765,7 +1834,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
|
||||
if ((ecomp->num1 != ecomp->num2) && (ecomp->cell2 != NULL) &&
|
||||
((ecomp->cell2->class == CLASS_RES) ||
|
||||
(ecomp->cell2->class == CLASS_VSOURCE))) {
|
||||
(ecomp->cell2->class == CLASS_VSOURCE) ||
|
||||
(ecomp->cell2->class == CLASS_ISOURCE))) {
|
||||
int node1 = -1, node2 = -1;
|
||||
lob = NULL;
|
||||
for (ob2 = tc2->cell; ob2; ) {
|
||||
@@ -1815,9 +1885,11 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
tc2->name);
|
||||
|
||||
/* merge node of endpoints */
|
||||
for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
|
||||
if (ob1->node == node2)
|
||||
ob1->node = node1;
|
||||
if (ecomp->cell2->class != CLASS_ISOURCE) {
|
||||
for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
|
||||
if (ob1->node == node2)
|
||||
ob1->node = node1;
|
||||
}
|
||||
}
|
||||
|
||||
/* snip, snip. Excise this device */
|
||||
|
||||
+155
-76
@@ -5246,6 +5246,12 @@ void DumpNetworkAll(char *model, int file)
|
||||
/* NOTE: ob1 must belong to Circuit1, and ob2 must belong to */
|
||||
/* Circuit2. The calling procedure is responsble for ensuring */
|
||||
/* that this is true. */
|
||||
/* */
|
||||
/* NOTE: This routine assumes that if file1 == file2 or if */
|
||||
/* file2 != Circuit1->graph, then "do_print" is FALSE. It */
|
||||
/* hard-codes "Circuit 1" and "Circuit 2" in most print */
|
||||
/* statements. file1 == file2 only when checking properties */
|
||||
/* for symmetry breaking, where nothing is printed. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
@@ -5253,8 +5259,9 @@ Tcl_Obj *
|
||||
#else
|
||||
void
|
||||
#endif
|
||||
PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
int do_list, int *retval)
|
||||
PropertyMatch(struct objlist *ob1, int file1,
|
||||
struct objlist *ob2, int file2,
|
||||
int do_print, int do_list, int *retval)
|
||||
{
|
||||
struct nlist *tc1, *tc2;
|
||||
struct objlist *tp1, *tp2, *obn1, *obn2;
|
||||
@@ -5268,8 +5275,22 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
Tcl_Obj *proplist = NULL, *mpair, *mlist;
|
||||
#endif
|
||||
|
||||
tc1 = LookupCellFile(ob1->model.class, Circuit1->file);
|
||||
tc2 = LookupCellFile(ob2->model.class, Circuit2->file);
|
||||
tc1 = LookupCellFile(ob1->model.class, file1);
|
||||
tc2 = LookupCellFile(ob2->model.class, file2);
|
||||
|
||||
if (tc1 == NULL || tc2 == NULL) {
|
||||
if (tc1 == NULL)
|
||||
Fprintf(stdout, "Error: Circuit %d device \"%s\" not found!\n",
|
||||
file1, ob1->model.class);
|
||||
else
|
||||
Fprintf(stdout, "Error: Circuit %d device \"%s\" not found!\n",
|
||||
file2, ob2->model.class);
|
||||
#ifdef TCL_NETGEN
|
||||
return NULL;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (tc1->classhash != tc2->classhash) {
|
||||
*retval = -1;
|
||||
@@ -5339,6 +5360,32 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
#endif
|
||||
}
|
||||
|
||||
/* WIP---Check for no-connect pins in merged devices on both sides. */
|
||||
/* Both sides should either have no-connects marked, or neither. */
|
||||
/* (Permutable pins may need to be handled correctly. . . */
|
||||
for (tp1 = ob1, tp2 = ob2; (tp1 != NULL) && tp1->type >= FIRSTPIN &&
|
||||
(tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next)
|
||||
{
|
||||
struct objlist *node1, *node2;
|
||||
|
||||
node1 = Circuit1->nodename_cache[tp1->node];
|
||||
node2 = Circuit2->nodename_cache[tp2->node];
|
||||
|
||||
if (node1->instance.flags != node2->instance.flags)
|
||||
{
|
||||
Fprintf(stdout, " Parallelized instances disagree on pin connections.\n");
|
||||
Fprintf(stdout, " Circuit1 instance %s pin %s connections are %s (%d)\n",
|
||||
tp1->instance.name, node1->name,
|
||||
(node1->instance.flags == 0) ? "tied together" : "no connects",
|
||||
node1->instance.flags);
|
||||
Fprintf(stdout, " Circuit2 instance %s pin %s connections are %s (%d)\n",
|
||||
tp2->instance.name, node2->name,
|
||||
(node2->instance.flags == 0) ? "tied together" : "no connects",
|
||||
node2->instance.flags);
|
||||
mismatches++;
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to organize devices by series and parallel combination
|
||||
if (t1type == PROPERTY && t2type == PROPERTY)
|
||||
PropertySortAndCombine(obn1, tc1, obn2, tc2);
|
||||
@@ -5550,9 +5597,11 @@ PropertyCheck(struct ElementClass *EC, int do_print, int do_list, int *rval)
|
||||
E2 = Etmp;
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
return PropertyMatch(E1->object, E2->object, do_print, do_list, rval);
|
||||
return PropertyMatch(E1->object, E1->graph, E2->object, E2->graph,
|
||||
do_print, do_list, rval);
|
||||
#else
|
||||
PropertyMatch(E1->object, E2->object, do_print, do_list, rval);
|
||||
PropertyMatch(E1->object, E1->graph, E2->object, E2->graph,
|
||||
do_print, do_list, rval);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5791,10 +5840,8 @@ int ResolveAutomorphsByProperty()
|
||||
badmatch = FALSE;
|
||||
for (E2 = E1->next; E2 != NULL; E2 = E2->next) {
|
||||
if (E2->hashval != orighash) continue;
|
||||
if (E1->graph == Circuit1->file)
|
||||
PropertyMatch(E1->object, E2->object, FALSE, FALSE, &result);
|
||||
else
|
||||
PropertyMatch(E2->object, E1->object, FALSE, FALSE, &result);
|
||||
PropertyMatch(E1->object, E1->graph, E2->object, E2->graph,
|
||||
FALSE, FALSE, &result);
|
||||
if (result == 0) {
|
||||
E2->hashval = newhash;
|
||||
if (E2->graph == E1->graph)
|
||||
@@ -5843,7 +5890,10 @@ int ResolveAutomorphsByProperty()
|
||||
*
|
||||
* ResolveAutormorphisms --
|
||||
*
|
||||
* Arbitrarily equivalence one pair of elements within an automorphic class
|
||||
* Do symmetry breaking of automorphisms.
|
||||
*
|
||||
* Arbitrarily equivalence all pairs of elements and nodes within all
|
||||
* automorphic classes, and run to completion.
|
||||
*
|
||||
* Return value is the same as VerifyMatching()
|
||||
*
|
||||
@@ -5853,8 +5903,8 @@ int ResolveAutomorphsByProperty()
|
||||
int ResolveAutomorphisms()
|
||||
{
|
||||
struct ElementClass *EC;
|
||||
struct NodeClass *NC;
|
||||
struct Element *E;
|
||||
struct NodeClass *NC;
|
||||
struct Node *N;
|
||||
int C1, C2;
|
||||
|
||||
@@ -5874,23 +5924,9 @@ int ResolveAutomorphisms()
|
||||
}
|
||||
if (C1 == C2 && C1 != 1) {
|
||||
unsigned long newhash;
|
||||
|
||||
/* Do all of them at once. */
|
||||
/* NOTE: If this were to fail for some reason, it would */
|
||||
/* probably be necessary to do this the original slow way */
|
||||
/* which is to rehash one pair at a time and iterate to */
|
||||
/* convergence, and repeat. */
|
||||
|
||||
E1 = E2 = EC->elements;
|
||||
while (E1 != NULL) {
|
||||
while (E1->graph != Circuit1->file) E1 = E1->next;
|
||||
while (E2->graph != Circuit2->file) E2 = E2->next;
|
||||
Magic(newhash);
|
||||
E1->hashval = newhash;
|
||||
E2->hashval = newhash;
|
||||
E1 = E1->next;
|
||||
E2 = E2->next;
|
||||
}
|
||||
Magic(newhash);
|
||||
E1->hashval = newhash;
|
||||
E2->hashval = newhash;
|
||||
goto converge;
|
||||
}
|
||||
}
|
||||
@@ -5911,32 +5947,18 @@ int ResolveAutomorphisms()
|
||||
}
|
||||
if (C1 == C2 && C1 != 1) {
|
||||
unsigned long newhash;
|
||||
|
||||
/* Do all of them at once */
|
||||
/* NOTE: If this were to fail for some reason, it would */
|
||||
/* probably be necessary to do this the original slow way */
|
||||
/* which is to rehash one pair at a time and iterate to */
|
||||
/* convergence, and repeat. */
|
||||
|
||||
N1 = N2 = NC->nodes;
|
||||
while (N1 != NULL) {
|
||||
while (N1->graph != Circuit1->file) N1 = N1->next;
|
||||
while (N2->graph != Circuit2->file) N2 = N2->next;
|
||||
Magic(newhash);
|
||||
N1->hashval = newhash;
|
||||
N2->hashval = newhash;
|
||||
N1 = N1->next;
|
||||
N2 = N2->next;
|
||||
}
|
||||
Magic(newhash);
|
||||
N1->hashval = newhash;
|
||||
N2->hashval = newhash;
|
||||
goto converge;
|
||||
}
|
||||
}
|
||||
|
||||
converge:
|
||||
FractureElementClass(&ElementClasses);
|
||||
FractureNodeClass(&NodeClasses);
|
||||
FractureElementClass(&ElementClasses);
|
||||
FractureNodeClass(&NodeClasses);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && VerifyMatching() != -1);
|
||||
while (!Iterate() && VerifyMatching() != -1);
|
||||
return(VerifyMatching());
|
||||
}
|
||||
|
||||
@@ -6553,24 +6575,45 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
|
||||
firstpin = ob;
|
||||
while (tob && (tob->type == PORT || tob->type == UNKNOWN)) {
|
||||
if (tob->type == UNKNOWN) {
|
||||
obn = (struct objlist *)CALLOC(1, sizeof(struct objlist));
|
||||
obn->name = (char *)MALLOC(strlen(firstpin->instance.name)
|
||||
+ strlen(tob->name) + 2);
|
||||
sprintf(obn->name, "%s/%s", firstpin->instance.name, tob->name);
|
||||
obn->instance.name = strsave(firstpin->instance.name);
|
||||
obn->model.class = strsave(tc->name);
|
||||
obn->type = i++;
|
||||
obn->node = numnodes++;
|
||||
obn->next = ob; // Splice into object list
|
||||
lob->next = obn;
|
||||
lob = obn;
|
||||
/* Do not do anything with (no pins) entries (in the reference cell) */
|
||||
if (strcmp(tob->name, "proxy(no pins)")) {
|
||||
/* But if the target cell instance has proxy(no pins), then reuse
|
||||
* the record and modify it.
|
||||
*/
|
||||
if (!strcmp(ob->name, "proxy(no pins)")) {
|
||||
obn = ob;
|
||||
FREE(ob->name);
|
||||
obn->name = (char *)MALLOC(strlen(ob->instance.name)
|
||||
+ strlen(tob->name) + 2);
|
||||
sprintf(obn->name, "%s/%s", ob->instance.name, tob->name);
|
||||
ob = obn->next;
|
||||
}
|
||||
else {
|
||||
obn = (struct objlist *)CALLOC(1, sizeof(struct objlist));
|
||||
obn->name = (char *)MALLOC(strlen(firstpin->instance.name)
|
||||
+ strlen(tob->name) + 2);
|
||||
sprintf(obn->name, "%s/%s", firstpin->instance.name, tob->name);
|
||||
obn->instance.name = strsave(firstpin->instance.name);
|
||||
obn->model.class = strsave(tc->name);
|
||||
obn->next = ob; // Splice into object list
|
||||
lob->next = obn;
|
||||
}
|
||||
obn->type = i++;
|
||||
obn->node = numnodes++;
|
||||
lob = obn;
|
||||
|
||||
// Hash the new pin record for "LookupObject()"
|
||||
HashPtrInstall(obn->name, obn, &(ptr->objdict));
|
||||
// Hash the new pin record for "LookupObject()"
|
||||
HashPtrInstall(obn->name, obn, &(ptr->objdict));
|
||||
|
||||
if (tob == tc->cell) {
|
||||
// Rehash the instance in instdict
|
||||
HashPtrInstall(firstpin->instance.name, firstpin, &(ptr->instdict));
|
||||
if (tob == tc->cell) {
|
||||
// Rehash the instance in instdict
|
||||
HashPtrInstall(firstpin->instance.name, firstpin, &(ptr->instdict));
|
||||
}
|
||||
}
|
||||
else {
|
||||
lob = ob;
|
||||
ob->type = i++;
|
||||
ob = ob->next;
|
||||
}
|
||||
}
|
||||
else if (ob == NULL) {
|
||||
@@ -6644,7 +6687,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
struct NodeClass *NC;
|
||||
struct Node *N1, *N2;
|
||||
int i, j, k, m, a, b, swapped, numnodes, numorig;
|
||||
int result = 1, haspins = 0;
|
||||
int result = 1, haspins = 0, notempty = 0;
|
||||
int hasproxy1 = 0, hasproxy2 = 0;
|
||||
int needclean1 = 0, needclean2 = 0;
|
||||
char *ostr;
|
||||
@@ -6809,12 +6852,15 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
/* has been left orphaned after flattening. If */
|
||||
/* disconnected, set its node number to -2. */
|
||||
|
||||
notempty = 0;
|
||||
for (obt = ob1->next; obt; obt = obt->next) {
|
||||
if (obt->type >= FIRSTPIN)
|
||||
if (obt->type >= FIRSTPIN) {
|
||||
notempty = 1;
|
||||
if (obt->node == ob1->node)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (obt == NULL) {
|
||||
if ((obt == NULL) && (notempty == 1)) {
|
||||
ob1->node = -2; // Will run this through cleanuppins
|
||||
needclean1 = 1;
|
||||
}
|
||||
@@ -6867,6 +6913,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (*(cover + i) == (char)0) {
|
||||
j = 0;
|
||||
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
|
||||
char *name1, *name2;
|
||||
|
||||
if (!IsPort(ob2)) break;
|
||||
|
||||
bangptr2 = strrchr(ob2->name, '!');
|
||||
@@ -6874,7 +6922,14 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
*bangptr2 = '\0';
|
||||
else bangptr2 = NULL;
|
||||
|
||||
if ((*matchfunc)(ob1->name, ob2->name)) {
|
||||
name1 = ob1->name;
|
||||
name2 = ob2->name;
|
||||
|
||||
/* Recognize proxy pins as matching */
|
||||
if (!strncmp(name1, "proxy", 5)) name1 +=5;
|
||||
if (!strncmp(name2, "proxy", 5)) name2 +=5;
|
||||
|
||||
if ((*matchfunc)(name1, name2)) {
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
@@ -6913,7 +6968,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
/* Find the end of the pin list in tc1, for adding proxy pins */
|
||||
|
||||
for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next) {
|
||||
if (ob1 && ob1->next && ob1->next->type != PORT)
|
||||
if (ob1 && ((ob1->next && ob1->next->type != PORT) || ob1->next == NULL))
|
||||
break;
|
||||
}
|
||||
if (ob1 == NULL) ob1 = tc1->cell; /* No ports */
|
||||
@@ -6956,12 +7011,15 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
/* flattening instances has left a port with a */
|
||||
/* net number that doesn't connect to anything */
|
||||
|
||||
notempty = 0;
|
||||
for (obt = ob2->next; obt; obt = obt->next) {
|
||||
if (obt->type >= FIRSTPIN)
|
||||
if (obt->type >= FIRSTPIN) {
|
||||
notempty = 1;
|
||||
if (obt->node == ob2->node)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (obt == NULL) {
|
||||
if ((obt == NULL) && (notempty == 1)) {
|
||||
ob2->node = -2; // Will run this through cleanuppins
|
||||
needclean2 = 1;
|
||||
continue;
|
||||
@@ -6978,7 +7036,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
obn->name = (char *)MALLOC(6 + strlen(ob2->name));
|
||||
sprintf(obn->name, "proxy%s", ob2->name);
|
||||
obn->type = UNKNOWN;
|
||||
obn->model.port = -1;
|
||||
// obn->model.port = -1;
|
||||
obn->instance.name = NULL;
|
||||
obn->node = -1;
|
||||
if (ob1 == tc1->cell) {
|
||||
@@ -6999,7 +7057,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
/* Find the end of the pin list in tc2, for adding proxy pins */
|
||||
|
||||
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
|
||||
if (ob2 && ob2->next && ob2->next->type != PORT)
|
||||
if (ob2 && ((ob2->next && ob2->next->type != PORT) || ob2->next == NULL))
|
||||
break;
|
||||
}
|
||||
if (ob2 == NULL) ob2 = tc2->cell; /* No ports */
|
||||
@@ -7030,7 +7088,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (obn == NULL) ob1->node = -1; /* Make disconnected */
|
||||
}
|
||||
|
||||
if (ob1 == NULL || ob1->type != PORT || ob1->node >= 0) {
|
||||
if (ob1 == NULL || ob1->type != PORT || ob1->node >= 0
|
||||
|| (ob1->node < 0 && tc1->class == CLASS_MODULE)) {
|
||||
|
||||
/* Add a proxy pin to tc2 */
|
||||
obn = (struct objlist *)CALLOC(1, sizeof(struct objlist));
|
||||
@@ -7047,6 +7106,25 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
obn->instance.name = NULL;
|
||||
obn->node = -1;
|
||||
|
||||
#if 0
|
||||
/* Note: This pin has already been accounted for */
|
||||
if (Debug == 0) {
|
||||
if (strcmp(ob1->name, "(no pins)")) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
snprintf(ostr, left_col_end, "%s", ob1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
|
||||
tc1->name, ob1->name);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ob2 == tc2->cell) {
|
||||
obn->next = ob2;
|
||||
tc2->cell = obn;
|
||||
@@ -7350,7 +7428,8 @@ static void handler(int sig)
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Note that this cover-all routine is not called from the Tcl/Tk */
|
||||
/* version, which replaces it with the script "lvs". */
|
||||
/* return 1 if the two are identical. Try to resolve automorphisms. */
|
||||
/* return 1 if the two are identical. Try to resolve automorphisms */
|
||||
/* using the original "full" symmetry breaking algorithm. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int Compare(char *cell1, char *cell2)
|
||||
|
||||
+48
-9
@@ -1337,7 +1337,7 @@ void Node(char *name)
|
||||
tp->name = strsave(name);
|
||||
tp->type = NODE; /* internal node type */
|
||||
tp->model.class = NULL;
|
||||
tp->instance.name = NULL;
|
||||
tp->instance.flags = 0;
|
||||
tp->node = -1; /* null node */
|
||||
tp->next = NULL;
|
||||
AddToCurrentCell (tp);
|
||||
@@ -2470,7 +2470,8 @@ void CopyProperties(struct objlist *obj_to, struct objlist *obj_from)
|
||||
kvcur->value.ival = 0;
|
||||
|
||||
obj_to->instance.props = kvcopy;
|
||||
obj_to->model.class = strsave(obj_from->model.class);
|
||||
if (obj_from->model.class)
|
||||
obj_to->model.class = strsave(obj_from->model.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3131,6 +3132,9 @@ int remove_group_tags(struct objlist *ob)
|
||||
/* If the device has permutable pins, then duplicate hashes are made */
|
||||
/* for each permutation. */
|
||||
/* */
|
||||
/* If the device has isolated (unconnected) pins, then treat them as */
|
||||
/* all belonging to the same net for the purpose of parallel merging. */
|
||||
/* */
|
||||
/* Return the number of devices merged. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
@@ -3145,6 +3149,7 @@ int CombineParallel(char *model, int file)
|
||||
size_t pcnt;
|
||||
int i, dcnt = 0, hastag;
|
||||
char *pstr, *p2str, *pptr;
|
||||
int *nodecount;
|
||||
struct valuelist *kv;
|
||||
|
||||
if ((tp = LookupCellFile(model, file)) == NULL) {
|
||||
@@ -3154,6 +3159,17 @@ int CombineParallel(char *model, int file)
|
||||
|
||||
InitializeHashTable(&devdict, OBJHASHSIZE);
|
||||
|
||||
/* Make one pass to count the number of times each node number is */
|
||||
/* used. This list indicates which pins are no-connects, so they */
|
||||
/* can be treated as equivalent for the purpose of parallelization. */
|
||||
|
||||
nodecount = (int *)CALLOC((tp->nodename_cache_maxnodenum + 1), sizeof(int));
|
||||
for (ob = tp->cell; ob; ob = ob->next) {
|
||||
if (ob->node >= 0)
|
||||
if (ob->type != NODE)
|
||||
nodecount[ob->node]++;
|
||||
}
|
||||
|
||||
lob = NULL;
|
||||
for (ob = tp->cell; ob; ) {
|
||||
if (ob->type == FIRSTPIN) {
|
||||
@@ -3200,7 +3216,14 @@ int CombineParallel(char *model, int file)
|
||||
pptr += pstr - (char *)2;
|
||||
|
||||
for (ob2 = ob; ob2 && (ob2->type > FIRSTPIN || ob2 == ob); ob2 = ob2->next) {
|
||||
sprintf(pptr, "_%d", ob2->node);
|
||||
if ((ob2->node >= 0) && (nodecount[ob2->node] == 1))
|
||||
{
|
||||
nob = (tp->nodename_cache)[ob2->node];
|
||||
nob->instance.flags = NO_CONNECT;
|
||||
strcat(pptr, "_nc");
|
||||
}
|
||||
else
|
||||
sprintf(pptr, "_%d", ob2->node);
|
||||
pptr += strlen(pptr);
|
||||
}
|
||||
|
||||
@@ -3236,11 +3259,26 @@ int CombineParallel(char *model, int file)
|
||||
for (ob2 = ob; ob2 && (ob2->type > FIRSTPIN || ob2 == ob);
|
||||
ob2 = ob2->next) {
|
||||
if (ob2 == pob1)
|
||||
sprintf(pptr, "_%d", pob2->node);
|
||||
{
|
||||
if ((pob2->node >= 0) && (nodecount[pob2->node] == 1))
|
||||
strcat(pptr, "_nc");
|
||||
else
|
||||
sprintf(pptr, "_%d", pob2->node);
|
||||
}
|
||||
else if (ob2 == pob2)
|
||||
sprintf(pptr, "_%d", pob1->node);
|
||||
{
|
||||
if ((pob1->node >= 0) && (nodecount[pob1->node] == 1))
|
||||
strcat(pptr, "_nc");
|
||||
else
|
||||
sprintf(pptr, "_%d", pob1->node);
|
||||
}
|
||||
else
|
||||
sprintf(pptr, "_%d", ob2->node);
|
||||
{
|
||||
if ((ob2->node >= 0) && (nodecount[ob2->node] == 1))
|
||||
strcat(pptr, "_nc");
|
||||
else
|
||||
sprintf(pptr, "_%d", ob2->node);
|
||||
}
|
||||
pptr += strlen(pptr);
|
||||
}
|
||||
HashPtrInstall(p2str, ob, &devdict);
|
||||
@@ -3256,7 +3294,7 @@ int CombineParallel(char *model, int file)
|
||||
else {
|
||||
/* Find parallel device "ob" and append properties of */
|
||||
/* "sob" to it. If "ob" does not have properties, then */
|
||||
/* create a property record and set property "M" to 2. */
|
||||
/* create a property record and set property "M" to 1. */
|
||||
|
||||
/* Find last non-property record of sob ( = pob) */
|
||||
/* Find first property record of sob ( = spropfirst) */
|
||||
@@ -3364,6 +3402,7 @@ int CombineParallel(char *model, int file)
|
||||
if (dcnt > 0) {
|
||||
Fprintf(stdout, "Class %s: Merged %d devices.\n", model, dcnt);
|
||||
}
|
||||
FREE(nodecount);
|
||||
return dcnt;
|
||||
}
|
||||
|
||||
@@ -3583,8 +3622,8 @@ int CombineSeries(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->next->type == PROPERTY; obp = obp->next);
|
||||
for (obp = instlist[i][0]; obp->next && (obp->next->type > FIRSTPIN ||
|
||||
obp->next->type == PROPERTY); obp = obp->next);
|
||||
for (ob2 = obp; ob2 && ob2->next != instlist[i][1]; ob2 = ob2->next);
|
||||
|
||||
/* Device may have been moved by the above code. If so, look for */
|
||||
|
||||
@@ -65,6 +65,15 @@ extern void AssignCircuits(char *name1, int file1, char *name2, int file2);
|
||||
/* flatten.c */
|
||||
extern int PrematchLists(char *, int, char *, int);
|
||||
|
||||
/* verilog.c */
|
||||
struct cellstack {
|
||||
char *cellname;
|
||||
struct cellstack *next;
|
||||
};
|
||||
|
||||
void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
int blackbox);
|
||||
|
||||
/* Define (enumerate) various device classes, largely based on SPICE */
|
||||
/* model types, mixed with some ext/sim types. */
|
||||
|
||||
|
||||
+13
-6
@@ -289,7 +289,7 @@ static struct hashdict cell_dict;
|
||||
void InitCellHashTable(void)
|
||||
{
|
||||
hashfunc = hash;
|
||||
matchfunc = match;
|
||||
matchfunc = NULL;
|
||||
matchintfunc = matchfile;
|
||||
InitializeHashTable(&cell_dict, CELLHASHSIZE);
|
||||
}
|
||||
@@ -975,7 +975,10 @@ struct objlist *CopyObjList(struct objlist *oldlist, unsigned char doforall)
|
||||
newob->model.class = NULL;
|
||||
else
|
||||
newob->model.class = strsave(tmp->model.class);
|
||||
newob->instance.name = (tmp->instance.name) ?
|
||||
if (newob->type == NODE)
|
||||
newob->instance.flags = tmp->instance.flags;
|
||||
else
|
||||
newob->instance.name = (tmp->instance.name) ?
|
||||
strsave(tmp->instance.name) : NULL;
|
||||
}
|
||||
newob->node = tmp->node;
|
||||
@@ -1095,8 +1098,8 @@ void FreeObject(struct objlist *ob)
|
||||
FREE(ob->instance.props);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* All other records */
|
||||
else if (ob->type != NODE) {
|
||||
/* All other records except NODE, which uses this for flags */
|
||||
if (ob->instance.name != NULL) FreeString(ob->instance.name);
|
||||
}
|
||||
if (ob->model.class != NULL) FreeString(ob->model.class);
|
||||
@@ -1112,13 +1115,17 @@ void FreeObjectAndHash(struct objlist *ob, struct nlist *ptr)
|
||||
|
||||
/*************** GENERAL UTILITIES ****************************/
|
||||
|
||||
int NumberOfPorts(char *cellname)
|
||||
int NumberOfPorts(char *cellname, int file)
|
||||
{
|
||||
struct nlist *tp;
|
||||
struct objlist *ob;
|
||||
int ports;
|
||||
|
||||
tp = LookupCell(cellname);
|
||||
if (file == -1)
|
||||
tp = LookupCell(cellname);
|
||||
else
|
||||
tp = LookupCellFile(cellname, file);
|
||||
|
||||
if (tp == NULL) return(0);
|
||||
ports = 0;
|
||||
for (ob = tp->cell; ob != NULL; ob = ob->next)
|
||||
|
||||
+5
-3
@@ -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. */
|
||||
@@ -160,6 +162,7 @@ struct objlist {
|
||||
union {
|
||||
char *name; /* unique name for the instance, or */
|
||||
/* (string) value of property for properties */
|
||||
int flags; /* Used by NODE type to flag isolated net */
|
||||
struct valuelist *props; /* Property record */
|
||||
} instance;
|
||||
int node; /* the electrical node number of the port/node/pin */
|
||||
@@ -192,9 +195,8 @@ struct Permutation {
|
||||
struct Permutation *next;
|
||||
};
|
||||
|
||||
#define OBJHASHSIZE 997 /* the size of the object and instance hash lists */
|
||||
#define OBJHASHSIZE 42073 /* the size of the object and instance hash lists */
|
||||
/* prime numbers are good choices as hash sizes */
|
||||
/* 101 is a good number for IBMPC */
|
||||
|
||||
/* cell definition for hash table */
|
||||
/* NOTE: "file" must come first for the hash matching by name and file */
|
||||
@@ -242,7 +244,7 @@ extern void FreeObjectAndHash(struct objlist *ob, struct nlist *ptr);
|
||||
extern void FreePorts(char *cellname);
|
||||
extern struct IgnoreList *ClassIgnore;
|
||||
|
||||
extern int NumberOfPorts(char *cellname);
|
||||
extern int NumberOfPorts(char *cellname, int file);
|
||||
extern struct objlist *InstanceNumber(struct nlist *tp, int inst);
|
||||
|
||||
extern struct objlist *List(char *list_template);
|
||||
|
||||
+1
-1
@@ -929,7 +929,7 @@ void ToggleDebug(void)
|
||||
void DescribeCell(char *name, int detail)
|
||||
{
|
||||
Printf("Cell: %s contains %d instances, %d nodes and %d ports\n", name,
|
||||
NumberOfInstances(name), RenumberNodes(name), NumberOfPorts(name));
|
||||
NumberOfInstances(name), RenumberNodes(name), NumberOfPorts(name, -1));
|
||||
PrintEmbeddingTree(stdout,name,detail);
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -801,7 +801,11 @@ void DescribeInstance(char *name, int file)
|
||||
{
|
||||
if (ob->node > nodemax) nodemax = ob->node;
|
||||
else if ((ob->node == -1) && (ob->model.port != PROXY)) {
|
||||
if (!(tp->flags & CELL_PLACEHOLDER))
|
||||
|
||||
/* All black-box modules and placeholders by definition have all */
|
||||
/* disconnected pins, so don't report those. */
|
||||
|
||||
if (!(tp->flags & CELL_PLACEHOLDER) && (tp->class != CLASS_MODULE))
|
||||
{
|
||||
if (disconnectednodes == 0) Fprintf(stderr, "\n");
|
||||
disconnectednodes++;
|
||||
@@ -903,7 +907,7 @@ void PrintLeavesInCell(char *cellname, int filenum)
|
||||
np->dumped = 1;
|
||||
|
||||
if (np->class != CLASS_SUBCKT) {
|
||||
Printf("%s; %d ports; Primitive.\n", cellname, NumberOfPorts(cellname));
|
||||
Printf("%s; %d ports; Primitive.\n", cellname, NumberOfPorts(cellname, filenum));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -916,7 +920,7 @@ void PrintLeavesInCell(char *cellname, int filenum)
|
||||
am_a_leaf = 0;
|
||||
}
|
||||
|
||||
if (am_a_leaf) Printf("%s; %d ports\n", cellname, NumberOfPorts(cellname));
|
||||
if (am_a_leaf) Printf("%s; %d ports\n", cellname, NumberOfPorts(cellname, filenum));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+25
-14
@@ -473,15 +473,6 @@ void CleanupSubcell() {
|
||||
SetClass(CLASS_MODULE);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Structure for stacking nested subcircuit definitions */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
struct cellstack {
|
||||
char *cellname;
|
||||
struct cellstack *next;
|
||||
};
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Push a subcircuit name onto the stack */
|
||||
/*------------------------------------------------------*/
|
||||
@@ -874,6 +865,17 @@ skip_ends:
|
||||
}
|
||||
}
|
||||
|
||||
/* Ignore anything in a .CONTROL ... .ENDC block */
|
||||
else if (matchnocase(nexttok, ".CONTROL")) {
|
||||
while (1) {
|
||||
SpiceSkipNewLine();
|
||||
SkipTok(NULL);
|
||||
if (EndParseFile()) break;
|
||||
if (matchnocase(nexttok, ".ENDC"))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Blackbox (library) mode---parse only subcircuits and models;
|
||||
// ignore all components.
|
||||
|
||||
@@ -1184,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;
|
||||
@@ -1900,10 +1902,19 @@ char *ReadSpiceTop(char *fname, int *fnum, int blackbox)
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure all SPICE file reading is case insensitive */
|
||||
matchfunc = matchnocase;
|
||||
matchintfunc = matchfilenocase;
|
||||
hashfunc = hashnocase;
|
||||
/* Make sure all SPICE file reading is case insensitive */
|
||||
/* BUT if a verilog file was read before it, then it will */
|
||||
/* be forced to be case sensitive, caveat end-user. */
|
||||
|
||||
if (matchfunc == match) {
|
||||
Printf("Warning: A case-sensitive file has been read and so the "
|
||||
"SPICE netlist must be treated case-sensitive to match.\n");
|
||||
}
|
||||
else {
|
||||
matchfunc = matchnocase;
|
||||
matchintfunc = matchfilenocase;
|
||||
hashfunc = hashnocase;
|
||||
}
|
||||
|
||||
InitializeHashTable(&spiceparams, OBJHASHSIZE);
|
||||
|
||||
|
||||
+59
-10
@@ -553,9 +553,43 @@ void CleanupModule() {
|
||||
int maxnode = 0;
|
||||
int has_submodules = FALSE;
|
||||
struct objlist *sobj, *nobj, *lobj, *pobj;
|
||||
struct objlist *myLastPort, *object_it, *myNextObject;
|
||||
|
||||
if (CurrentCell == NULL) return;
|
||||
|
||||
myLastPort = NULL;
|
||||
|
||||
/* Reorder objects so that all ports come first, before nodes, because
|
||||
* parts of the code depend on it.
|
||||
*/
|
||||
|
||||
for (object_it = CurrentCell->cell; object_it && object_it->type <= 0;
|
||||
object_it = myNextObject ) {
|
||||
|
||||
myNextObject = object_it->next;
|
||||
if (!myNextObject) // end of list
|
||||
continue;
|
||||
|
||||
if (myLastPort == NULL) {
|
||||
if (object_it->type == PORT) {
|
||||
myLastPort = object_it; // port at begining of list
|
||||
myNextObject = object_it; // otherwise skips one
|
||||
}
|
||||
else if (myNextObject->type == PORT) {
|
||||
object_it->next = myNextObject->next;
|
||||
myNextObject->next = CurrentCell->cell;
|
||||
CurrentCell->cell = myNextObject;
|
||||
myLastPort = myNextObject;
|
||||
}
|
||||
}
|
||||
else if (myNextObject->type == PORT) {
|
||||
object_it->next = myNextObject->next;
|
||||
myNextObject->next = myLastPort->next;
|
||||
myLastPort->next = myNextObject;
|
||||
myLastPort = myNextObject;
|
||||
}
|
||||
}
|
||||
|
||||
for (sobj = CurrentCell->cell; sobj; sobj = sobj->next)
|
||||
if (sobj->node > maxnode)
|
||||
maxnode = sobj->node + 1;
|
||||
@@ -598,11 +632,6 @@ void CleanupModule() {
|
||||
/* Structure for stacking nested module definitions */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
struct cellstack {
|
||||
char *cellname;
|
||||
struct cellstack *next;
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
extern void IncludeVerilog(char *, int, struct cellstack **, int);
|
||||
|
||||
@@ -1225,7 +1254,12 @@ skip_endmodule:
|
||||
lhs = LookupObject(nodename, CurrentCell);
|
||||
*aptr = '[';
|
||||
}
|
||||
else strcpy(noderoot, nexttok);
|
||||
else {
|
||||
strcpy(noderoot, nexttok);
|
||||
/* Set LHS to the start of the vector */
|
||||
sprintf(nodename, "%s[%d]", nexttok, wb.start);
|
||||
lhs = LookupObject(nodename, CurrentCell);
|
||||
}
|
||||
}
|
||||
else {
|
||||
lhs = LookupObject(nexttok, CurrentCell);
|
||||
@@ -1290,13 +1324,21 @@ skip_endmodule:
|
||||
if (rhs != NULL) {
|
||||
Printf("Improper assignment; left-hand side cannot "
|
||||
"be parsed.\n");
|
||||
Printf("Right-hand side is \"%s\".\n", rhs->name);
|
||||
if (j != -1)
|
||||
Printf("Right-hand side is \"%s\".\n", assignroot);
|
||||
else
|
||||
Printf("Right-hand side is \"%s\".\n", rhs->name);
|
||||
Printf("Improper expression is \"%s\".\n", nexttok);
|
||||
break;
|
||||
}
|
||||
if (lhs != NULL) {
|
||||
Printf("Improper assignment; right-hand side cannot "
|
||||
"be parsed.\n");
|
||||
Printf("Left-hand side is \"%s\".\n", lhs->name);
|
||||
if (i != -1)
|
||||
Printf("Left-hand side is \"%s\".\n", noderoot);
|
||||
else
|
||||
Printf("Left-hand side is \"%s\".\n", lhs->name);
|
||||
Printf("Improper expression is \"%s\".\n", nexttok);
|
||||
/* Not parsable, probably behavioral verilog? */
|
||||
Printf("Module '%s' is not structural verilog, "
|
||||
"making black-box.\n", model);
|
||||
@@ -1854,7 +1896,7 @@ nextinst:
|
||||
if (is_bundle &&
|
||||
((i == -1) ||
|
||||
((wbb.start > wbb.end) && (i < wbb.end)) ||
|
||||
((wbb.start < wbb.end) && (i > wbb.end)))) {
|
||||
((wbb.start <= wbb.end) && (i > wbb.end)))) {
|
||||
if (bptr) *bptr = '[';
|
||||
|
||||
netname = cptr + 1;
|
||||
@@ -1933,7 +1975,9 @@ nextinst:
|
||||
sprintf(localnet, "_noconnect_%d_", localcount++);
|
||||
Node(localnet);
|
||||
join(localnet, obptr->name);
|
||||
Fprintf(stderr, "Note: Implicit pin %s\n", obpinname);
|
||||
Fprintf(stderr,
|
||||
"Note: Implicit pin %s in instance %s of %s in cell %s\n",
|
||||
obpinname, locinst, modulename, CurrentCell->name);
|
||||
}
|
||||
else if (GetBus(scan->net, &wb) == 0) {
|
||||
char *bptr2;
|
||||
@@ -2094,6 +2138,11 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
|
||||
Printf("Warning: A case-insensitive file has been read and so the "
|
||||
"verilog file must be treated case-insensitive to match.\n");
|
||||
}
|
||||
else {
|
||||
matchfunc = match;
|
||||
matchintfunc = matchfile;
|
||||
hashfunc = hash;
|
||||
}
|
||||
|
||||
InitializeHashTable(&verilogparams, OBJHASHSIZE);
|
||||
InitializeHashTable(&verilogdefs, OBJHASHSIZE);
|
||||
|
||||
@@ -4,4 +4,6 @@
|
||||
# all of its config scripts in a different directory than the configure
|
||||
# script itself.
|
||||
|
||||
( CFLAGS="-g" ; export CFLAGS ; cd scripts ; ./configure "$@" )
|
||||
export CFLAGS="$CFLAGS -g"
|
||||
cd scripts
|
||||
exec ./configure "$@"
|
||||
|
||||
+7
-1
@@ -501,6 +501,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
return
|
||||
}
|
||||
set properr {}
|
||||
set pinsgood 0
|
||||
while {$endval != {}} {
|
||||
if {$dolist == 1} {
|
||||
netgen::run -list converge
|
||||
@@ -546,6 +547,7 @@ 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
|
||||
netgen::log echo on
|
||||
}
|
||||
if {$uresult == 2} {lappend properr [lindex $endval 0]}
|
||||
@@ -569,7 +571,11 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
netgen::log echo off
|
||||
puts stdout "Result: " nonewline
|
||||
netgen::log echo on
|
||||
verify only
|
||||
if {$pinsgood == 0} {
|
||||
netgen::log put "The top level cell failed pin matching.\n"
|
||||
} else {
|
||||
verify only
|
||||
}
|
||||
if {$properr != {}} {
|
||||
netgen::log put "The following cells had property errors: $properr\n"
|
||||
}
|
||||
|
||||
+61
-6
@@ -94,6 +94,7 @@ int _netcmp_ignore(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
|
||||
int _netcmp_permute(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
|
||||
int _netcmp_property(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
|
||||
int _netcmp_exhaustive(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
|
||||
int _netcmp_symmetry(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
|
||||
int _netcmp_restart(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
|
||||
int _netcmp_global(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
|
||||
int _netcmp_convert(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
|
||||
@@ -244,6 +245,8 @@ Command netcmp_cmds[] = {
|
||||
{"exhaustive", _netcmp_exhaustive,
|
||||
"\n "
|
||||
"toggle exhaustive subdivision"},
|
||||
{"symmetry", _netcmp_symmetry,
|
||||
"(deprecated)"},
|
||||
{"restart", _netcmp_restart,
|
||||
"\n "
|
||||
"start over (reset data structures)"},
|
||||
@@ -1532,23 +1535,24 @@ int
|
||||
_netgen_model(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
|
||||
{
|
||||
struct nlist *tp;
|
||||
struct nlist *tp, *tp2;
|
||||
char *model, *retclass;
|
||||
unsigned char class;
|
||||
int fnum = -1;
|
||||
int result, index, nports;
|
||||
int result, index, nports, nports2;
|
||||
|
||||
char *modelclasses[] = {
|
||||
"undefined", "nmos", "pmos", "pnp", "npn",
|
||||
"resistor", "capacitor", "diode",
|
||||
"inductor", "module", "blackbox", "xline",
|
||||
"moscap", "mosfet", "bjt", "subcircuit", NULL
|
||||
"moscap", "mosfet", "bjt", "subcircuit", "copy",
|
||||
NULL
|
||||
};
|
||||
enum OptionIdx {
|
||||
UNDEF_IDX, NMOS_IDX, PMOS_IDX, PNP_IDX, NPN_IDX,
|
||||
RES_IDX, CAP_IDX, DIODE_IDX, INDUCT_IDX,
|
||||
MODULE_IDX, BLACKBOX_IDX, XLINE_IDX, MOSCAP_IDX,
|
||||
MOSFET_IDX, BJT_IDX, SUBCKT_IDX
|
||||
MOSFET_IDX, BJT_IDX, SUBCKT_IDX, COPY_IDX
|
||||
};
|
||||
|
||||
if (objc != 3 && objc != 2) {
|
||||
@@ -1580,7 +1584,7 @@ _netgen_model(ClientData clientData,
|
||||
|
||||
if (objc == 3) {
|
||||
model = Tcl_GetString(objv[2]);
|
||||
nports = NumberOfPorts(model);
|
||||
nports = NumberOfPorts(model, fnum);
|
||||
|
||||
if (Tcl_GetIndexFromObj(interp, objv[2], (CONST84 char **)modelclasses,
|
||||
"class", 0, &index) != TCL_OK) {
|
||||
@@ -1644,6 +1648,40 @@ _netgen_model(ClientData clientData,
|
||||
break;
|
||||
case SUBCKT_IDX:
|
||||
class = CLASS_SUBCKT;
|
||||
break;
|
||||
case COPY_IDX:
|
||||
/* "copy" is not a class, but indicates that the cell, */
|
||||
/* if undefined or a module, should have its class */
|
||||
/* taken from the other circuit, if that circuit has a */
|
||||
/* cell of the same name. */
|
||||
if (Circuit1 == NULL || Circuit2 == NULL) {
|
||||
Tcl_SetResult(interp, "Circuits have not been queued for comparison.",
|
||||
NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (tp == Circuit1) {
|
||||
tp2 = LookupCellFile(tp->name, Circuit2->file);
|
||||
nports2 = NumberOfPorts(tp2->name, Circuit2->file);
|
||||
}
|
||||
else if (tp == Circuit2) {
|
||||
tp2 = LookupCellFile(tp->name, Circuit1->file);
|
||||
nports2 = NumberOfPorts(tp2->name, Circuit1->file);
|
||||
}
|
||||
else {
|
||||
Tcl_SetResult(interp, "The referenced netlist is not being compared.",
|
||||
NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
/* Should a non-matching number of ports be considered a fatal error? */
|
||||
// if (nports2 != nports) {
|
||||
// Tcl_SetResult(interp, "The number of ports for this cell does not "
|
||||
// "match between netlists.", NULL);
|
||||
// return TCL_ERROR;
|
||||
// }
|
||||
|
||||
class = tp2->class;
|
||||
/* To do (maybe): Rename tp ports to match tp2? */
|
||||
|
||||
break;
|
||||
}
|
||||
tp->class = class;
|
||||
@@ -3937,6 +3975,23 @@ _netcmp_permute(ClientData clientData,
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Function name: _netcmp_symmetry */
|
||||
/* Syntax: netgen::symmetry [fast|full] */
|
||||
/* Formerly: x */
|
||||
/* Results: */
|
||||
/* Side Effects: */
|
||||
/* Notes: Deprecated, retained for compatibility. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
int
|
||||
_netcmp_symmetry(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
|
||||
{
|
||||
Printf("Symmetry breaking method has been deprecated.\n");
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Function name: _netcmp_exhaustive */
|
||||
/* Syntax: netgen::exhaustive [on|off] */
|
||||
@@ -3958,7 +4013,7 @@ _netcmp_exhaustive(ClientData clientData,
|
||||
int result, index;
|
||||
|
||||
if (objc == 1)
|
||||
index = YES_IDX;
|
||||
index = -1;
|
||||
else {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)yesno,
|
||||
"option", 0, &index) != TCL_OK)
|
||||
|
||||
Reference in New Issue
Block a user