Compare commits

...
33 Commits
Author SHA1 Message Date
Tim Edwards e97d6f1aeb Merge branch 'master' into netgen-1.5 2021-05-14 03:00:10 -04:00
Tim Edwards 47e7367c26 Updated the versio with the last commit. 2021-05-13 15:58:49 -04:00
Tim Edwards 362fb7120b Modified the behavior of the parallel combination of devices with
"similar no connect" pins so that it is not done on top-level
netlists.  This is mainly to deal with the problem where connections
that would normally be pins (but may have, for example, been
connected to a voltage source in a schematic that was deleted because
it was not a netlistable device) are treated as no-connects.
The parallel combination of devices with similar no-connects can then
differ between netlists that differ in describing transistors as
fingered vs. individual devices.  This is an obscure case, but the
output of netgen then becomes not only wrong but difficult to
understand what happened, so it is better to avoid.
2021-05-13 15:50:12 -04:00
Tim Edwards fb4759a8cd Merge branch 'master' into netgen-1.5 2021-05-04 03:00:10 -04:00
Tim Edwards 92e8fed8be Corrected an error in checking merge flags when doing sorting of
parallel and series devices.  This was a fairly major error
undermining the property sorting (the case where the same number
of devices are in parallel in both circuits and need to be sorted
by, e.g., width, prior to checking for matches).
2021-05-03 11:20:44 -04:00
Tim Edwards 45d4004d43 Merge branch 'master' into netgen-1.5 2021-05-02 03:00:09 -04:00
Tim Edwards 01b2484be3 Updated version. 2021-05-01 22:49:59 -04:00
Tim Edwards fe47d84ace Missed a corner case in the series combination code where a device
has been shuffled to the beginning of the cell, which requires
different handling.
2021-05-01 22:48:59 -04:00
Tim Edwards 0b014e6efd Merge branch 'master' into netgen-1.5 2021-03-20 03:00:09 -04:00
Tim Edwards 0a2adeb593 Modified the "flatten" command to allow class "module" to be
flattened.  This is marginally useful---since the "module" class
is a black box, it is essentially the same as using the "ignore"
command.
2021-03-19 13:57:11 -04:00
Tim Edwards 330b34139c Slight modification to print the list of cells being forced to
match for both the filename option and immediate list.
2021-03-19 10:51:42 -04:00
Tim Edwards 62d0352149 Modified the "-noflatten" command option to "lvs" so that it can be
given a filename as a value in addition to being passed a list of
cells directly.
2021-03-19 09:41:42 -04:00
Tim Edwards 9ca713dfd9 Merge branch 'master' into netgen-1.5 2021-03-18 03:00:29 -04:00
Tim Edwards b1b04b8e87 Corrected a statement related to proxy pins that can cause a
segfault condition.
2021-03-17 16:31:22 -04:00
Tim Edwards 851a1f941e Merge branch 'master' into netgen-1.5 2021-03-06 03:00:09 -05:00
Tim Edwards 6b9d92de65 Corrected some pointer-to-int and int-to-pointer conversions to
keep the compiler happy.
2021-03-05 20:19:04 -05:00
Tim Edwards d763ad0e60 First and simplest (but most effective) cut at aligning the two
sides of the output when presenting side-by-side results.  This
matches up net or device names within a partition.  Where net or
device names match, the contents are also aligned on either side.
I attempted to also do a "best match" of contents between sides,
but as this involves a lot of analyzing the contents, it is very
computationally expensive, and so the code has been disabled.  It
could be added back in as an option.  There are also various ways
to optimize it for speed.
2021-03-05 17:23:22 -05:00
Tim Edwards fd72e24a86 Corrected an error in the code that handles no-connects as valid
pins for enabling parallel combinations, which could cause a crash.
Added a "-force" option to "equate pins" to allow pins to be matched
even on subcircuits that did not correctly match;  this was done in
conjuction with an extra option to the "lvs" command "-noflatten="
to pass a list of cellname to not be flattened even if they do not
match.  This is generally discouraged, as it prevents netgen from
resolving differences between layout and schematic hierarchy, but it
can be useful for checking that the hierarchy above a certain cell
is correct, given that if a subcell is really unmatched, then its
errors will keep propagating up the top level, making additional
errors hard to diagnose.
2021-03-05 11:32:17 -05:00
Tim Edwards 20077d3d56 Modifed the handling of parallelized no-connects so that the behavior
can be turned on or off from the setup using "property parallel open"
to allow parallelizing devices with no-connect pins vs. "property
parallel connected" to only allow parallelizing of devices with all
pins connected.
2021-03-03 17:31:45 -05:00
Tim Edwards fb798d6ce7 Merge branch 'master' into netgen-1.5 2021-03-03 03:00:12 -05:00
Tim Edwards a21ba820e9 Corrected a missing variable in a print statement in the SPICE read
routine that can cause a segfault.
2021-03-02 21:48:48 -05:00
Tim Edwards 792c5e569a Resolved the case mentioned in a prior commit where the case of N
devices in parallel with unconnected pins would be confused with
N devices in parallel with those pins all tied together.  This is
treated as a property error.
2021-03-02 16:49:03 -05:00
Tim Edwards f92192efd4 Corrected an error from yesterday's commit; the test case for
parallel combinations with disconnected nodes works with the error,
but in general it won't.
2021-03-02 10:58:36 -05:00
Tim Edwards 1f50c7ccc5 Updating VERSION with pull request #18 on github. 2021-03-02 10:16:54 -05:00
Ahmed Ghazy 8282460774 Remove netgen.{sh,tcl} and add them to .gitignore 2021-03-02 10:24:17 +02:00
Tim Edwards a888502038 Merge branch 'master' into netgen-1.5 2021-03-02 03:00:35 -05:00
Tim Edwards ea07642172 Removed the symmetry breaking option from the scripted "lvs"
command.
2021-03-01 16:57:49 -05:00
Tim Edwards e9da037001 Removed the code for fast symmetry breaking, as it has been found
to generate incorrect results on occasion.  The method to parallelize
cells with the same no-connect pins should avoid the worst-case
symmetry breaking that was previously plaguing the LVS of large
standard-cell layouts.
2021-03-01 16:55:07 -05:00
Tim Edwards 7ee50a3f8f Modified the parallel combination code to treat cells as equivalently
parallel if the same pins are no-connects.  These were previously not
treated as parallel because each no-connect has a unique node number,
and cells were only considered as parallel if all pins connected to
the same node numbers.  This avoids issues with long-running symmetry
breaking on standard cell designs due to cells like antenna taps or
any cell that is placed without connecting it up.  To do:  This
makes indistinguishable certain cases, e.g., N cells in circuit 1
with pin X open vs. N cells in circuit 2 with pin X all tied together.
This could be caught during property matching.
2021-03-01 16:33:55 -05:00
Tim Edwards c16258d4d1 Merge branch 'master' into netgen-1.5 2021-02-25 03:00:36 -05:00
Tim Edwards c7848c9c02 Corrected an error that (in a rare circumstance) can cause netgen
to go into an infinite loop and fill memory until it crashes, due
to a complete pin mismatch between devices causing one device to
have its pins removed and replaced with proxy pins.
2021-02-24 16:12:19 -05:00
Tim Edwards 5341d7a5fd Merge branch 'master' into netgen-1.5 2021-02-17 03:00:31 -05:00
Tim Edwards 402e1f0f25 Found a chokepoint in FlattenInstancesOf that was unnecessary as it
was running through the entire object linked list to find the
predecessor of a record that it had already found.  Solved by simply
keeping track of the predecessor record.
2021-02-16 17:12:00 -05:00
12 changed files with 710 additions and 286 deletions
+2
View File
@@ -12,3 +12,5 @@ scripts/config.status
*~
*.log
UPDATE_ME
tcltk/netgen.sh
tcltk/netgen.tcl
+1 -1
View File
@@ -1 +1 @@
1.5.166
1.5.176
+100 -37
View File
@@ -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 */
}
+402 -185
View File
@@ -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) = ' ';
@@ -3798,7 +4120,7 @@ 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 (kl && (kl->merge & (MERGE_S_ADD | MERGE_S_PAR))) {
if (vl->type == PROP_INTEGER)
cval = (double)vl->value.ival;
else
@@ -3815,6 +4137,9 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
proplist[i].value = cval / (double)sval;
sl->value.ival = 1;
}
else {
proplist[i].value = (double)0;
}
proplist[i].idx = i;
proplist[i].ob = obp;
obp = obp->next;
@@ -3947,8 +4272,9 @@ 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);
@@ -3960,6 +4286,7 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
+ (double)vl->value.string[1] / 10.0;
else
cval = vl->value.dval;
merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR);
}
}
@@ -3971,6 +4298,9 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
proplist[i].value = cval / (double)mval;
if (ml) ml->value.ival = 1;
}
else {
proplist[i].value = (double)0;
}
proplist[i].idx = i;
proplist[i].ob = obp;
obp = obp->next;
@@ -4019,6 +4349,9 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
proplist[i].value = cval / (double)mval;
if (ml) ml->value.ival = 1;
}
else {
proplist[i].value = 0;
}
obp = obp->next;
}
}
@@ -5363,6 +5696,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);
@@ -5865,16 +6232,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 +6306,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 +6919,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()"
-1
View File
@@ -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;
+71 -11
View File
@@ -50,6 +50,7 @@ int NextNode;
int Composition = NONE;
int QuickSearch = 0;
int GlobalParallelNone = FALSE;
int GlobalParallelOpen = TRUE;
int AddToExistingDefinition = 0; /* default: overwrite cell when reopened */
@@ -1337,7 +1338,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);
@@ -3132,6 +3133,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. */
/*----------------------------------------------------------------------*/
@@ -3146,6 +3150,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) {
@@ -3155,6 +3160,29 @@ 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));
/* Do not combine open connections on top level cells. The situation */
/* where it is meant to optimize run time, namely large digital */
/* standard cell layouts, will generally have ports and not be run on */
/* the top level cell, while a small analog circuit might. A */
/* combination of running on the top level and a difference between */
/* individual devices in one netlist vs. fingered devices in the */
/* can cause parallelizing devices with similar "no-connect" pins to */
/* produce incorrect results. */
if (GlobalParallelOpen && !(tp->flags & CELL_TOP)) {
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) {
@@ -3201,7 +3229,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);
}
@@ -3237,11 +3272,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);
@@ -3257,7 +3307,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) */
@@ -3365,6 +3415,7 @@ int CombineParallel(char *model, int file)
if (dcnt > 0) {
Fprintf(stdout, "Class %s: Merged %d devices.\n", model, dcnt);
}
FREE(nodecount);
return dcnt;
}
@@ -3590,12 +3641,21 @@ int CombineSeries(char *model, int file)
/* Device may have been moved by the above code. If so, look for */
/* it from the beginning of the list. */
if (ob2 == NULL)
for (ob2 = tp->cell; ob2->next != instlist[i][1]; ob2 = ob2->next);
for (obs = ob2->next; obs->next && (obs->next->type > FIRSTPIN
if ((ob2 == NULL) && (tp->cell == instlist[i][1]))
{
ob2 = tp->cell;
for (obs = ob2; obs->next && (obs->next->type > FIRSTPIN
|| obs->next->type == PROPERTY); obs = obs->next);
ob2->next = obs->next;
tp->cell = obs->next;
}
else
{
if (ob2 == NULL)
for (ob2 = tp->cell; ob2->next != instlist[i][1]; ob2 = ob2->next);
for (obs = ob2->next; obs->next && (obs->next->type > FIRSTPIN
|| obs->next->type == PROPERTY); obs = obs->next);
ob2->next = obs->next;
}
if (obs->next) obs->next = NULL; // Terminate 2nd instance record
/* If 1st device has unbalanced 'open' records, then add 'close' */
+1
View File
@@ -149,6 +149,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
View File
@@ -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);
+3
View File
@@ -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 */
+1 -1
View File
@@ -1186,7 +1186,7 @@ skip_ends:
else if (CountPorts(model, filenum) != 2) {
/* Modeled device: Make sure it has the right number of ports */
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a "
"resistor.\n");
"resistor.\n", model);
goto baddevice;
}
usemodel = 1;
+89 -14
View File
@@ -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
}
+34 -33
View File
@@ -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)"},
@@ -2828,11 +2827,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 +2841,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 +3005,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 +3073,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;
@@ -3418,9 +3438,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;
@@ -3982,39 +4008,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;
}