Compare commits

...
20 Commits
Author SHA1 Message Date
Tim Edwards aaf8fefc1a Merge branch 'master' into netgen-1.5 2024-10-16 02:00:02 -04:00
Tim Edwards e1aa231db1 Corrected another error discovered by Andrei Bondar in which
the critical property (e.g., L for transistors) is required to
match exactly between devices in order to allow the additive
property (e.g., W for transistors) to be summed.  The critical
property should match if all values are within the slop value,
for floating-point values.  Note:  The implementation is still
not rigorous, as the saved critical value may shift from
device to device;  so comparing, e.g., 1.00 to 1.01 to 1.02 to
1.03, etc., can find that all individual comparisons are within
the slop value even though the slop is exceeded across all values.
2024-10-15 20:52:23 -04:00
Tim Edwards abaf896f7f Merge branch 'master' into netgen-1.5 2024-10-15 02:00:02 -04:00
Tim Edwards df8fa29b2f Fixed an issue with property matching that was preventing the last-
ditch effort of matching based on combining devices with the same
critical property (e.g., adding gate widths together for transistors
of the same gate length, if the property records remain stubbornly
mismatched to the end).  Thanks to Bondar Andrey Renatovich for
surfacing this issue and providing a reproducible example.
2024-10-14 13:24:35 -04:00
Tim Edwards e94d25b3f1 Merge branch 'master' into netgen-1.5 2024-10-08 02:00:03 -04:00
Tim Edwards d14bf70f1c Working to get some MatchPins improvements from Mitch Bailey from
a long time ago into the code.  The improvements collided with
intervening changes to the same routines and would not merge
cleanly, which is why they were never merged.  Step 1:  Show the
net name of a matching net that is missing a pin.  Remove output
of missing pins that is redundant (pin names being output twice).
2024-10-07 11:10:33 -04:00
Tim Edwards e659495ef5 Merge branch 'master' into netgen-1.5 2024-10-04 02:00:03 -04:00
Tim Edwards 5c21000a8b Made a modification to accommodate the situation where a SPICE
instance is matched to a verilog module definition, and the SPICE
instance is read before the verilog definition, forcing a
placeholder cell to be created.  Netgen will now make the
assumption that the verilog ports are in the same order as the
SPICE instance port order.  At the same time, it will output a
warning message that it is making this not-necessarily-warranted
assumption.  If the number of ports don't match or the placeholder
did not come from a SPICE instance, then the placeholder pins are
left alone.
2024-10-03 14:52:42 -04:00
Tim Edwards 2ce3cf8dd9 Merge branch 'master' into netgen-1.5 2024-10-03 02:00:02 -04:00
Tim Edwards 05872ca918 Corrected an apparently long-standing error that is responsible for
some errors failing to list in the output while also being responsible
for a number of non-errors showing up in the output.  This fix may
substantially clean up netgen output.  Also:  Added text to the
output noting that pin matching may be incorrect with respect to
symmetries if the nets have failed to match.
2024-10-02 21:20:27 -04:00
Tim Edwards 05f433f334 Merge branch 'master' into netgen-1.5 2024-10-01 02:00:02 -04:00
Tim Edwards e821381900 Corrected a rather obscure error in which an otherwise unconnected
port-to-port short (formed by "assign" in verilog or zero-valued
resistors in SPICE) does not get checked when counting nodes
before adding a proxy pin to a subcircuit in that cell, causing
the proxy pin to be assigned the same node number and forming an
unintended connection to the port-to-port connecting net.
2024-09-30 22:11:53 -04:00
Tim Edwards 2129073a38 Merge branch 'master' into netgen-1.5 2024-09-28 02:00:02 -04:00
Tim Edwards 8022e1370f Added a few lines to rebuild the node cache after removing devices
such a zero-ohm resistors or zero-volt sources during the pre-match
phase, since the list of nodes gets changed by merging nets across
the removed devices.  Otherwise, the node-name cache gets
corrupted and random LVS errors occur.
2024-09-27 10:08:37 -04:00
Tim Edwards b0d980bb7d Merge branch 'master' into netgen-1.5 2024-08-17 02:00:03 -04:00
Tim Edwards 2b88d79adc Corrected a rare case where a NULL value propagates in the flattening
routine and is not caught until it causes a segfault.
2024-08-16 19:48:36 -04:00
Tim Edwards ab0165b16c Merge branch 'master' into netgen-1.5 2024-05-17 02:00:02 -04:00
Tim Edwards bf4112db07 Corrected two statements that can cause a segfault because a
structure variable is not checked for the condition of being NULL
before attempting to read a component of the structure.  These
conditions imply that something is badly wrong in the netlist but
should not be causing a segfault.
2024-05-16 11:49:56 -04:00
Tim Edwards 5197eb6186 Merge branch 'master' into netgen-1.5 2024-05-15 02:00:01 -04:00
Tim Edwards fcee934580 Corrected the parsing of the "model" command, which was failing to
pass the right cell name to the routine which counts the number of
pins.  Using this in a setup file will prevent netgen from spending
time matching low-level devices.
2024-05-14 15:12:41 -04:00
7 changed files with 140 additions and 58 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.274
1.5.284
+28 -14
View File
@@ -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;
}
+43 -38
View File
@@ -2706,7 +2706,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 +2830,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++;
@@ -5165,26 +5169,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 +5205,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 +5253,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 +5277,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.
@@ -6246,22 +6270,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
@@ -7360,7 +7382,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;
@@ -7625,7 +7647,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (ob2->model.port == -1)
snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", ob2->name);
else
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)", ob2->name);
}
nomatch = TRUE;
/* Pins with different names are on different nets,
@@ -7680,7 +7702,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
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)");
snprintf(ostr + left_col_end + 1, left_col_end, "(no pin, node is %s)", obp->name);
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
@@ -8128,23 +8150,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;
+2 -2
View File
@@ -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);
+7
View File
@@ -224,6 +224,13 @@ int matchnocase(char *st1, char *st2)
char *sp1 = st1;
char *sp2 = st2;
/* 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;
while (*sp1 != '\0' && *sp2 != '\0') {
if (to_lower[*sp1] != to_lower[*sp2]) break;
sp1++;
+55
View File
@@ -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", &ltest) != 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
+4 -3
View File
@@ -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) {
@@ -2652,8 +2651,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)