mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 14:07:07 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1272ed22fe | ||
|
|
7d910b616c | ||
|
|
6179ba8cb8 | ||
|
|
b1032f846b | ||
|
|
4c546d1472 | ||
|
|
aaf8fefc1a | ||
|
|
e1aa231db1 | ||
|
|
abaf896f7f | ||
|
|
df8fa29b2f | ||
|
|
e94d25b3f1 | ||
|
|
d14bf70f1c | ||
|
|
e659495ef5 | ||
|
|
5c21000a8b | ||
|
|
2ce3cf8dd9 | ||
|
|
05872ca918 | ||
|
|
05f433f334 | ||
|
|
e821381900 | ||
|
|
2129073a38 | ||
|
|
8022e1370f | ||
|
|
b0d980bb7d | ||
|
|
2b88d79adc | ||
|
|
ab0165b16c | ||
|
|
bf4112db07 | ||
|
|
5197eb6186 | ||
|
|
fcee934580 | ||
|
|
48ed1f7583 | ||
|
|
2d427aef3c | ||
|
|
e63593c7e2 | ||
|
|
fd0c8c87ea | ||
|
|
3d180f778d | ||
|
|
178af5f493 | ||
|
|
035fef5c72 |
+28
-14
@@ -600,8 +600,10 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
else break;
|
||||
|
||||
/* Put the child cell at the start of ChildObjList */
|
||||
ChildEnd->next = ChildObjList;
|
||||
ChildObjList = ChildStart;
|
||||
if (ChildEnd) {
|
||||
ChildEnd->next = ChildObjList;
|
||||
ChildObjList = ChildStart;
|
||||
}
|
||||
}
|
||||
|
||||
/* Put the child cell at the start of ChildObjList */
|
||||
@@ -1634,7 +1636,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
ECompare *ecomp, *ncomp;
|
||||
ECompList *list0X, *listX0;
|
||||
int hascontents1, hascontents2;
|
||||
int match, modified = 0;
|
||||
int match, modified1 = 0, modified2 = 0;
|
||||
int not_top;
|
||||
|
||||
if (file1 == -1)
|
||||
@@ -1712,7 +1714,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
" makes a better match\n", ecomp->cell1->name,
|
||||
name1, file1);
|
||||
flattenInstancesOf(name1, file1, ecomp->cell1->name);
|
||||
modified++;
|
||||
modified1++;
|
||||
}
|
||||
if (ecomp->cell2 && (ecomp->num2 > 0) &&
|
||||
(!(ecomp->cell2->flags & CELL_PLACEHOLDER))) {
|
||||
@@ -1720,7 +1722,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
" makes a better match\n", ecomp->cell2->name,
|
||||
name2, file2);
|
||||
flattenInstancesOf(name2, file2, ecomp->cell2->name);
|
||||
modified++;
|
||||
modified2++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1810,7 +1812,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
" makes a better match\n", ecomp->cell2->name,
|
||||
name2, file2);
|
||||
flattenInstancesOf(name2, file2, ecomp->cell2->name);
|
||||
modified++;
|
||||
modified2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1876,7 +1878,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
" makes a better match\n", ecomp->cell1->name,
|
||||
name1, file1);
|
||||
flattenInstancesOf(name1, file1, ecomp->cell1->name);
|
||||
modified++;
|
||||
modified1++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2030,7 +2032,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
|
||||
/* Remove from list */
|
||||
ecomp->num1--;
|
||||
modified++;
|
||||
modified1++;
|
||||
|
||||
ob1 = lob;
|
||||
}
|
||||
@@ -2168,8 +2170,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
|
||||
/* Remove from list */
|
||||
ecomp->num1--;
|
||||
modified++;
|
||||
ecomp->num2--;
|
||||
modified2++;
|
||||
|
||||
ob2 = lob;
|
||||
}
|
||||
@@ -2203,7 +2205,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
// are no other modifications, as this rule is relaxed compared to other
|
||||
// rules, and the other rules should be exhaustively applied first.
|
||||
|
||||
if ((listX0 != NULL) && (list0X != NULL) && (modified == 0)) {
|
||||
if ((listX0 != NULL) && (list0X != NULL) && ((modified1 + modified2) == 0)) {
|
||||
ECompare *ecomp0X, *ecompX0;
|
||||
ECompList *elist0X, *elistX0;
|
||||
for (elistX0 = listX0; elistX0; elistX0 = elistX0->next) {
|
||||
@@ -2235,7 +2237,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
flattenInstancesOf(name1, file1, ecompX0->cell1->name);
|
||||
ecompX0->num1 = 0;
|
||||
ecomp0X->num1 += ecompX0->num1;
|
||||
modified++;
|
||||
modified1++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2261,7 +2263,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
flattenInstancesOf(name2, file2, ecomp0X->cell2->name);
|
||||
ecomp0X->num2 = 0;
|
||||
ecompX0->num2 += ecomp0X->num2;
|
||||
modified++;
|
||||
modified2++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2292,5 +2294,17 @@ done:
|
||||
FREE(list0X);
|
||||
list0X = nextptr;
|
||||
}
|
||||
return modified;
|
||||
|
||||
// If either netlist was modified, rebuild its node cache
|
||||
|
||||
if (modified1 > 0) {
|
||||
FreeNodeNames(tc1);
|
||||
CacheNodeNames(tc1);
|
||||
}
|
||||
if (modified2 > 0) {
|
||||
FreeNodeNames(tc2);
|
||||
CacheNodeNames(tc2);
|
||||
}
|
||||
|
||||
return modified1 + modified2;
|
||||
}
|
||||
|
||||
+251
-230
@@ -21,6 +21,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for rand(), abs(), etc */
|
||||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <time.h> /* for time() as a seed for random number generator */
|
||||
@@ -1496,6 +1497,112 @@ void SortUnmatchedLists(nlists1, nlists2, n1max, n2max)
|
||||
HashKill(&n2hash);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Output string formatting routines */
|
||||
/* for two-column side-by-side comparisons */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Fill left and right columns with spaces */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
void output_string_fill(char *ostr)
|
||||
{
|
||||
int m;
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Write a formatted string in the usual format of sprintf() to */
|
||||
/* the left column. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
void output_string_left(char *ostr, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(ostr, left_col_end, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Write a formatted string in the usual format of sprintf() to */
|
||||
/* the right column. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
void output_string_right(char *ostr, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(ostr + left_col_end + 1, left_col_end, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Remove any string breaks within the output string, then */
|
||||
/* print the string to stdout. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
void output_string_print(char *ostr)
|
||||
{
|
||||
int m;
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0')
|
||||
*(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Draw a divider line to the output. If "colbrk" is TRUE, */
|
||||
/* then leave the center character as a vertical bar. */
|
||||
/* Print the divider line to stdout, then reinstate the */
|
||||
/* vertical bar. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
void output_string_print_divider(char *ostr, char colbrk)
|
||||
{
|
||||
int m;
|
||||
for (m = 0; m < right_col_end; m++) *(ostr + m) = '-';
|
||||
if (colbrk) *(ostr + left_col_end) = '|';
|
||||
output_string_print(ostr);
|
||||
*(ostr + left_col_end) = '|';
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Initialize the output string with an empty line and divider */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
char *output_string_init()
|
||||
{
|
||||
char *ostr = CALLOC(right_col_end + 2, sizeof(char));
|
||||
|
||||
*(ostr + left_col_end) = '|';
|
||||
*(ostr + right_col_end) = '\n';
|
||||
*(ostr + right_col_end + 1) = '\0';
|
||||
|
||||
output_string_fill(ostr);
|
||||
|
||||
return ostr;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Write the header for the comparison output */
|
||||
/* Print the header to stdout. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
void output_string_print_header(char *ostr, struct nlist *tc1, struct nlist *tc2)
|
||||
{
|
||||
if (tc1)
|
||||
output_string_left(ostr, "Circuit 1: %s", tc1->name);
|
||||
if (tc2)
|
||||
output_string_right(ostr, "Circuit 2: %s", tc2->name);
|
||||
|
||||
output_string_print(ostr);
|
||||
}
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------
|
||||
*---------------------------------------------------------------------
|
||||
@@ -1512,9 +1619,9 @@ void FormatIllegalElementClasses()
|
||||
char *permcount;
|
||||
int bytesleft;
|
||||
|
||||
ostr = CALLOC(right_col_end + 2, sizeof(char));
|
||||
permname = CALLOC(right_col_end + 2, sizeof(char));
|
||||
permcount = CALLOC(right_col_end + 2, sizeof(char));
|
||||
ostr = output_string_init();
|
||||
|
||||
found = 0;
|
||||
for (escan = ElementClasses; escan != NULL; escan = escan->next)
|
||||
@@ -1527,15 +1634,7 @@ void FormatIllegalElementClasses()
|
||||
|
||||
/* Print in side-by-side format */
|
||||
|
||||
*(ostr + left_col_end) = '|';
|
||||
*(ostr + right_col_end) = '\n';
|
||||
*(ostr + right_col_end + 1) = '\0';
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
snprintf(ostr, left_col_end, "Circuit 1: %s", Circuit1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "Circuit 2: %s", Circuit2->name);
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print_header(ostr, Circuit1, Circuit2);
|
||||
}
|
||||
found = 1;
|
||||
|
||||
@@ -1579,32 +1678,27 @@ void FormatIllegalElementClasses()
|
||||
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) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
output_string_fill(ostr);
|
||||
Fprintf(stdout, ostr);
|
||||
} else {
|
||||
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
|
||||
Fprintf(stdout, ostr);
|
||||
*(ostr + left_col_end) = '|';
|
||||
output_string_print_divider(ostr, FALSE);
|
||||
}
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
output_string_fill(ostr);
|
||||
if (n < n1) {
|
||||
estr = elist1[n]->name;
|
||||
if (*estr == '/') estr++; // Remove leading slash, if any
|
||||
snprintf(ostr, left_col_end, "Instance: %s", estr);
|
||||
output_string_left(ostr, "Instance: %s", estr);
|
||||
}
|
||||
else
|
||||
snprintf(ostr, left_col_end, "(no matching instance)");
|
||||
output_string_left(ostr, "%s", "(no matching instance)");
|
||||
if (n < n2) {
|
||||
estr = elist2[n]->name;
|
||||
if (*estr == '/') estr++; // Remove leading slash, if any
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "Instance: %s", estr);
|
||||
output_string_right(ostr, "Instance: %s", estr);
|
||||
}
|
||||
else
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching instance)");
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_right(ostr, "%s", "(no matching instance)");
|
||||
output_string_print(ostr);
|
||||
|
||||
if (n >= n1)
|
||||
maxf = elist2[n]->fanout;
|
||||
@@ -1616,12 +1710,11 @@ void FormatIllegalElementClasses()
|
||||
|
||||
f1 = f2 = 0;
|
||||
while ((f1 < maxf) || (f2 < maxf)) {
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
output_string_fill(ostr);
|
||||
if (n < n1) {
|
||||
if (f1 < elist1[n]->fanout) {
|
||||
if (elist1[n]->flist[f1].permute == (char)1) {
|
||||
snprintf(ostr, left_col_end, " %s = %d", elist1[n]->flist[f1].name,
|
||||
output_string_left(ostr, " %s = %d", elist1[n]->flist[f1].name,
|
||||
elist1[n]->flist[f1].count);
|
||||
}
|
||||
else {
|
||||
@@ -1643,7 +1736,7 @@ void FormatIllegalElementClasses()
|
||||
sprintf(value, "%d", elist1[n]->flist[f1].count);
|
||||
strcat(permcount, value);
|
||||
strcat(permcount, ")");
|
||||
snprintf(ostr, left_col_end, " %s = %s", permname, permcount);
|
||||
output_string_left(ostr, " %s = %s", permname, permcount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1651,7 +1744,7 @@ void FormatIllegalElementClasses()
|
||||
if (n < n2) {
|
||||
if (f2 < elist2[n]->fanout) {
|
||||
if (elist2[n]->flist[f2].permute == (char)1) {
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, " %s = %d", elist2[n]->flist[f2].name,
|
||||
output_string_right(ostr, " %s = %d", elist2[n]->flist[f2].name,
|
||||
elist2[n]->flist[f2].count);
|
||||
}
|
||||
else {
|
||||
@@ -1673,21 +1766,18 @@ void FormatIllegalElementClasses()
|
||||
sprintf(value, "%d", elist2[n]->flist[f2].count);
|
||||
strcat(permcount, value);
|
||||
strcat(permcount, ")");
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, " %s = %s", permname, permcount);
|
||||
output_string_right(ostr, " %s = %s", permname, permcount);
|
||||
}
|
||||
}
|
||||
}
|
||||
f2++;
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
}
|
||||
|
||||
FreeFormattedLists(elist1, numlists1);
|
||||
FreeFormattedLists(elist2, numlists2);
|
||||
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
|
||||
Fprintf(stdout, ostr);
|
||||
*(ostr + left_col_end) = '|';
|
||||
output_string_print_divider(ostr, FALSE);
|
||||
}
|
||||
|
||||
FREE(ostr);
|
||||
@@ -1875,7 +1965,7 @@ void FormatIllegalNodeClasses()
|
||||
int found, numlists1, numlists2, n1, n2, n, f, i, maxf;
|
||||
char *ostr;
|
||||
|
||||
ostr = CALLOC(right_col_end + 2, sizeof(char));
|
||||
ostr = output_string_init();
|
||||
found = 0;
|
||||
|
||||
/*
|
||||
@@ -1893,15 +1983,7 @@ void FormatIllegalNodeClasses()
|
||||
Fprintf(stdout, "Class fragments follow (with fanout counts):\n");
|
||||
|
||||
/* Print in side-by-side format */
|
||||
*(ostr + left_col_end) = '|';
|
||||
*(ostr + right_col_end) = '\n';
|
||||
*(ostr + right_col_end + 1) = '\0';
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
snprintf(ostr, left_col_end, "Circuit 1: %s", Circuit1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "Circuit 2: %s", Circuit2->name);
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print_header(ostr, Circuit1, Circuit2);
|
||||
}
|
||||
found = 1;
|
||||
|
||||
@@ -1941,26 +2023,21 @@ void FormatIllegalNodeClasses()
|
||||
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) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
output_string_fill(ostr);
|
||||
Fprintf(stdout, ostr);
|
||||
} else {
|
||||
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
|
||||
Fprintf(stdout, ostr);
|
||||
*(ostr + left_col_end) = '|';
|
||||
output_string_print_divider(ostr, FALSE);
|
||||
}
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
output_string_fill(ostr);
|
||||
if (n < n1)
|
||||
snprintf(ostr, left_col_end, "Net: %s", nlists1[n]->name);
|
||||
output_string_left(ostr, "Net: %s", nlists1[n]->name);
|
||||
else
|
||||
snprintf(ostr, left_col_end, "(no matching net)");
|
||||
output_string_left(ostr, "%s", "(no matching net)");
|
||||
if (n < n2)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "Net: %s", nlists2[n]->name);
|
||||
output_string_right(ostr, "Net: %s", nlists2[n]->name);
|
||||
else
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching net)");
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_right(ostr, "%s", "(no matching net)");
|
||||
output_string_print(ostr);
|
||||
|
||||
if (n >= n1)
|
||||
maxf = nlists2[n]->fanout;
|
||||
@@ -1971,17 +2048,16 @@ void FormatIllegalNodeClasses()
|
||||
nlists1[n]->fanout : nlists2[n]->fanout;
|
||||
|
||||
for (f = 0; f < maxf; f++) {
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
output_string_fill(ostr);
|
||||
if (n < n1)
|
||||
if (f < nlists1[n]->fanout) {
|
||||
if (nlists1[n]->flist[f].permute <= 1)
|
||||
snprintf(ostr, left_col_end, " %s/%s = %d",
|
||||
output_string_left(ostr, " %s/%s = %d",
|
||||
nlists1[n]->flist[f].model,
|
||||
nlists1[n]->flist[f].name,
|
||||
nlists1[n]->flist[f].count);
|
||||
else {
|
||||
snprintf(ostr, left_col_end, " %s/(%s) = %d",
|
||||
output_string_left(ostr, " %s/(%s) = %d",
|
||||
nlists1[n]->flist[f].model,
|
||||
nlists1[n]->flist[f].name,
|
||||
nlists1[n]->flist[f].count);
|
||||
@@ -1991,28 +2067,25 @@ void FormatIllegalNodeClasses()
|
||||
if (n < n2)
|
||||
if (f < nlists2[n]->fanout) {
|
||||
if (nlists2[n]->flist[f].permute <= 1)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, " %s/%s = %d",
|
||||
output_string_right(ostr, " %s/%s = %d",
|
||||
nlists2[n]->flist[f].model,
|
||||
nlists2[n]->flist[f].name,
|
||||
nlists2[n]->flist[f].count);
|
||||
else {
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, " %s/(%s) = %d",
|
||||
output_string_right(ostr, " %s/(%s) = %d",
|
||||
nlists2[n]->flist[f].model,
|
||||
nlists2[n]->flist[f].name,
|
||||
nlists2[n]->flist[f].count);
|
||||
FREE(nlists2[n]->flist[f].name);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
}
|
||||
|
||||
FreeFormattedLists(nlists1, numlists1);
|
||||
FreeFormattedLists(nlists2, numlists2);
|
||||
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
|
||||
Fprintf(stdout, ostr);
|
||||
*(ostr + left_col_end) = '|';
|
||||
output_string_print_divider(ostr, FALSE);
|
||||
}
|
||||
FREE(ostr);
|
||||
}
|
||||
@@ -2706,7 +2779,9 @@ CheckLegalElementPartition(struct ElementClass *head)
|
||||
found = 0;
|
||||
for (scan = head; scan != NULL; scan = scan->next) {
|
||||
|
||||
if (scan->count == 2) continue;
|
||||
/* Quick check for matching 1:1 case */
|
||||
if ((scan->count == 2) && (scan->elements->graph != scan->elements->next->graph))
|
||||
continue;
|
||||
C1 = C2 = 0;
|
||||
for (E = scan->elements; E != NULL; E = E->next) {
|
||||
if (E->graph == Circuit1->file) C1++;
|
||||
@@ -2828,7 +2903,9 @@ CheckLegalNodePartition(struct NodeClass *head)
|
||||
found = 0;
|
||||
for (scan = head; scan != NULL; scan = scan->next) {
|
||||
|
||||
if (scan->count == 2) continue;
|
||||
/* Quick check for matching 1:1 case */
|
||||
if ((scan->count == 2) && (scan->nodes->graph != scan->nodes->next->graph))
|
||||
continue;
|
||||
C1 = C2 = 0;
|
||||
for (N = scan->nodes; N != NULL; N = N->next) {
|
||||
if (N->graph == Circuit1->file) C1++;
|
||||
@@ -3198,23 +3275,12 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
Tcl_Obj *clist1, *clist2;
|
||||
#endif
|
||||
|
||||
ostr = CALLOC(right_col_end + 2, sizeof(char));
|
||||
ostr = output_string_init();
|
||||
|
||||
if (Debug == 0) {
|
||||
Fprintf(stdout, "Subcircuit summary:\n");
|
||||
*(ostr + left_col_end) = '|';
|
||||
*(ostr + right_col_end) = '\n';
|
||||
*(ostr + right_col_end + 1) = '\0';
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
|
||||
snprintf(ostr, left_col_end, "Circuit 1: %s", Circuit1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "Circuit 2: %s", Circuit2->name);
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = '-';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = '-';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print_header(ostr, Circuit1, Circuit2);
|
||||
output_string_print_divider(ostr, TRUE);
|
||||
}
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
@@ -3268,27 +3334,24 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
}
|
||||
|
||||
if (Debug == 0) {
|
||||
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
output_string_fill(ostr);
|
||||
if (M1 == C1)
|
||||
snprintf(ostr, left_col_end, "%s (%d)", Esrch->object->model.class, C1);
|
||||
output_string_left(ostr, "%s (%d)", Esrch->object->model.class, C1);
|
||||
else
|
||||
snprintf(ostr, left_col_end, "%s (%d->%d)", Esrch->object->model.class,
|
||||
output_string_left(ostr, "%s (%d->%d)", Esrch->object->model.class,
|
||||
M1, C1);
|
||||
if (C2 > 0) {
|
||||
if (M2 == C2)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)%s", tp2->name,
|
||||
output_string_right(ostr, "%s (%d)%s", tp2->name,
|
||||
C2, (C2 == C1) ? "" : " **Mismatch**");
|
||||
else
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d->%d)%s",
|
||||
output_string_right(ostr, "%s (%d->%d)%s",
|
||||
tp2->name, M2, C2, (C2 == C1) ? "" : " **Mismatch**");
|
||||
}
|
||||
else {
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching element)");
|
||||
output_string_right(ostr, "%s", "(no matching element)");
|
||||
}
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist) {
|
||||
@@ -3347,17 +3410,15 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
}
|
||||
|
||||
if (Debug == 0) {
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
snprintf(ostr, left_col_end, "(no matching element)");
|
||||
output_string_fill(ostr);
|
||||
output_string_left(ostr, "%s", "(no matching element)");
|
||||
if (C2 == M2)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)",
|
||||
output_string_right(ostr, "%s (%d)",
|
||||
Esrch->object->model.class, C2);
|
||||
else
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d->%d)",
|
||||
output_string_right(ostr, "%s (%d->%d)",
|
||||
Esrch->object->model.class, M2, C2);
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist) {
|
||||
@@ -3401,14 +3462,12 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
C1, C2);
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
snprintf(ostr, left_col_end, "Number of devices: %d%s", C1, (C1 == C2) ? "" :
|
||||
output_string_fill(ostr);
|
||||
output_string_left(ostr, "Number of devices: %d%s", C1, (C1 == C2) ? "" :
|
||||
" **Mismatch**");
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "Number of devices: %d%s", C2, (C1 == C2) ? "" :
|
||||
output_string_right(ostr, "Number of devices: %d%s", C2, (C1 == C2) ? "" :
|
||||
" **Mismatch**");
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
@@ -3454,23 +3513,14 @@ void FirstNodePass(struct Node *N, int dolist)
|
||||
char *ostr;
|
||||
int i;
|
||||
|
||||
ostr = CALLOC(right_col_end + 2, sizeof(char));
|
||||
|
||||
*(ostr + left_col_end) = '|';
|
||||
*(ostr + right_col_end) = '\n';
|
||||
*(ostr + right_col_end + 1) = '\0';
|
||||
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
snprintf(ostr, left_col_end, "Number of nets: %d%s", C1, (C1 == C2) ? "" :
|
||||
ostr = output_string_init();
|
||||
output_string_left(ostr, "Number of nets: %d%s", C1, (C1 == C2) ? "" :
|
||||
" **Mismatch**");
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "Number of nets: %d%s", C2, (C1 == C2) ? "" :
|
||||
output_string_right(ostr, "Number of nets: %d%s", C2, (C1 == C2) ? "" :
|
||||
" **Mismatch**");
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print(ostr);
|
||||
|
||||
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print_divider(ostr, FALSE);
|
||||
|
||||
FREE(ostr);
|
||||
}
|
||||
@@ -4467,9 +4517,9 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
proplist = (propsort *)MALLOC(run * sizeof(propsort));
|
||||
|
||||
obp = obn;
|
||||
mval = 1;
|
||||
pval = aval = oval = 0.0;
|
||||
for (i = 0; i < run; i++) {
|
||||
mval = 1;
|
||||
has_crit = FALSE;
|
||||
merge_type = MERGE_NONE;
|
||||
ca = co = (char)0;
|
||||
@@ -5165,26 +5215,34 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
// (if any)
|
||||
|
||||
if (comb == TRUE) {
|
||||
double pd;
|
||||
int mult, cidx = -1;
|
||||
struct valuelist *avl, *cvl = NULL;
|
||||
critval.type = PROP_ENDLIST;
|
||||
critval.value.dval = 0.0;
|
||||
for (i = 0; i < run; i++) {
|
||||
avl = NULL;
|
||||
if (vlist[0][i] == NULL) continue;
|
||||
mult = vlist[0][i]->value.ival;
|
||||
// if (vlist[0][i] == NULL) continue;
|
||||
// mult = vlist[0][i]->value.ival;
|
||||
if (vlist[0][i] == NULL)
|
||||
mult = 1;
|
||||
else
|
||||
mult = vlist[0][i]->value.ival;
|
||||
changed = 0;
|
||||
|
||||
/* For all properties that are not M, S, or crit, */
|
||||
/* combine as specified by the merge type of the property. */
|
||||
|
||||
for (p = 1; p < pcount; p++) {
|
||||
kl = plist[p];
|
||||
vl = vlist[p][i];
|
||||
ctype = clist[p][i];
|
||||
|
||||
/* critical properties never combine, but track them */
|
||||
if ((series == TRUE) && (ctype & MERGE_S_CRIT)) {
|
||||
if ((vl->type != critval.type) || (vl->value.dval != critval.value.dval))
|
||||
pd = 2 * fabs(vl->value.dval - critval.value.dval) /
|
||||
(vl->value.dval + critval.value.dval);
|
||||
if ((vl->type != critval.type) || (pd > kl->slop.dval))
|
||||
{
|
||||
critval.type = vl->type;
|
||||
critval.value = vl->value;
|
||||
@@ -5193,7 +5251,9 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
continue;
|
||||
}
|
||||
if ((series == FALSE) && (ctype & MERGE_P_CRIT)) {
|
||||
if ((vl->type != critval.type) || (vl->value.dval != critval.value.dval))
|
||||
pd = 2 * fabs(vl->value.dval - critval.value.dval) /
|
||||
(vl->value.dval + critval.value.dval);
|
||||
if ((vl->type != critval.type) || (pd > kl->slop.dval))
|
||||
{
|
||||
critval.type = vl->type;
|
||||
critval.value = vl->value;
|
||||
@@ -5239,6 +5299,11 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
ctype = clist[p][i];
|
||||
|
||||
if (ctype & (MERGE_S_ADD | MERGE_P_ADD)) {
|
||||
if (!vlist[0][i]) {
|
||||
/* Create an entry with M = 0 to force removal */
|
||||
vlist[0][i] = (struct valuelist *)CALLOC(1,
|
||||
sizeof(struct valuelist));
|
||||
}
|
||||
vlist[0][i]->value.ival = 0; /* set M to 0 */
|
||||
if (cvl && (cvl->type == PROP_INTEGER))
|
||||
{
|
||||
@@ -5258,6 +5323,11 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
}
|
||||
}
|
||||
else if (ctype & (MERGE_S_PAR | MERGE_P_PAR)) {
|
||||
if (!vlist[0][i]) {
|
||||
/* Create an entry with M = 0 to force removal */
|
||||
vlist[0][i] = (struct valuelist *)CALLOC(1,
|
||||
sizeof(struct valuelist));
|
||||
}
|
||||
vlist[0][i]->value.ival = 0; /* set M to 0 */
|
||||
/* To do parallel combination, both types need to
|
||||
* be double, so recast them if they are integer.
|
||||
@@ -6211,7 +6281,9 @@ PropertyMatch(struct Element *E1, struct Element *E2,
|
||||
if (kl1 != NULL)
|
||||
break; // Property is required
|
||||
}
|
||||
else if (vl1->value.ival != 1)
|
||||
else if ((vl1->type == PROP_INTEGER) && (vl1->value.ival != 1))
|
||||
break; // Property M != 1 or S != 1 is a mismatch.
|
||||
else if ((vl1->type == PROP_DOUBLE) && (vl1->value.dval != 1))
|
||||
break; // Property M != 1 or S != 1 is a mismatch.
|
||||
}
|
||||
if (vl1->type != PROP_ENDLIST) {
|
||||
@@ -6244,22 +6316,20 @@ PropertyMatch(struct Element *E1, struct Element *E2,
|
||||
int multmatch, count;
|
||||
PropertyCheckMismatch(tp1, tc1, inst1, tp2, tc2,
|
||||
inst2, E1, E2, FALSE, FALSE, &multmatch, NULL);
|
||||
if (multmatch == 1) {
|
||||
/* Final attempt: Reduce M to 1 on both devices */
|
||||
run1 = run2 = 0;
|
||||
for (tpc = tp1; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run1++;
|
||||
for (tpc = tp2; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run2++;
|
||||
PropertyOptimize(tp1, tc1, run1, FALSE, TRUE);
|
||||
PropertyOptimize(tp2, tc2, run2, FALSE, TRUE);
|
||||
}
|
||||
else if (multmatch == 2) {
|
||||
run1 = run2 = 0;
|
||||
for (tpc = tp1; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run1++;
|
||||
for (tpc = tp2; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run2++;
|
||||
|
||||
if (multmatch == 2) {
|
||||
/* Final attempt: Reduce S to 1 on both devices */
|
||||
run1 = run2 = 0;
|
||||
for (tpc = tp1; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run1++;
|
||||
for (tpc = tp2; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run2++;
|
||||
PropertyOptimize(tp1, tc1, run1, TRUE, TRUE);
|
||||
PropertyOptimize(tp2, tc2, run2, TRUE, TRUE);
|
||||
}
|
||||
else if ((multmatch == 1) || (run1 != run2)) {
|
||||
/* Final attempt: Reduce M to 1 on both devices */
|
||||
PropertyOptimize(tp1, tc1, run1, FALSE, TRUE);
|
||||
PropertyOptimize(tp2, tc2, run2, FALSE, TRUE);
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
mlist =
|
||||
#endif
|
||||
@@ -7202,8 +7272,6 @@ int EquivalenceClasses(char *name1, int file1, char *name2, int file2, int douni
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Callback function used by MatchPins */
|
||||
/*----------------------------------------------------------------------*/
|
||||
@@ -7360,7 +7428,7 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
|
||||
// Count the largest node number used in the cell
|
||||
maxnode = -1;
|
||||
for (ob = ptr->cell; ob; ob = ob->next)
|
||||
if (ob->type >= FIRSTPIN || ob->type == NODE)
|
||||
if (ob->type >= FIRSTPIN || ob->type == NODE || ob->type == PORT)
|
||||
if (ob->node >= maxnode)
|
||||
maxnode = ob->node + 1;
|
||||
numnodes = maxnode;
|
||||
@@ -7542,23 +7610,13 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
}
|
||||
#endif
|
||||
|
||||
ostr = CALLOC(right_col_end + 2, sizeof(char));
|
||||
ostr = output_string_init();
|
||||
|
||||
if (Debug == 0) {
|
||||
/* Format side-by-side comparison of pins */
|
||||
Fprintf(stdout, "\nSubcircuit pins:\n");
|
||||
*(ostr + left_col_end) = '|';
|
||||
*(ostr + right_col_end) = '\n';
|
||||
*(ostr + right_col_end + 1) = '\0';
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
snprintf(ostr, left_col_end, "Circuit 1: %s", tc1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "Circuit 2: %s", tc2->name);
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = '-';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = '-';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print_header(ostr, tc1, tc2);
|
||||
output_string_print_divider(ostr, TRUE);
|
||||
}
|
||||
|
||||
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
|
||||
@@ -7597,13 +7655,12 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
nomatch = FALSE;
|
||||
if ((IsPort(ob2)) && (ob2->node == obp->node)) {
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
snprintf(ostr, left_col_end, "%s", ob1->name);
|
||||
output_string_fill(ostr);
|
||||
output_string_left(ostr, "%s", ob1->name);
|
||||
}
|
||||
if ((*matchfunc)(ob1->name, ob2->name)) {
|
||||
if (Debug == 0)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
output_string_right(ostr, "%s", ob2->name);
|
||||
}
|
||||
else {
|
||||
/* Check remainder of ports to see if there is a name match on the
|
||||
@@ -7615,7 +7672,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if ((*matchfunc)(ob3->name, ob1->name)) {
|
||||
ob2 = ob3;
|
||||
if (Debug == 0)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
output_string_right(ostr, "%s", ob2->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -7623,9 +7680,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (ob3 == NULL) {
|
||||
if (Debug == 0) {
|
||||
if (ob2->model.port == -1)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", ob2->name);
|
||||
output_string_right(ostr, "%s **Mismatch**",
|
||||
ob2->name);
|
||||
else
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
|
||||
output_string_right(ostr, "%s", "(no matching pin)");
|
||||
}
|
||||
nomatch = TRUE;
|
||||
/* Pins with different names are on different nets,
|
||||
@@ -7636,9 +7694,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
}
|
||||
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
else if (nomatch) {
|
||||
Fprintf(stderr, "No matching pin in cell %s for "
|
||||
@@ -7677,13 +7733,11 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
// so don't print out the "no pins" entry.
|
||||
|
||||
if (strcmp(obn->name, "(no pins)")) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
snprintf(ostr, 32, "%s", obn->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_fill(ostr);
|
||||
output_string_left(ostr, "%s", obn->name);
|
||||
output_string_right(ostr, "(no pin, node is %s",
|
||||
obp->name);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -7725,13 +7779,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
|
||||
if (ob1 == NULL) {
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
snprintf(ostr, left_col_end, "%s", obn->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_fill(ostr);
|
||||
output_string_left(ostr, "%s", obn->name);
|
||||
output_string_right(ostr, "%s", "(no matching pin)");
|
||||
output_string_print(ostr);
|
||||
}
|
||||
else {
|
||||
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
|
||||
@@ -7811,13 +7862,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
snprintf(ostr, left_col_end, "%s", ob1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_fill(ostr);
|
||||
output_string_left(ostr, "%s", ob1->name);
|
||||
output_string_right(ostr, "%s", ob2->name);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, "Circuit %s port %d \"%s\""
|
||||
@@ -7866,13 +7914,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
snprintf(ostr, left_col_end, "%s", ob1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_fill(ostr);
|
||||
output_string_left(ostr, "%s", ob1->name);
|
||||
output_string_right(ostr, "%s", ob2->name);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, "Circuit %s port %d \"%s\""
|
||||
@@ -7930,13 +7975,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
snprintf(ostr, left_col_end, "%s", ob1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_fill(ostr);
|
||||
output_string_left(ostr, "%s", ob1->name);
|
||||
output_string_right(ostr, "%s", ob2->name);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, "Circuit %s port %d \"%s\""
|
||||
@@ -7988,13 +8030,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (Debug == 0) {
|
||||
// See above for reverse case
|
||||
if (strcmp(ob2->name, "(no pins)")) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
snprintf(ostr, left_col_end, "(no matching pin)");
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
output_string_fill(ostr);
|
||||
output_string_left(ostr, "%s", "(no matching pin)");
|
||||
output_string_right(ostr, "%s", ob2->name);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -8128,23 +8167,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
obn->instance.name = NULL;
|
||||
obn->node = -1;
|
||||
|
||||
/* Note: Has this pin already been accounted for? */
|
||||
if (Debug == 0) {
|
||||
if (strcmp(ob1->name, "(no pins)")) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
snprintf(ostr, left_col_end, "%s", ob1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
|
||||
tc1->name, ob1->name);
|
||||
}
|
||||
|
||||
if (ob2 == tc2->cell) {
|
||||
obn->next = ob2;
|
||||
tc2->cell = obn;
|
||||
@@ -8174,15 +8196,12 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
}
|
||||
FREE(cover);
|
||||
|
||||
if (Debug == 0) {
|
||||
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
|
||||
Fprintf(stdout, ostr);
|
||||
}
|
||||
if (Debug == 0)
|
||||
output_string_print_divider(ostr, FALSE);
|
||||
|
||||
/* Run cleanuppins on circuit 1 */
|
||||
if (needclean1) {
|
||||
if (needclean1)
|
||||
CleanupPins(tc1->name, tc1->file);
|
||||
}
|
||||
|
||||
/* Add proxy pins to all instances of Circuit1 */
|
||||
|
||||
@@ -8410,6 +8429,8 @@ void FlattenCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Handler is only used when netgen is run from a */
|
||||
/* terminal, not the Tk console. */
|
||||
|
||||
+2
-2
@@ -3094,7 +3094,7 @@ void add_balancing_close(struct objlist *ob1, struct objlist *ob2)
|
||||
for (nob = ob1->next; nob && nob->type != FIRSTPIN; nob = nob->next)
|
||||
if (nob->type == PROPERTY)
|
||||
break;
|
||||
if (nob->type != PROPERTY) return; // shouldn't happen
|
||||
if (nob == NULL || nob->type != PROPERTY) return; // shouldn't happen
|
||||
|
||||
opentags = 0;
|
||||
for (; nob->next && nob->next->type == PROPERTY; nob = nob->next) {
|
||||
@@ -3644,7 +3644,7 @@ int CombineSeries(char *model, int file)
|
||||
nob->type = PROPERTY;
|
||||
nob->name = strsave("properties");
|
||||
nob->node = -2; /* Don't report as disconnected node */
|
||||
nob->model.class = (obp->model.class == NULL) ? NULL :
|
||||
nob->model.class = (obp == NULL || obp->model.class == NULL) ? NULL :
|
||||
strsave(obp->model.class);
|
||||
nob->instance.props = NewPropValue(2);
|
||||
|
||||
|
||||
+91
-68
@@ -223,12 +223,35 @@ int matchnocase(char *st1, char *st2)
|
||||
{
|
||||
char *sp1 = st1;
|
||||
char *sp2 = st2;
|
||||
char v1 = FALSE, v2 = FALSE;
|
||||
|
||||
/* In case of a property that does not exist in one netlist, matchnocase()
|
||||
* may be passed a null value, so return 0 to indicate a non-match.
|
||||
* *Both* values null will also be treated as a mismatch (debatable
|
||||
* behavior).
|
||||
*/
|
||||
if (!sp1 || !sp2) return 0;
|
||||
|
||||
/* Verilog back-slash escaped names should match an equivalent non-
|
||||
* back-slashed name. (NOTE: This behavior needs to be added to match().)
|
||||
*/
|
||||
if ((*sp1 == '\\') && (*sp2 != '\\')) {
|
||||
v1 = TRUE;
|
||||
sp1++;
|
||||
}
|
||||
if ((*sp2 == '\\') && (*sp1 != '\\')) {
|
||||
v2 = TRUE;
|
||||
sp2++;
|
||||
}
|
||||
|
||||
while (*sp1 != '\0' && *sp2 != '\0') {
|
||||
if (to_lower[*sp1] != to_lower[*sp2]) break;
|
||||
sp1++;
|
||||
sp2++;
|
||||
}
|
||||
if (v1 && (*sp1 == ' ')) sp1++;
|
||||
if (v2 && (*sp2 == ' ')) sp2++;
|
||||
|
||||
if ((*sp1 != '\0') || (*sp2 != '\0')) return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -596,65 +619,65 @@ int freeprop(struct hashlist *p)
|
||||
|
||||
void CellDelete(char *name, int fnum)
|
||||
{
|
||||
/* delete all the contents of cell 'name', and remove 'name' from
|
||||
the cell hash table. NOTE: this procedure does not care or check
|
||||
if 'name' has been instanced anywhere. It is assumed that if this
|
||||
is the case, the user will (quickly) define a new cell of that name.
|
||||
*/
|
||||
struct objlist *ob, *obnext;
|
||||
struct nlist *tp;
|
||||
/* delete all the contents of cell 'name', and remove 'name' from
|
||||
the cell hash table. NOTE: this procedure does not care or check
|
||||
if 'name' has been instanced anywhere. It is assumed that if this
|
||||
is the case, the user will (quickly) define a new cell of that name.
|
||||
*/
|
||||
struct objlist *ob, *obnext;
|
||||
struct nlist *tp;
|
||||
|
||||
tp = LookupCellFile(name, fnum);
|
||||
if (tp == NULL) {
|
||||
Printf ("No cell '%s' found.\n", name);
|
||||
return;
|
||||
}
|
||||
tp = LookupCellFile(name, fnum);
|
||||
if (tp == NULL) {
|
||||
Printf ("No cell '%s' found.\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
HashIntDelete(name, fnum, &cell_dict);
|
||||
/* now make sure that we free all the fields of the nlist struct */
|
||||
if (tp->name != NULL) FREE(tp->name);
|
||||
HashKill(&(tp->objdict));
|
||||
HashKill(&(tp->instdict));
|
||||
RecurseHashTable(&(tp->propdict), freeprop);
|
||||
HashKill(&(tp->propdict));
|
||||
FreeNodeNames(tp);
|
||||
ob = tp->cell;
|
||||
while (ob != NULL) {
|
||||
obnext = ob->next;
|
||||
FreeObject (ob);
|
||||
ob = obnext;
|
||||
}
|
||||
HashIntDelete(name, fnum, &cell_dict);
|
||||
/* now make sure that we free all the fields of the nlist struct */
|
||||
if (tp->name != NULL) FREE(tp->name);
|
||||
HashKill(&(tp->objdict));
|
||||
HashKill(&(tp->instdict));
|
||||
RecurseHashTable(&(tp->propdict), freeprop);
|
||||
HashKill(&(tp->propdict));
|
||||
FreeNodeNames(tp);
|
||||
ob = tp->cell;
|
||||
while (ob != NULL) {
|
||||
obnext = ob->next;
|
||||
FreeObject (ob);
|
||||
ob = obnext;
|
||||
}
|
||||
}
|
||||
|
||||
static int PrintCellHashTableElement(struct hashlist *p)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct nlist *ptr;
|
||||
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if ((TopFile >= 0) && (ptr->file != TopFile)) return 1;
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if ((TopFile >= 0) && (ptr->file != TopFile)) return 1;
|
||||
|
||||
if (ptr->class != CLASS_SUBCKT) {
|
||||
/* only print primitive cells if Debug is enabled */
|
||||
if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n",
|
||||
if ((ptr->class != CLASS_SUBCKT) && (ptr->class != CLASS_MODULE)) {
|
||||
/* only print primitive cells if Debug is enabled */
|
||||
if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n",
|
||||
ptr->name, ptr->number);
|
||||
else if (Debug == 3) { /* list */
|
||||
else if (Debug == 3) { /* list */
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
#else
|
||||
Printf("%s ", ptr->name);
|
||||
Printf("%s ", ptr->name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if ((Debug == 2) || (Debug == 3)) { /* list only */
|
||||
}
|
||||
}
|
||||
else if ((Debug == 2) || (Debug == 3)) { /* list only */
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
#else
|
||||
Printf("%s ", ptr->name);
|
||||
Printf("%s ", ptr->name);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
Printf("Cell: %s (instanced %d times)\n",ptr->name,ptr->number);
|
||||
return(1);
|
||||
}
|
||||
else
|
||||
Printf("Cell: %s (instanced %d times)\n", ptr->name, ptr->number);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Print the contents of the cell hash table. */
|
||||
@@ -663,65 +686,65 @@ static int PrintCellHashTableElement(struct hashlist *p)
|
||||
|
||||
void PrintCellHashTable(int full, int filenum)
|
||||
{
|
||||
int total, bins;
|
||||
int OldDebug;
|
||||
int total, bins;
|
||||
int OldDebug;
|
||||
|
||||
if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||
if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||
PrintCellHashTable(full, Circuit1->file);
|
||||
PrintCellHashTable(full, Circuit2->file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TopFile = filenum;
|
||||
TopFile = filenum;
|
||||
|
||||
bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed);
|
||||
total = RecurseHashTable(&cell_dict, CountHashTableEntries);
|
||||
if (full < 2)
|
||||
Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n",
|
||||
bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed);
|
||||
total = RecurseHashTable(&cell_dict, CountHashTableEntries);
|
||||
if (full < 2)
|
||||
Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n",
|
||||
bins, CELLHASHSIZE, total, (bins == 0) ? 0 :
|
||||
(float)((float)total / (float)bins));
|
||||
|
||||
OldDebug = Debug;
|
||||
Debug = full;
|
||||
RecurseHashTable(&cell_dict, PrintCellHashTableElement);
|
||||
Debug = OldDebug;
|
||||
OldDebug = Debug;
|
||||
Debug = full;
|
||||
RecurseHashTable(&cell_dict, PrintCellHashTableElement);
|
||||
Debug = OldDebug;
|
||||
#ifndef TCL_NETGEN
|
||||
if (full >= 2) Printf("\n");
|
||||
if (full >= 2) Printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
struct nlist *FirstCell(void)
|
||||
{
|
||||
return((struct nlist *)HashFirst(&cell_dict));
|
||||
return((struct nlist *)HashFirst(&cell_dict));
|
||||
}
|
||||
|
||||
struct nlist *NextCell(void)
|
||||
{
|
||||
return((struct nlist *)HashNext(&cell_dict));
|
||||
return((struct nlist *)HashNext(&cell_dict));
|
||||
}
|
||||
|
||||
static int ClearDumpedElement(struct hashlist *np)
|
||||
{
|
||||
struct nlist *p;
|
||||
struct nlist *p;
|
||||
|
||||
p = (struct nlist *)(np->ptr);
|
||||
p->dumped = 0;
|
||||
return(1);
|
||||
p = (struct nlist *)(np->ptr);
|
||||
p->dumped = 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
void ClearDumpedList(void)
|
||||
{
|
||||
RecurseHashTable(&cell_dict, ClearDumpedElement);
|
||||
RecurseHashTable(&cell_dict, ClearDumpedElement);
|
||||
}
|
||||
|
||||
int RecurseCellHashTable(int (*foo)(struct hashlist *np))
|
||||
{
|
||||
return RecurseHashTable(&cell_dict, foo);
|
||||
return RecurseHashTable(&cell_dict, foo);
|
||||
}
|
||||
|
||||
int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value)
|
||||
{
|
||||
return RecurseHashTableValue(&cell_dict, foo, value);
|
||||
return RecurseHashTableValue(&cell_dict, foo, value);
|
||||
}
|
||||
|
||||
/* Yet another version, passing one parameter that is a pointer */
|
||||
@@ -729,7 +752,7 @@ int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value)
|
||||
struct nlist *RecurseCellHashTable2(struct nlist *(*foo)(struct hashlist *,
|
||||
void *), void *pointer)
|
||||
{
|
||||
return RecurseHashTablePointer(&cell_dict, foo, pointer);
|
||||
return RecurseHashTablePointer(&cell_dict, foo, pointer);
|
||||
}
|
||||
|
||||
/************************** WILD-CARD STUFF *******************************/
|
||||
|
||||
@@ -1408,6 +1408,9 @@ skip_endmodule:
|
||||
if (tpsave != NULL) {
|
||||
struct nlist *tpplace;
|
||||
char *savename;
|
||||
int lnum, pnum, ltest;
|
||||
unsigned char valid;
|
||||
struct objlist *lobj, *pobj;
|
||||
|
||||
/* Handle a placeholder from a verilog file that has been replaced
|
||||
* by a netlist with pins in a different order. The pins need to
|
||||
@@ -1418,6 +1421,58 @@ skip_endmodule:
|
||||
Printf("Verilog placeholder module %s replaced by module definition\n",
|
||||
tpsave->name);
|
||||
tpplace = LookupCellFile("_PLACEHOLDER_", filenum);
|
||||
|
||||
/* If tpsave was generated from an instance in a SPICE netlist that
|
||||
* did not have a black-box subcircuit definition, then the pins
|
||||
* will all be labeled 1, 2, 3, etc. If so, then assume that the
|
||||
* verilog pins are in order, and rename the placeholder pins.
|
||||
* If the number of pins does not match, or if the pins are not
|
||||
* labeled as ascending integers, then leave the cell alone.
|
||||
* In either case, output a warning message.
|
||||
*/
|
||||
|
||||
/* Get the number of ports in the placeholder */
|
||||
pnum = 0;
|
||||
for (pobj = tpplace->cell; pobj; pobj = pobj->next) {
|
||||
if (pobj->type != PORT) break;
|
||||
pnum++;
|
||||
}
|
||||
|
||||
/* Get the number of ports in the saved cell and make */
|
||||
/* sure that it equals the number of ports in the */
|
||||
/* placeholder, and that all of the ports in the saved */
|
||||
/* cell are integers in ascending order. */
|
||||
|
||||
valid = TRUE;
|
||||
lnum = 0;
|
||||
for (lobj = tpsave->cell; lobj; lobj = lobj->next) {
|
||||
if (lobj->type != PORT) break;
|
||||
lnum++;
|
||||
if (sscanf(lobj->name, "%d", <est) != 1) break;
|
||||
if (ltest != lnum) break;
|
||||
}
|
||||
if ((lobj != NULL) && (lobj->type == PORT))
|
||||
valid = FALSE; /* Pins are not integers in ascending order */
|
||||
if (pnum != lnum) valid = FALSE; /* Different number of pins */
|
||||
|
||||
if (valid == TRUE) {
|
||||
Printf("Replacing pins of placeholder cell %s from cell definition.\n",
|
||||
tpsave->name);
|
||||
pobj = tpplace->cell;
|
||||
for (lobj = tpsave->cell; lobj; lobj = lobj->next) {
|
||||
if (lobj->type != PORT) break;
|
||||
if (pobj == NULL) break; /* should not happen */
|
||||
FREE(lobj->name);
|
||||
lobj->name = (char *)MALLOC(strlen(pobj->name) + 1);
|
||||
strcpy(lobj->name, pobj->name);
|
||||
pobj = pobj->next;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Printf("Placeholder pins of cell %s are not compatible and"
|
||||
" will be left unchanged\n", tpsave->name);
|
||||
}
|
||||
|
||||
/* MatchPins is part of netcmp and normally Circuit2 is the
|
||||
* circuit being matched, so set Circuit2 to the original
|
||||
* verilog black-box cell, and MatchPins() will force its
|
||||
|
||||
+14
-5
@@ -1595,8 +1595,7 @@ _netgen_model(ClientData clientData,
|
||||
return result;
|
||||
|
||||
if (objc == 3) {
|
||||
model = Tcl_GetString(objv[2]);
|
||||
nports = NumberOfPorts(model, fnum);
|
||||
nports = NumberOfPorts(tp->name, fnum);
|
||||
|
||||
if (Tcl_GetIndexFromObj(interp, objv[2], (CONST84 char **)modelclasses,
|
||||
"class", 0, &index) != TCL_OK) {
|
||||
@@ -2523,8 +2522,16 @@ _netcmp_run(ClientData clientData,
|
||||
|
||||
if (automorphisms == -1)
|
||||
Fprintf(stdout, "Netlists do not match.\n");
|
||||
else if (automorphisms == -2)
|
||||
Fprintf(stdout, "Netlists match uniquely with port errors.\n");
|
||||
else if (automorphisms == -2) {
|
||||
Fprintf(stdout, "Netlists match uniquely with port");
|
||||
if (PropertyErrorDetected) {
|
||||
Fprintf(stdout, " and property errors.\n");
|
||||
PrintPropertyResults(dolist);
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, " errors.\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (automorphisms == 0)
|
||||
Fprintf(stdout, "Netlists match uniquely");
|
||||
@@ -2652,8 +2659,10 @@ _netcmp_verify(ClientData clientData,
|
||||
disable_interrupt();
|
||||
if (index == EQUIV_IDX || index == UNIQUE_IDX)
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
|
||||
else
|
||||
else {
|
||||
Fprintf(stdout, "Netlists do not match.\n");
|
||||
Fprintf(stdout, "Port matching may fail to disambiguate symmetries.\n");
|
||||
}
|
||||
}
|
||||
else if (automorphisms == -2) {
|
||||
if (index == EQUIV_IDX)
|
||||
|
||||
Reference in New Issue
Block a user