mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 14:07:07 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
8395df633c | ||
|
|
19471275df | ||
|
|
e75f5661e2 |
@@ -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) && (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 &&
|
||||
@@ -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 */
|
||||
|
||||
+493
-268
@@ -158,9 +158,6 @@ int right_col_end = 87;
|
||||
/* if TRUE, always partition ALL classes */
|
||||
int ExhaustiveSubdivision = 0;
|
||||
|
||||
/* if TRUE, use fast symmetry breaking to resolve automorphisms */
|
||||
int FastSymmetryBreaking = 1;
|
||||
|
||||
#ifdef TEST
|
||||
static void PrintElement_List(struct Element *E)
|
||||
{
|
||||
@@ -1144,6 +1141,323 @@ Tcl_Obj *ListElementClasses(int legal)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------
|
||||
*
|
||||
* Sort the fanout lists of two formatted list entries so that they
|
||||
* are as well aligned as they can be made, practically. The matching
|
||||
* is ad hoc as it does not affect LVS results but only how the results
|
||||
* are organized and presented in the output.
|
||||
*
|
||||
*---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
SortFanoutLists(nlist1, nlist2)
|
||||
struct FormattedList *nlist1, *nlist2;
|
||||
{
|
||||
struct hashdict f1hash, f2hash;
|
||||
int f1, f2, total;
|
||||
struct FanoutList temp;
|
||||
int *matched;
|
||||
char pinname[1024], pinnameA[1024], pinnameB[1024];
|
||||
|
||||
InitializeHashTable(&f1hash, OBJHASHSIZE);
|
||||
InitializeHashTable(&f2hash, OBJHASHSIZE);
|
||||
|
||||
if (nlist1->fanout < nlist2->fanout) {
|
||||
matched = (int *)CALLOC(nlist2->fanout, sizeof(int));
|
||||
total = 0;
|
||||
|
||||
for (f2 = 0; f2 < nlist2->fanout; f2++) {
|
||||
sprintf(pinname, "%s/%s", nlist2->flist[f2].model,
|
||||
nlist2->flist[f2].name);
|
||||
HashPtrInstall(pinname, (void *)((long)f2 + 1), &f2hash);
|
||||
}
|
||||
|
||||
for (f1 = 0; f1 < nlist1->fanout; f1++) {
|
||||
sprintf(pinname, "%s/%s", nlist1->flist[f1].model,
|
||||
nlist1->flist[f1].name);
|
||||
f2 = (int)(long)HashLookup(pinname, &f2hash);
|
||||
if (f2 != 0) {
|
||||
f2 -= 1;
|
||||
matched[f1] = -1;
|
||||
total++;
|
||||
if (f2 != f1) {
|
||||
temp = nlist2->flist[f2];
|
||||
nlist2->flist[f2] = nlist2->flist[f1];
|
||||
nlist2->flist[f1] = temp;
|
||||
sprintf(pinnameA, "%s/%s", nlist2->flist[f1].model,
|
||||
nlist2->flist[f1].name);
|
||||
sprintf(pinnameB, "%s/%s", nlist2->flist[f2].model,
|
||||
nlist2->flist[f2].name);
|
||||
HashPtrInstall(pinnameA, (void *)((long)f1 + 1), &f2hash);
|
||||
HashPtrInstall(pinnameB, (void *)((long)f2 + 1), &f2hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* To do: If full pin names don't match, match by model name only */
|
||||
}
|
||||
else {
|
||||
matched = (int *)CALLOC(nlist1->fanout, sizeof(int));
|
||||
total = 0;
|
||||
|
||||
for (f1 = 0; f1 < nlist1->fanout; f1++) {
|
||||
sprintf(pinname, "%s/%s", nlist1->flist[f1].model,
|
||||
nlist1->flist[f1].name);
|
||||
HashPtrInstall(pinname, (void *)((long)f1 + 1), &f1hash);
|
||||
}
|
||||
|
||||
for (f2 = 0; f2 < nlist2->fanout; f2++) {
|
||||
sprintf(pinname, "%s/%s", nlist2->flist[f2].model,
|
||||
nlist2->flist[f2].name);
|
||||
f1 = (int)(long)HashLookup(pinname, &f1hash);
|
||||
if (f1 != 0) {
|
||||
f1 -= 1;
|
||||
matched[f2] = -1;
|
||||
total++;
|
||||
if (f1 != f2) {
|
||||
temp = nlist1->flist[f1];
|
||||
nlist1->flist[f1] = nlist1->flist[f2];
|
||||
nlist1->flist[f2] = temp;
|
||||
sprintf(pinnameA, "%s/%s", nlist1->flist[f1].model,
|
||||
nlist1->flist[f1].name);
|
||||
sprintf(pinnameB, "%s/%s", nlist1->flist[f2].model,
|
||||
nlist1->flist[f2].name);
|
||||
HashPtrInstall(pinnameA, (void *)((long)f1 + 1), &f1hash);
|
||||
HashPtrInstall(pinnameB, (void *)((long)f2 + 1), &f1hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* To do: If full pin names don't match, match by model name only */
|
||||
}
|
||||
|
||||
FREE(matched);
|
||||
HashKill(&f1hash);
|
||||
HashKill(&f2hash);
|
||||
}
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------
|
||||
*
|
||||
* Determine the match between two entries in a bad node fragment
|
||||
* according to an ad hoc metric of how many fanout entries are
|
||||
* the same between the two. This is not used to match circuits
|
||||
* for LVS, but is used to sort the dump of unmatched nets generated
|
||||
* for an unmatched subcell, so that the end-user is not presented
|
||||
* with a list in a confusingly arbitrary order.
|
||||
*
|
||||
* Score is normalized to 100.
|
||||
* If a model/pin has an equivalent on the other size, add 1
|
||||
* If a model/pin equivalent has the same count, add 1
|
||||
* Total values and normalize to a 100 score for an exact match.
|
||||
*
|
||||
*---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
NodeMatchScore(nlist1, nlist2)
|
||||
struct FormattedList *nlist1, *nlist2;
|
||||
{
|
||||
struct hashdict f1hash, f2hash;
|
||||
char pinname[1024];
|
||||
int f1, f2, maxfanout;
|
||||
int score = 0;
|
||||
|
||||
InitializeHashTable(&f1hash, OBJHASHSIZE);
|
||||
InitializeHashTable(&f2hash, OBJHASHSIZE);
|
||||
|
||||
if (nlist1->fanout < nlist2->fanout) {
|
||||
for (f2 = 0; f2 < nlist2->fanout; f2++) {
|
||||
sprintf(pinname, "%s/%s", nlist2->flist[f2].model,
|
||||
nlist2->flist[f2].name);
|
||||
HashPtrInstall(pinname, (void *)((long)f2 + 1), &f2hash);
|
||||
}
|
||||
|
||||
for (f1 = 0; f1 < nlist1->fanout; f1++) {
|
||||
sprintf(pinname, "%s/%s", nlist1->flist[f1].model,
|
||||
nlist1->flist[f1].name);
|
||||
f2 = (int)(long)HashLookup(pinname, &f2hash);
|
||||
if (f2 != 0) {
|
||||
f2 -= 1;
|
||||
score++;
|
||||
if (nlist1->flist[f1].count == nlist2->flist[f2].count)
|
||||
score++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (f1 = 0; f1 < nlist1->fanout; f1++) {
|
||||
sprintf(pinname, "%s/%s", nlist1->flist[f1].model,
|
||||
nlist1->flist[f1].name);
|
||||
HashPtrInstall(pinname, (void *)((long)f1 + 1), &f1hash);
|
||||
}
|
||||
|
||||
for (f2 = 0; f2 < nlist2->fanout; f2++) {
|
||||
sprintf(pinname, "%s/%s", nlist2->flist[f2].model,
|
||||
nlist2->flist[f2].name);
|
||||
f1 = (int)(long)HashLookup(pinname, &f1hash);
|
||||
if (f1 != 0) {
|
||||
f1 -= 1;
|
||||
score++;
|
||||
if (nlist2->flist[f2].count == nlist1->flist[f1].count)
|
||||
score++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HashKill(&f1hash);
|
||||
HashKill(&f2hash);
|
||||
|
||||
maxfanout = (nlist1->fanout < nlist2->fanout) ? nlist2->fanout : nlist1->fanout;
|
||||
score = (50 * score) / maxfanout;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------
|
||||
*
|
||||
* Sort node list 2 to match the entries in list 1, to the extent
|
||||
* possible. Exact name matching is preferred, followed by matching
|
||||
* of the largest percentage of components.
|
||||
*
|
||||
*---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void SortUnmatchedLists(nlists1, nlists2, n1max, n2max)
|
||||
struct FormattedList **nlists1, **nlists2;
|
||||
int n1max, n2max;
|
||||
{
|
||||
struct FormattedList *temp;
|
||||
int n1, n2;
|
||||
int *matched, total, best, ibest;
|
||||
|
||||
struct hashdict n1hash, n2hash;
|
||||
|
||||
InitializeHashTable(&n1hash, OBJHASHSIZE);
|
||||
InitializeHashTable(&n2hash, OBJHASHSIZE);
|
||||
|
||||
if (n1max < n2max) {
|
||||
matched = (int *)CALLOC(n2max, sizeof(int));
|
||||
total = 0;
|
||||
|
||||
for (n2 = 0; n2 < n2max; n2++)
|
||||
HashPtrInstall(nlists2[n2]->name, (void *)((long)n2 + 1), &n2hash);
|
||||
|
||||
/* Match by name */
|
||||
for (n1 = 0; n1 < n1max; n1++) {
|
||||
n2 = (int)(long)HashLookup(nlists1[n1]->name, &n2hash);
|
||||
if (n2 != 0) {
|
||||
n2 -= 1;
|
||||
matched[n1] = -1;
|
||||
total++;
|
||||
if (n2 != n1) {
|
||||
temp = nlists2[n2];
|
||||
nlists2[n2] = nlists2[n1];
|
||||
nlists2[n1] = temp;
|
||||
HashPtrInstall(nlists2[n1]->name, (void *)((long)n1 + 1), &n2hash);
|
||||
HashPtrInstall(nlists2[n2]->name, (void *)((long)n2 + 1), &n2hash);
|
||||
SortFanoutLists(nlists1[n1], nlists2[n1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* For all nets that didn't match by name, match by content */
|
||||
#if 0
|
||||
/* This is ifdef'd out because the improvement in the presentation
|
||||
* of the output is minimal, but the amount of computation is huge.
|
||||
* There are numerous ways to optimize this.
|
||||
*/
|
||||
if (total < n1max) {
|
||||
for (n1 = 0; n1 < n1max; n1++) {
|
||||
if (matched[n1] != -1) {
|
||||
best = 0;
|
||||
ibest = -1;
|
||||
for (n2 = 0; n2 < n2max; n2++) {
|
||||
if (matched[n2] != -1) {
|
||||
matched[n2] = NodeMatchScore(nlists1[n1], nlists2[n2]);
|
||||
if (matched[n2] > best) {
|
||||
best = matched[n2];
|
||||
ibest = n2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ibest >= 0) {
|
||||
matched[n1] = -1;
|
||||
temp = nlists2[ibest];
|
||||
nlists2[ibest] = nlists2[n1];
|
||||
nlists2[n1] = temp;
|
||||
SortFanoutLists(nlists1[n1], nlists2[n1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
matched = (int *)CALLOC(n1max, sizeof(int));
|
||||
total = 0;
|
||||
|
||||
for (n1 = 0; n1 < n1max; n1++)
|
||||
HashPtrInstall(nlists1[n1]->name, (void *)((long)n1 + 1), &n1hash);
|
||||
|
||||
for (n2 = 0; n2 < n2max; n2++) {
|
||||
n1 = (int)(long)HashLookup(nlists2[n2]->name, &n1hash);
|
||||
if (n1 != 0) {
|
||||
n1 -= 1;
|
||||
matched[n2] = -1;
|
||||
total++;
|
||||
if (n1 != n2) {
|
||||
temp = nlists1[n1];
|
||||
nlists1[n1] = nlists1[n2];
|
||||
nlists1[n2] = temp;
|
||||
HashPtrInstall(nlists1[n1]->name, (void *)((long)n1 + 1), &n1hash);
|
||||
HashPtrInstall(nlists1[n2]->name, (void *)((long)n2 + 1), &n1hash);
|
||||
SortFanoutLists(nlists2[n2], nlists1[n2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* For all nets that didn't match by name, match by content */
|
||||
#if 0
|
||||
/* This is ifdef'd out because the improvement in the presentation
|
||||
* of the output is minimal, but the amount of computation is huge.
|
||||
* There are numerous ways to optimize this.
|
||||
*/
|
||||
if (total < n2max) {
|
||||
for (n2 = 0; n2 < n2max; n2++) {
|
||||
if (matched[n2] != -1) {
|
||||
best = 0;
|
||||
ibest = -1;
|
||||
for (n1 = 0; n1 < n1max; n1++) {
|
||||
if (matched[n1] != -1) {
|
||||
matched[n1] = NodeMatchScore(nlists2[n2], nlists1[n1]);
|
||||
if (matched[n1] > best) {
|
||||
best = matched[n1];
|
||||
ibest = n1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ibest >= 0) {
|
||||
matched[n2] = -1;
|
||||
temp = nlists1[ibest];
|
||||
nlists1[ibest] = nlists1[n2];
|
||||
nlists1[n2] = temp;
|
||||
SortFanoutLists(nlists2[n2], nlists1[n2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
FREE(matched);
|
||||
HashKill(&n1hash);
|
||||
HashKill(&n2hash);
|
||||
}
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------
|
||||
*---------------------------------------------------------------------
|
||||
@@ -1222,8 +1536,9 @@ void FormatIllegalElementClasses()
|
||||
n2++;
|
||||
}
|
||||
}
|
||||
Fprintf(stdout, "\n");
|
||||
SortUnmatchedLists(elist1, elist2, n1, n2);
|
||||
|
||||
Fprintf(stdout, "\n");
|
||||
for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) {
|
||||
if (n != 0) {
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
@@ -1525,6 +1840,12 @@ void FormatIllegalNodeClasses()
|
||||
ostr = CALLOC(right_col_end + 2, sizeof(char));
|
||||
found = 0;
|
||||
|
||||
/*
|
||||
* To do: match net names across partitions, to make it much clearer how
|
||||
* two nets are mismatched, when they have been dropped into different
|
||||
* partitions.
|
||||
*/
|
||||
|
||||
for (nscan = NodeClasses; nscan != NULL; nscan = nscan->next)
|
||||
if (!(nscan->legalpartition)) {
|
||||
struct Node *N;
|
||||
@@ -1577,8 +1898,9 @@ void FormatIllegalNodeClasses()
|
||||
n2++;
|
||||
}
|
||||
}
|
||||
Fprintf(stdout, "\n");
|
||||
SortUnmatchedLists(nlists1, nlists2, n1, n2);
|
||||
|
||||
Fprintf(stdout, "\n");
|
||||
for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) {
|
||||
if (n != 0) {
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
@@ -3736,24 +4058,33 @@ int series_optimize(struct objlist *ob1, struct nlist *tp1, int idx1,
|
||||
}
|
||||
|
||||
typedef struct _propsort {
|
||||
double value;
|
||||
double value; /* Primary sorting value */
|
||||
double avalue; /* Secondary sorting value */
|
||||
double slop; /* Delta for accepting equality */
|
||||
int idx;
|
||||
unsigned char flags;
|
||||
struct objlist *ob;
|
||||
} propsort;
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Property sorting routine used by qsort() */
|
||||
/* Property sorting routine used by qsort(). Sorts on "value" */
|
||||
/* unless the "value" for the two entries differs by less than */
|
||||
/* "slop", in which case the entries are sorted on "avalue". */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
static int compsort(const void *p1, const void *p2)
|
||||
{
|
||||
propsort *s1, *s2;
|
||||
double smax;
|
||||
|
||||
s1 = (propsort *)p1;
|
||||
s2 = (propsort *)p2;
|
||||
|
||||
return (s1->value > s2->value) ? 1 : 0;
|
||||
smax = fmax(s1->slop, s2->slop);
|
||||
if (fabs(s1->value - s2->value) <= smax)
|
||||
return (s1->avalue > s2->avalue) ? 1 : 0;
|
||||
else
|
||||
return (s1->value > s2->value) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
@@ -3772,7 +4103,7 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
struct property *kl;
|
||||
struct valuelist *vl, *sl;
|
||||
int i, p, sval, merge_type;
|
||||
double cval;
|
||||
double cval, slop;
|
||||
|
||||
obn = ob1->next;
|
||||
for (i = 0; i < idx1; i++) obn = obn->next;
|
||||
@@ -3785,7 +4116,7 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
|
||||
obp = obn;
|
||||
sval = 1;
|
||||
cval = 0.0;
|
||||
cval = slop = 0.0;
|
||||
for (i = 0; i < run; i++) {
|
||||
merge_type = MERGE_NONE;
|
||||
for (p = 0;; p++) {
|
||||
@@ -3798,23 +4129,37 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
}
|
||||
else {
|
||||
kl = (struct property *)HashLookup(vl->key, &(tp1->propdict));
|
||||
if (kl && (kl->merge & MERGE_S_CRIT)) {
|
||||
if (vl->type == PROP_INTEGER)
|
||||
if (kl && (kl->merge & (MERGE_S_ADD | MERGE_S_PAR))) {
|
||||
if (vl->type == PROP_INTEGER) {
|
||||
cval = (double)vl->value.ival;
|
||||
else
|
||||
slop = (double)kl->slop.ival;
|
||||
}
|
||||
else {
|
||||
cval = vl->value.dval;
|
||||
slop = kl->slop.dval;
|
||||
}
|
||||
merge_type = kl->merge & (MERGE_S_ADD | MERGE_S_PAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (merge_type == MERGE_S_ADD) {
|
||||
proplist[i].value = cval * (double)sval;
|
||||
proplist[i].slop = slop;
|
||||
proplist[i].avalue = 0;
|
||||
sl->value.ival = 1;
|
||||
}
|
||||
else if (merge_type == MERGE_S_PAR) {
|
||||
proplist[i].value = cval / (double)sval;
|
||||
proplist[i].slop = slop;
|
||||
proplist[i].avalue = 0;
|
||||
sl->value.ival = 1;
|
||||
}
|
||||
else {
|
||||
/* Components which declare no series addition method stay unsorted */
|
||||
proplist[i].value = (double)0;
|
||||
proplist[i].avalue = (double)0;
|
||||
proplist[i].slop = (double)1E-6;
|
||||
}
|
||||
proplist[i].idx = i;
|
||||
proplist[i].ob = obp;
|
||||
obp = obp->next;
|
||||
@@ -3911,32 +4256,31 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
struct property *kl;
|
||||
struct valuelist *vl, *ml;
|
||||
int i, p, mval, merge_type, has_crit = FALSE;
|
||||
char *subs_crit = NULL;
|
||||
double cval;
|
||||
char c, *subs_crit = NULL;
|
||||
double cval, tval, aval, slop, tslop;
|
||||
|
||||
obn = ob1->next;
|
||||
for (i = 0; i < idx1; i++) obn = obn->next;
|
||||
|
||||
// Create a structure of length (run) to hold critical property
|
||||
// value and index. Then sort that list, then use the sorted
|
||||
// indexes to sort the actual property linked list.
|
||||
|
||||
// If there is no critical property listed, then it is still better
|
||||
// to sort on any random property than on no properties. Note that
|
||||
// this can (and should!) be made better by sorting on *all*
|
||||
// properties, not just the first. Otherwise, circuit 1 can have, e.g.,
|
||||
// parallel transistors with W=1, L=1 and W=1, L=2 while circuit two
|
||||
// has W=1, L=2 and W=1, L=1 and property matching will fail because
|
||||
// sorting was done on W only.
|
||||
/* Create a structure of length (run) to hold critical property
|
||||
* value and index. Then sort that list, then use the sorted
|
||||
* indexes to sort the actual property linked list.
|
||||
*
|
||||
* If there is no critical property listed, then it will sort on
|
||||
* M first, and any additive property second, or any property at
|
||||
* all if no additive property was found. It is doubtful that any
|
||||
* use case requires more than two properties for sorting.
|
||||
*/
|
||||
|
||||
proplist = (propsort *)MALLOC(run * sizeof(propsort));
|
||||
|
||||
obp = obn;
|
||||
mval = 1;
|
||||
cval = 0.0;
|
||||
cval = aval = slop = 0.0;
|
||||
for (i = 0; i < run; i++) {
|
||||
merge_type = MERGE_NONE;
|
||||
ml = NULL;
|
||||
c = (char)0;
|
||||
for (p = 0;; p++) {
|
||||
vl = &(obp->instance.props[p]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
@@ -3947,82 +4291,77 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
}
|
||||
kl = (struct property *)HashLookup(vl->key, &(tp1->propdict));
|
||||
if (kl == NULL) continue; /* Ignored property */
|
||||
if (kl->merge & MERGE_P_CRIT) {
|
||||
if (kl->merge & MERGE_P_CRIT)
|
||||
has_crit = TRUE;
|
||||
else if (kl->merge & (MERGE_P_ADD | MERGE_P_PAR)) {
|
||||
if ((vl->type == PROP_STRING || vl->type == PROP_EXPRESSION) &&
|
||||
(kl->type != vl->type))
|
||||
PromoteProperty(kl, vl);
|
||||
if (vl->type == PROP_INTEGER)
|
||||
cval = (double)vl->value.ival;
|
||||
else if (vl->type == PROP_STRING)
|
||||
PromoteProperty(kl, vl, obp, tp1);
|
||||
if (vl->type == PROP_INTEGER) {
|
||||
tval = (double)vl->value.ival;
|
||||
tslop = (double)kl->slop.ival;
|
||||
}
|
||||
else if (vl->type == PROP_STRING) {
|
||||
/* This is unlikely---no method to merge string properties! */
|
||||
cval = (double)vl->value.string[0]
|
||||
tval = (double)vl->value.string[0]
|
||||
+ (double)vl->value.string[1] / 10.0;
|
||||
else
|
||||
cval = vl->value.dval;
|
||||
merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR);
|
||||
tslop = (double)0;
|
||||
}
|
||||
else {
|
||||
tval = vl->value.dval;
|
||||
tslop = kl->slop.dval;
|
||||
}
|
||||
|
||||
if (merge_type == MERGE_NONE)
|
||||
{
|
||||
merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR);
|
||||
cval = tval;
|
||||
slop = tslop;
|
||||
}
|
||||
else {
|
||||
if ((c == (char)0) || (toupper(vl->key[0]) > c)) {
|
||||
c = toupper(vl->key[0]);
|
||||
aval = tval;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((c == (char)0) || (toupper(vl->key[0]) > c)) {
|
||||
if (vl->type == PROP_INTEGER) {
|
||||
aval = (double)vl->value.ival;
|
||||
c = toupper(vl->key[0]);
|
||||
}
|
||||
else if (vl->type == PROP_DOUBLE) {
|
||||
aval = vl->value.dval;
|
||||
c = toupper(vl->key[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (merge_type == MERGE_P_ADD) {
|
||||
proplist[i].value = cval * (double)mval;
|
||||
proplist[i].avalue = aval;
|
||||
proplist[i].slop = tslop;
|
||||
if (ml) ml->value.ival = 1;
|
||||
}
|
||||
else if (merge_type == MERGE_P_PAR) {
|
||||
proplist[i].value = cval / (double)mval;
|
||||
proplist[i].avalue = aval;
|
||||
proplist[i].slop = tslop;
|
||||
if (ml) ml->value.ival = 1;
|
||||
}
|
||||
else {
|
||||
/* If there are no additive values, then sort first by M */
|
||||
/* and second by aval */
|
||||
proplist[i].value = (double)mval;
|
||||
proplist[i].avalue = aval;
|
||||
proplist[i].slop = (double)0;
|
||||
}
|
||||
proplist[i].idx = i;
|
||||
proplist[i].ob = obp;
|
||||
obp = obp->next;
|
||||
}
|
||||
|
||||
if (has_crit == FALSE) {
|
||||
/* If no critical property was specified, then choose the first one found */
|
||||
/* and recalculate all the proplist values. */
|
||||
mval = 1;
|
||||
obp = obn;
|
||||
ml = NULL;
|
||||
merge_type = MERGE_NONE;
|
||||
for (i = 0; i < run; i++) {
|
||||
for (p = 0;; p++) {
|
||||
vl = &(obp->instance.props[p]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
if (vl->key == NULL) continue;
|
||||
if ((*matchfunc)(vl->key, "M")) {
|
||||
mval = vl->value.ival;
|
||||
ml = vl;
|
||||
}
|
||||
kl = (struct property *)HashLookup(vl->key, &(tp1->propdict));
|
||||
if (kl == NULL) continue; /* Ignored property */
|
||||
if (subs_crit == NULL)
|
||||
subs_crit = vl->key;
|
||||
if ((subs_crit != NULL) && (*matchfunc)(vl->key, subs_crit)) {
|
||||
if ((vl->type == PROP_STRING || vl->type == PROP_EXPRESSION) &&
|
||||
(kl->type != vl->type))
|
||||
PromoteProperty(kl, vl);
|
||||
if (vl->type == PROP_INTEGER)
|
||||
cval = (double)vl->value.ival;
|
||||
else if (vl->type == PROP_STRING)
|
||||
/* In case property is non-numeric, sort by dictionary order */
|
||||
cval = (double)vl->value.string[0]
|
||||
+ (double)vl->value.string[1] / 10.0;
|
||||
else
|
||||
cval = vl->value.dval;
|
||||
merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR);
|
||||
}
|
||||
}
|
||||
if (merge_type == MERGE_P_ADD) {
|
||||
proplist[i].value = cval * (double)mval;
|
||||
if (ml) ml->value.ival = 1;
|
||||
}
|
||||
else if (merge_type == MERGE_P_PAR) {
|
||||
proplist[i].value = cval / (double)mval;
|
||||
if (ml) ml->value.ival = 1;
|
||||
}
|
||||
obp = obp->next;
|
||||
}
|
||||
}
|
||||
|
||||
obn = obp; /* Link from last property */
|
||||
|
||||
qsort(&proplist[0], run, sizeof(propsort), compsort);
|
||||
@@ -4486,12 +4825,12 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
else if (vl == NULL || vl2 == NULL) {
|
||||
if (vl == NULL) {
|
||||
if (kl->type != vlist[p][j]->type)
|
||||
PromoteProperty(kl, vl2);
|
||||
PromoteProperty(kl, vl2, ob2, tp);
|
||||
vl = &dfltvl;
|
||||
}
|
||||
else {
|
||||
if (kl->type != vlist[p][i]->type)
|
||||
PromoteProperty(kl, vl);
|
||||
PromoteProperty(kl, vl, ob2, tp);
|
||||
vl2 = &dfltvl;
|
||||
}
|
||||
dfltvl.type = kl->type;
|
||||
@@ -4513,7 +4852,7 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
}
|
||||
|
||||
// Additive properties do not need to be matched, since
|
||||
// they can be combined. Critical paroperties must be
|
||||
// they can be combined. Critical properties must be
|
||||
// matched. Properties with no merge behavior must match.
|
||||
|
||||
ctype = clist[p][i];
|
||||
@@ -4966,8 +5305,8 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
}
|
||||
|
||||
/* Promote properties as necessary to make sure they all match */
|
||||
if (kl1->type != vl1->type) PromoteProperty(kl1, vl1);
|
||||
if (kl2->type != vl2->type) PromoteProperty(kl2, vl2);
|
||||
if (kl1->type != vl1->type) PromoteProperty(kl1, vl1, tc1, tp1);
|
||||
if (kl2->type != vl2->type) PromoteProperty(kl2, vl2, tc2, tp2);
|
||||
|
||||
/* If kl1 and kl2 types differ, choose one type to target. Prefer */
|
||||
/* double if either type is double, otherwise string. */
|
||||
@@ -4987,8 +5326,8 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
else
|
||||
klt = kl1;
|
||||
|
||||
if (vl2->type != klt->type) PromoteProperty(klt, vl2);
|
||||
if (vl1->type != klt->type) PromoteProperty(klt, vl1);
|
||||
if (vl2->type != klt->type) PromoteProperty(klt, vl2, tc2, tp2);
|
||||
if (vl1->type != klt->type) PromoteProperty(klt, vl1, tc1, tp1);
|
||||
|
||||
if (vl1->type != vl2->type) {
|
||||
if (do_print && (vl1->type != vl2->type)) {
|
||||
@@ -5363,6 +5702,40 @@ PropertyMatch(struct objlist *ob1, int file1,
|
||||
#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;
|
||||
|
||||
if (file1 == Circuit1->file)
|
||||
node1 = Circuit1->nodename_cache[tp1->node];
|
||||
else
|
||||
node1 = Circuit2->nodename_cache[tp1->node];
|
||||
|
||||
if (file2 == Circuit1->file)
|
||||
node2 = Circuit1->nodename_cache[tp2->node];
|
||||
else
|
||||
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);
|
||||
@@ -5840,6 +6213,7 @@ int ResolveAutomorphsByProperty()
|
||||
if ((E2->graph != E1->graph) && (E2->hashval == newhash)) {
|
||||
E2->hashval = orighash;
|
||||
C2--;
|
||||
if (C2 == C1) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5848,6 +6222,7 @@ int ResolveAutomorphsByProperty()
|
||||
if ((E2->graph == E1->graph) && (E2->hashval == newhash)) {
|
||||
E2->hashval = orighash;
|
||||
C1--;
|
||||
if (C1 == C2) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5865,16 +6240,19 @@ int ResolveAutomorphsByProperty()
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResolveAutormorphismsFull --
|
||||
* 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()
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int ResolveAutomorphismsFull()
|
||||
int ResolveAutomorphisms()
|
||||
{
|
||||
struct ElementClass *EC;
|
||||
struct Element *E;
|
||||
@@ -5936,172 +6314,6 @@ int ResolveAutomorphismsFull()
|
||||
return(VerifyMatching());
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResolveElementAutomorphismsFast --
|
||||
*
|
||||
* Apply arbitrary symmetry breaking to symmetric element lists, then
|
||||
* iterate exhaustively to resolve all automorphisms.
|
||||
*
|
||||
* Return value is the same as VerifyMatching()
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int ResolveElementAutomorphismsFast()
|
||||
{
|
||||
struct ElementClass *EC;
|
||||
struct Element *E;
|
||||
int C1, C2;
|
||||
|
||||
for (EC = ElementClasses; EC != NULL; EC = EC->next) {
|
||||
struct Element *E1, *E2;
|
||||
C1 = C2 = 0;
|
||||
E1 = E2 = NULL;
|
||||
for (E = EC->elements; E != NULL; E = E->next) {
|
||||
if (E->graph == Circuit1->file) {
|
||||
C1++;
|
||||
E1 = E;
|
||||
}
|
||||
else {
|
||||
C2++;
|
||||
E2 = E;
|
||||
}
|
||||
}
|
||||
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 && E2 != 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FractureElementClass(&ElementClasses);
|
||||
FractureNodeClass(&NodeClasses);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && VerifyMatching() != -1);
|
||||
return(VerifyMatching());
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResolveNodeAutomorphismsFast --
|
||||
*
|
||||
* Apply arbitrary symmetry breaking to symmetric node lists, then iterate
|
||||
* exhaustively to resolve all automorphisms. Normally, all automorphisms
|
||||
* should be resolved by ResolveElementAutomorphisms(). It is likely true
|
||||
* that this routine will never run, by definition.
|
||||
*
|
||||
* Return value is the same as VerifyMatching()
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
|
||||
int ResolveNodeAutomorphismsFast()
|
||||
{
|
||||
struct Node *N;
|
||||
struct NodeClass *NC;
|
||||
int C1, C2;
|
||||
|
||||
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
|
||||
struct Node *N1, *N2;
|
||||
C1 = C2 = 0;
|
||||
N1 = N2 = NULL;
|
||||
for (N = NC->nodes; N != NULL; N = N->next) {
|
||||
if (N->graph == Circuit1->file) {
|
||||
C1++;
|
||||
N1 = N;
|
||||
}
|
||||
else {
|
||||
C2++;
|
||||
N2 = N;
|
||||
}
|
||||
}
|
||||
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 && N2 != 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FractureElementClass(&ElementClasses);
|
||||
FractureNodeClass(&NodeClasses);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && VerifyMatching() != -1);
|
||||
return(VerifyMatching());
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResolveAutormorphisms --
|
||||
*
|
||||
* Do symmetry breaking of automorphisms. If FastSymmetryBreaking is
|
||||
* False (not the default), then run ResolveAutomorphismsFull() (q.v.).
|
||||
* Otherwise, run the fast symmetry breaking method:
|
||||
*
|
||||
* Arbitrarily equivalence all pairs of elements and nodes within all
|
||||
* automorphic classes, and run to completion. Note that this is a
|
||||
* fast version of ResolveAutomorphismsFull(), and can run many orders
|
||||
* of magnitude faster. However, it can also produce an incorrect
|
||||
* result, declaring a global mismatch where none exists. In that
|
||||
* case, the matching should be re-run with ResolveAutomorphismsFull().
|
||||
*
|
||||
* Some investigation needs to be done to determine if there is a way
|
||||
* to execute faster symmetry breaking without the possibility of
|
||||
* producing an incorrect result.
|
||||
*
|
||||
* Return value is the same as VerifyMatching()
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int ResolveAutomorphisms()
|
||||
{
|
||||
int result;
|
||||
|
||||
if (FastSymmetryBreaking == 0)
|
||||
return ResolveAutomorphismsFull();
|
||||
|
||||
result = ResolveElementAutomorphismsFast();
|
||||
if (result != 0)
|
||||
result = ResolveNodeAutomorphismsFast();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* PermuteSetup -- */
|
||||
/* Add an entry to a cell's "permutes" linked list. */
|
||||
@@ -6715,18 +6927,31 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
|
||||
firstpin = ob;
|
||||
while (tob && (tob->type == PORT || tob->type == UNKNOWN)) {
|
||||
if (tob->type == UNKNOWN) {
|
||||
/* ??? Do not do anything with (no pins) entries */
|
||||
/* Do not do anything with (no pins) entries (in the reference cell) */
|
||||
if (strcmp(tob->name, "proxy(no pins)")) {
|
||||
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);
|
||||
/* But if the target cell instance has proxy(no pins), then reuse
|
||||
* the record and modify it.
|
||||
*/
|
||||
if (ob && !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++;
|
||||
obn->next = ob; // Splice into object list
|
||||
lob->next = obn;
|
||||
lob = obn;
|
||||
|
||||
// Hash the new pin record for "LookupObject()"
|
||||
|
||||
@@ -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;
|
||||
|
||||
+611
-530
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??? */
|
||||
|
||||
+6
-3
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+12
-1
@@ -865,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.
|
||||
|
||||
@@ -1175,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;
|
||||
|
||||
+89
-14
@@ -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,6 +531,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
return
|
||||
}
|
||||
set properr {}
|
||||
set matcherr {}
|
||||
set pinsgood 0
|
||||
while {$endval != {}} {
|
||||
if {$dolist == 1} {
|
||||
@@ -532,9 +560,30 @@ 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
|
||||
@@ -557,9 +606,32 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
} 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
|
||||
@@ -582,6 +654,9 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
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
|
||||
}
|
||||
|
||||
+49
-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)"},
|
||||
@@ -2458,8 +2457,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 +2465,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 +2829,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 +2843,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 +3007,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 +3075,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 +3343,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 +3440,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 +3735,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 +4015,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