Merge branch 'master' into netgen-1.5
This commit is contained in:
commit
851a1f941e
337
base/netcmp.c
337
base/netcmp.c
|
|
@ -1141,6 +1141,323 @@ Tcl_Obj *ListElementClasses(int legal)
|
||||||
|
|
||||||
#endif
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*---------------------------------------------------------------------
|
*---------------------------------------------------------------------
|
||||||
*---------------------------------------------------------------------
|
*---------------------------------------------------------------------
|
||||||
|
|
@ -1219,8 +1536,9 @@ void FormatIllegalElementClasses()
|
||||||
n2++;
|
n2++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Fprintf(stdout, "\n");
|
SortUnmatchedLists(elist1, elist2, n1, n2);
|
||||||
|
|
||||||
|
Fprintf(stdout, "\n");
|
||||||
for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) {
|
for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) {
|
||||||
if (n != 0) {
|
if (n != 0) {
|
||||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||||
|
|
@ -1522,6 +1840,12 @@ void FormatIllegalNodeClasses()
|
||||||
ostr = CALLOC(right_col_end + 2, sizeof(char));
|
ostr = CALLOC(right_col_end + 2, sizeof(char));
|
||||||
found = 0;
|
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)
|
for (nscan = NodeClasses; nscan != NULL; nscan = nscan->next)
|
||||||
if (!(nscan->legalpartition)) {
|
if (!(nscan->legalpartition)) {
|
||||||
struct Node *N;
|
struct Node *N;
|
||||||
|
|
@ -1574,8 +1898,9 @@ void FormatIllegalNodeClasses()
|
||||||
n2++;
|
n2++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Fprintf(stdout, "\n");
|
SortUnmatchedLists(nlists1, nlists2, n1, n2);
|
||||||
|
|
||||||
|
Fprintf(stdout, "\n");
|
||||||
for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) {
|
for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) {
|
||||||
if (n != 0) {
|
if (n != 0) {
|
||||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||||
|
|
@ -5363,12 +5688,20 @@ PropertyMatch(struct objlist *ob1, int file1,
|
||||||
/* WIP---Check for no-connect pins in merged devices on both sides. */
|
/* WIP---Check for no-connect pins in merged devices on both sides. */
|
||||||
/* Both sides should either have no-connects marked, or neither. */
|
/* Both sides should either have no-connects marked, or neither. */
|
||||||
/* (Permutable pins may need to be handled correctly. . . */
|
/* (Permutable pins may need to be handled correctly. . . */
|
||||||
|
|
||||||
for (tp1 = ob1, tp2 = ob2; (tp1 != NULL) && tp1->type >= FIRSTPIN &&
|
for (tp1 = ob1, tp2 = ob2; (tp1 != NULL) && tp1->type >= FIRSTPIN &&
|
||||||
(tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next)
|
(tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next)
|
||||||
{
|
{
|
||||||
struct objlist *node1, *node2;
|
struct objlist *node1, *node2;
|
||||||
|
|
||||||
|
if (file1 == Circuit1->file)
|
||||||
node1 = Circuit1->nodename_cache[tp1->node];
|
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];
|
node2 = Circuit2->nodename_cache[tp2->node];
|
||||||
|
|
||||||
if (node1->instance.flags != node2->instance.flags)
|
if (node1->instance.flags != node2->instance.flags)
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ int NextNode;
|
||||||
int Composition = NONE;
|
int Composition = NONE;
|
||||||
int QuickSearch = 0;
|
int QuickSearch = 0;
|
||||||
int GlobalParallelNone = FALSE;
|
int GlobalParallelNone = FALSE;
|
||||||
|
int GlobalParallelOpen = TRUE;
|
||||||
|
|
||||||
int AddToExistingDefinition = 0; /* default: overwrite cell when reopened */
|
int AddToExistingDefinition = 0; /* default: overwrite cell when reopened */
|
||||||
|
|
||||||
|
|
@ -3164,11 +3165,14 @@ int CombineParallel(char *model, int file)
|
||||||
/* can be treated as equivalent for the purpose of parallelization. */
|
/* can be treated as equivalent for the purpose of parallelization. */
|
||||||
|
|
||||||
nodecount = (int *)CALLOC((tp->nodename_cache_maxnodenum + 1), sizeof(int));
|
nodecount = (int *)CALLOC((tp->nodename_cache_maxnodenum + 1), sizeof(int));
|
||||||
|
|
||||||
|
if (GlobalParallelOpen) {
|
||||||
for (ob = tp->cell; ob; ob = ob->next) {
|
for (ob = tp->cell; ob; ob = ob->next) {
|
||||||
if (ob->node >= 0)
|
if (ob->node >= 0)
|
||||||
if (ob->type != NODE)
|
if (ob->type != NODE)
|
||||||
nodecount[ob->node]++;
|
nodecount[ob->node]++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lob = NULL;
|
lob = NULL;
|
||||||
for (ob = tp->cell; ob; ) {
|
for (ob = tp->cell; ob; ) {
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,7 @@ extern int NoOutput; /* set this to 1 to disable stdout output */
|
||||||
extern int Composition; /* direction of composition */
|
extern int Composition; /* direction of composition */
|
||||||
extern int UnixWildcards; /* TRUE if *,?,{},[] only; false if full REGEXP */
|
extern int UnixWildcards; /* TRUE if *,?,{},[] only; false if full REGEXP */
|
||||||
extern int GlobalParallelNone; /* If TRUE, don't parallel combine any cells */
|
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 */
|
/* magic internal flag to restrict searches to recently placed cells */
|
||||||
extern int QuickSearch;
|
extern int QuickSearch;
|
||||||
/* does re"CellDef"ing a cell add to it or overwrite it??? */
|
/* does re"CellDef"ing a cell add to it or overwrite it??? */
|
||||||
|
|
|
||||||
|
|
@ -352,7 +352,7 @@ proc netgen::convert_to_json {filename lvs_final} {
|
||||||
close $fjson
|
close $fjson
|
||||||
}
|
}
|
||||||
|
|
||||||
#----------------------------------------------------------------
|
#-----------------------------------------------------------------------
|
||||||
# Define the "lvs" command as a way of calling the netgen options
|
# Define the "lvs" command as a way of calling the netgen options
|
||||||
# for standard compare, essentially the same as the old "netcomp"
|
# for standard compare, essentially the same as the old "netcomp"
|
||||||
# standalone program.
|
# 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
|
# although if the cells have not been read in yet, then the
|
||||||
# original syntax of filename or {filename cellname} is required.
|
# original syntax of filename or {filename cellname} is required.
|
||||||
#
|
#
|
||||||
# "args" is passed to verify and may therefore contain only the
|
# "args" may be "-list", "-json", or "-blackbox".
|
||||||
# value "-list" or nothing. If "-list", then output is returned
|
# "-list" returns output as a nested list.
|
||||||
# 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} {
|
proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
set dolist 0
|
set dolist 0
|
||||||
set dojson 0
|
set dojson 0
|
||||||
|
set noflat {}
|
||||||
foreach arg $args {
|
foreach arg $args {
|
||||||
if {$arg == "-list"} {
|
if {$arg == "-list"} {
|
||||||
puts stdout "Generating list result"
|
puts stdout "Generating list result"
|
||||||
|
|
@ -382,6 +388,9 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
} elseif {$arg == "-blackbox"} {
|
} elseif {$arg == "-blackbox"} {
|
||||||
puts stdout "Treating empty subcircuits as black-box cells"
|
puts stdout "Treating empty subcircuits as black-box cells"
|
||||||
netgen::model blackbox on
|
netgen::model blackbox on
|
||||||
|
} elseif {[string first "-noflatten=" $arg] == 0} {
|
||||||
|
set noflat [string trim [string range $arg 11 end] \"\{\}]
|
||||||
|
puts stdout "Will not flatten these subcells: $noflat"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -501,6 +510,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
set properr {}
|
set properr {}
|
||||||
|
set matcherr {}
|
||||||
set pinsgood 0
|
set pinsgood 0
|
||||||
while {$endval != {}} {
|
while {$endval != {}} {
|
||||||
if {$dolist == 1} {
|
if {$dolist == 1} {
|
||||||
|
|
@ -529,9 +539,30 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
|
|
||||||
# Flatten the non-matching subcircuit (but not the top-level cells)
|
# Flatten the non-matching subcircuit (but not the top-level cells)
|
||||||
if {[netgen::print queue] != {}} {
|
if {[netgen::print queue] != {}} {
|
||||||
|
if {([lsearch $noflat [lindex $endval 0]] == -1) &&
|
||||||
|
([lsearch $noflat [lindex $endval 1]] == -1)} {
|
||||||
netgen::log put " Flattening non-matched subcircuits $endval"
|
netgen::log put " Flattening non-matched subcircuits $endval"
|
||||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
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 {
|
} else {
|
||||||
# Match pins
|
# Match pins
|
||||||
|
|
@ -554,9 +585,32 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
} else {
|
} else {
|
||||||
# Flatten the non-matching subcircuit (but not the top-level cells)
|
# Flatten the non-matching subcircuit (but not the top-level cells)
|
||||||
if {[netgen::print queue] != {}} {
|
if {[netgen::print queue] != {}} {
|
||||||
|
if {([lsearch $noflat [lindex $endval 1]] == -1) &&
|
||||||
|
([lsearch $noflat [lindex $endval 1]] == -1)} {
|
||||||
netgen::log put " Flattening non-matched subcircuits $endval"
|
netgen::log put " Flattening non-matched subcircuits $endval"
|
||||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
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
|
netgen::log echo off
|
||||||
|
|
@ -579,6 +633,9 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
if {$properr != {}} {
|
if {$properr != {}} {
|
||||||
netgen::log put "The following cells had property errors: $properr\n"
|
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} {
|
if {$dolog} {
|
||||||
netgen::log end
|
netgen::log end
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2827,11 +2827,13 @@ _netcmp_equate(ClientData clientData,
|
||||||
char *name1 = NULL, *name2 = NULL, *optstart;
|
char *name1 = NULL, *name2 = NULL, *optstart;
|
||||||
struct nlist *tp1, *tp2, *SaveC1, *SaveC2;
|
struct nlist *tp1, *tp2, *SaveC1, *SaveC2;
|
||||||
struct objlist *ob1, *ob2;
|
struct objlist *ob1, *ob2;
|
||||||
|
struct ElementClass *saveEclass = NULL;
|
||||||
|
struct NodeClass *saveNclass = NULL;
|
||||||
int file1, file2;
|
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;
|
Tcl_Obj *tobj1, *tobj2, *tobj3;
|
||||||
|
|
||||||
if (objc > 1) {
|
while (objc > 1) {
|
||||||
optstart = Tcl_GetString(objv[1]);
|
optstart = Tcl_GetString(objv[1]);
|
||||||
if (*optstart == '-') optstart++;
|
if (*optstart == '-') optstart++;
|
||||||
if (!strcmp(optstart, "list")) {
|
if (!strcmp(optstart, "list")) {
|
||||||
|
|
@ -2839,6 +2841,13 @@ _netcmp_equate(ClientData clientData,
|
||||||
objv++;
|
objv++;
|
||||||
objc--;
|
objc--;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(optstart, "force")) {
|
||||||
|
doforce = 1;
|
||||||
|
objv++;
|
||||||
|
objc--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((objc != 2) && (objc != 4) && (objc != 6)) {
|
if ((objc != 2) && (objc != 4) && (objc != 6)) {
|
||||||
|
|
@ -2996,6 +3005,12 @@ _netcmp_equate(ClientData clientData,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINS_IDX:
|
case PINS_IDX:
|
||||||
|
if ((ElementClasses != NULL) && (doforce == TRUE)) {
|
||||||
|
saveEclass = ElementClasses;
|
||||||
|
saveNclass = NodeClasses;
|
||||||
|
ElementClasses = NULL;
|
||||||
|
NodeClasses = NULL;
|
||||||
|
}
|
||||||
if ((ElementClasses == NULL) && (auto_blackbox == FALSE)) {
|
if ((ElementClasses == NULL) && (auto_blackbox == FALSE)) {
|
||||||
if (CurrentCell == NULL) {
|
if (CurrentCell == NULL) {
|
||||||
Fprintf(stderr, "Equate elements: no current cell.\n");
|
Fprintf(stderr, "Equate elements: no current cell.\n");
|
||||||
|
|
@ -3058,6 +3073,12 @@ _netcmp_equate(ClientData clientData,
|
||||||
/* Recover temporarily set global variables (see above) */
|
/* Recover temporarily set global variables (see above) */
|
||||||
Circuit1 = SaveC1;
|
Circuit1 = SaveC1;
|
||||||
Circuit2 = SaveC2;
|
Circuit2 = SaveC2;
|
||||||
|
|
||||||
|
/* Recover ElementClasses if forcing pins on mismatched circuits */
|
||||||
|
if (doforce == TRUE) {
|
||||||
|
ElementClasses = saveEclass;
|
||||||
|
NodeClasses = saveNclass;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -3417,9 +3438,15 @@ _netcmp_property(ClientData clientData,
|
||||||
GlobalParallelNone = FALSE;
|
GlobalParallelNone = FALSE;
|
||||||
SetParallelCombine(TRUE);
|
SetParallelCombine(TRUE);
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(Tcl_GetString(objv[2]), "connected")) {
|
||||||
|
GlobalParallelOpen = FALSE;
|
||||||
|
}
|
||||||
|
else if (!strcmp(Tcl_GetString(objv[2]), "open")) {
|
||||||
|
GlobalParallelOpen = TRUE;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
Tcl_SetResult(interp, "Bad option, should be property parallel none|all",
|
Tcl_SetResult(interp, "Bad option, should be property parallel "
|
||||||
NULL);
|
"none|all|connected", NULL);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue