From 38b8889550b528352c28b4c134fb3d7aca29046c Mon Sep 17 00:00:00 2001 From: "D. Mitch Bailey" Date: Tue, 21 Dec 2021 07:37:16 -0800 Subject: [PATCH 1/5] Decrease instance flattening time and added file number display to flattening message. Decreased flattening time by: 1) shifting instance node numbers in one pass instead of one pass per node. 2) quit pin renumber processing after the last pin. Added file number to flattening display message: Before: Flattening instances of dff_buf_0 in cell control_logic_r makes a better match After: Flattening instances of dff_buf_0 in cell control_logic_r(1) makes a better match --- VERSION | 2 +- base/flatten.c | 50 ++++++++++++++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/VERSION b/VERSION index 37c8b13..4e28cf4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.213 +1.5.213-F1 diff --git a/base/flatten.c b/base/flatten.c index 567862c..910856d 100644 --- a/base/flatten.c +++ b/base/flatten.c @@ -370,23 +370,30 @@ int flattenInstancesOf(char *name, int fnum, char *instance) if (ChildListEnd == NULL) ChildListEnd = ChildEnd; - /* update node numbers in child to unique numbers */ + /* update node numbers in child to unique numbers + by adding previous greatest node number. */ oldmax = 0; - for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) + for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) { if (tmp->node > oldmax) oldmax = tmp->node; - if (nextnode <= oldmax) nextnode = oldmax + 1; + if (tmp->node > 0) tmp->node += (nextnode - 1); + } + //if (nextnode <= oldmax) nextnode = oldmax + 1; + nextnode += oldmax; +/* This block is unnecessary for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) if (tmp->node <= oldmax && tmp->node > 0) { if (Debug) Printf("Update node %d --> %d\n", tmp->node, nextnode); UpdateNodeNumbers(ChildStart, tmp->node, nextnode); nextnode++; } +*/ /* copy nodenumbers of ports from parent */ ob2 = ParentParams; - for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) { - if (IsPort(tmp)) { + // Since ports are grouped at the front of the list and only ports are processed + // quit loop when non port is found + for (tmp = ChildStart; tmp && IsPort(tmp); tmp = tmp->next) { if (tmp->node > 0) { if (ob2->node == -1) { @@ -423,7 +430,6 @@ int flattenInstancesOf(char *name, int fnum, char *instance) if (ob2 != NULL) ob2 = ob2->next; if (ob2 == NULL) break; - } } /* Using name == NULL to indicate that a .ext file is being */ @@ -1607,15 +1613,15 @@ PrematchLists(char *name1, int file1, char *name2, int file2) } if (match) { if (ecomp->cell1 && (ecomp->num1 > 0)) { - Fprintf(stdout, "Flattening instances of %s in cell %s" + Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" " makes a better match\n", ecomp->cell1->name, - name1); + name1, file1); flattenInstancesOf(name1, file1, ecomp->cell1->name); } if (ecomp->cell2 && (ecomp->num2 > 0)) { - Fprintf(stdout, "Flattening instances of %s in cell %s" + Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" " makes a better match\n", ecomp->cell2->name, - name2); + name2, file2); flattenInstancesOf(name2, file2, ecomp->cell2->name); } modified++; @@ -1696,9 +1702,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2) } if (match) { if (ecomp->cell2) { - Fprintf(stdout, "Flattening instances of %s in cell %s" + Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" " makes a better match\n", ecomp->cell2->name, - name2); + name2, file2); flattenInstancesOf(name2, file2, ecomp->cell2->name); } modified++; @@ -1754,9 +1760,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2) } if (match) { if (ecomp->cell1) { - Fprintf(stdout, "Flattening instances of %s in cell %s" + Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" " makes a better match\n", ecomp->cell1->name, - name1); + name1, file1); flattenInstancesOf(name1, file1, ecomp->cell1->name); } modified++; @@ -1837,9 +1843,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2) } if (found) { Fprintf(stdout, "Removing zero-valued device " - "%s from cell %s makes a better match\n", + "%s from cell %s(%d) makes a better match\n", tsub1->name, - tc1->name); + tc1->name, tc1->file); /* A current source is an open, while a */ /* resistor or voltage source is a short. */ @@ -1948,9 +1954,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2) } if (found) { Fprintf(stdout, "Removing zero-valued device " - "%s from cell %s makes a better match\n", + "%s from cell %s(%d) makes a better match\n", tsub2->name, - tc2->name); + tc2->name, tc2->file); /* merge node of endpoints */ if (ecomp->cell2->class != CLASS_ISOURCE) { @@ -2040,9 +2046,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2) ecompX0->cell1->file, &compdict); if (dstr) *dstr = '['; if ((ncomp == ecomp0X) && (ecomp0X->num2 <= ecompX0->num1)) { - Fprintf(stdout, "Flattening instances of %s in cell %s" + Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" " makes a better match\n", ecompX0->cell1->name, - name1); + name1, file1); flattenInstancesOf(name1, file1, ecompX0->cell1->name); ecompX0->num1 = 0; ecomp0X->num1 += ecompX0->num1; @@ -2066,9 +2072,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2) ecomp0X->cell2->file, &compdict); if (dstr) *dstr = '['; if ((ncomp == ecompX0) && (ecompX0->num1 <= ecomp0X->num2)) { - Fprintf(stdout, "Flattening instances of %s in cell %s" + Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" " makes a better match\n", ecomp0X->cell2->name, - name2); + name2, file2); flattenInstancesOf(name2, file2, ecomp0X->cell2->name); ecomp0X->num2 = 0; ecompX0->num2 += ecomp0X->num2; From e771c30d3ed6b1df245ed694db7ea6f6b37ec790 Mon Sep 17 00:00:00 2001 From: "D. Mitch Bailey" Date: Thu, 30 Dec 2021 17:05:46 -0800 Subject: [PATCH 2/5] noflatten list processing fix and cosmetic changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed ‘noflatten' processing to correctly handle list of cells. stdout and log changes. Changed tab to space in case related message. (stdout) Standardized single cell name output to include file number. cellname -> cellname(1) (stdout/log) Standardized black-box. “black box” -> “black-box” (log) Separated black box messages from surrounding circuits. (stdout/log) Removed ‘“‘ from file number display in failed matching list. DFFRAM¥”(0)¥” -> DFFRAM(0) (stdout/log) Removed extraneous “Equate pins … has no elements”. (log) --- base/flatten.c | 14 +++++++------- base/netcmp.c | 14 +++++++------- base/verilog.c | 2 +- tcltk/netgen.tcl.in | 10 +++++----- tcltk/tclnetgen.c | 22 ++++++++++++++-------- 5 files changed, 34 insertions(+), 28 deletions(-) diff --git a/base/flatten.c b/base/flatten.c index 910856d..b54b463 100644 --- a/base/flatten.c +++ b/base/flatten.c @@ -66,7 +66,7 @@ void flattenCell(char *name, int file) else ThisCell = LookupCellFile(name, file); if (ThisCell == NULL) { - Printf("No cell %s found.\n", name); + Printf("No cell %s(%d) found.\n", name, file); return; } FreeNodeNames(ThisCell); @@ -278,13 +278,13 @@ int flattenInstancesOf(char *name, int fnum, char *instance) } else { if (Debug) - Printf("Flattening instances of %s within cell: %s\n", instance, name); + Printf("Flattening instances of %s within cell: %s(%d)\n", instance, name, fnum); if (fnum == -1) ThisCell = LookupCell(name); else ThisCell = LookupCellFile(name, fnum); if (ThisCell == NULL) { - Printf("No cell %s found.\n", name); + Printf("No cell %s(%d) found.\n", name, fnum); return 0; } } @@ -694,7 +694,7 @@ void convertGlobalsOf(char *name, int fnum, char *instance) else ThisCell = LookupCellFile(name, fnum); if (ThisCell == NULL) { - Printf("No cell %s found.\n", name); + Printf("No cell %s(%d) found.\n", name, fnum); return; } } @@ -1124,7 +1124,7 @@ int UniquePins(char *name, int filenum) ThisCell = LookupCellFile(name, filenum); if (ThisCell == NULL) { - Printf("No cell %s found.\n", name); + Printf("No cell %s(%d) found.\n", name, filenum); return 0; } @@ -1146,7 +1146,7 @@ int UniquePins(char *name, int filenum) if (ob->node > 0) { nodecount[ob->node]++; if (nodecount[ob->node] == 2) { - Printf("Duplicate pin %s in cell %s\n", ob->name, ThisCell->name); + Printf("Duplicate pin %s in cell %s(%d)\n", ob->name, ThisCell->name, filenum); } if (nodecount[ob->node] > 1) { /* Remove this node; prep for removal by marking with UNKNOWN */ @@ -1345,7 +1345,7 @@ int CleanupPins(char *name, int filenum) ThisCell = LookupCellFile(name, filenum); if (ThisCell == NULL) { - Printf("No cell %s found.\n", name); + Printf("No cell %s(%d) found.\n", name, filenum); return 0; } diff --git a/base/netcmp.c b/base/netcmp.c index 9b7456d..a1a1ff3 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -3457,7 +3457,7 @@ int FlattenUnmatched(struct nlist *tc, char *parent, int stoplevel, int loclevel if (loclevel == stoplevel && !(tc->flags & CELL_MATCHED)) { ClearDumpedList(); if (Debug == TRUE) Fprintf(stdout, "Level %d ", loclevel); - Fprintf(stdout, "Flattening unmatched subcell %s in circuit %s (%d)", + Fprintf(stdout, "Flattening unmatched subcell %s in circuit %s(%d)", tc->name, parent, tc->file); changed = flattenInstancesOf(parent, tc->file, tc->name); Fprintf(stdout, "(%d instance%s)\n", changed, ((changed == 1) ? "" : "s")); @@ -3810,11 +3810,11 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist) modified = CreateLists(name1, file1); if (Elements == NULL) { - Printf("Circuit %s contains no devices.\n", name1); + Printf("\nCircuit %s(%d) contains no devices. Compared as black-box.\n", name1, file1); return; } if (Nodes == NULL) { - Printf("Circuit %s contains no nets.\n", name1); + Printf("\nCircuit %s(%d) contains no nets. Compared as black-box.\n", name1, file1); return; } @@ -3855,13 +3855,13 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist) modified += CreateLists(name2, file2); if (Elements == NULL) { - Printf("Circuit %s contains no devices.\n", name2); + Printf("\nCircuit %s(%d) contains no devices. Compared as black-box.\n", name2, file2); ResetState(); return; } if (Nodes == NULL) { - Printf("Circuit %s contains no nets.\n", name2); + Printf("\nCircuit %s(%d) contains no nets. Compared as black-box.\n", name2, file2); ResetState(); return; } @@ -7885,10 +7885,10 @@ int EquivalentElement(char *name, struct nlist *circuit, struct objlist **retobj void FlattenCurrent() { if (Circuit1 != NULL && Circuit2 != NULL) { - Fprintf(stdout, "Flattening subcell %s\n", Circuit1->name); + Fprintf(stdout, "Flattening subcell %s(%d)\n", Circuit1->name, Circuit1->file); FlattenInstancesOf(Circuit1->name, Circuit1->file); - Fprintf(stdout, "Flattening subcell %s\n", Circuit2->name); + Fprintf(stdout, "Flattening subcell %s(%d)\n", Circuit2->name, Circuit2->file); FlattenInstancesOf(Circuit2->name, Circuit2->file); } } diff --git a/base/verilog.c b/base/verilog.c index b8d8b11..a244772 100644 --- a/base/verilog.c +++ b/base/verilog.c @@ -2233,7 +2233,7 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox) /* be case insensitive, with a stern warning. */ if (matchfunc == matchnocase) { - Printf("Warning: A case-insensitive file has been read and so the " + Printf("Warning: A case-insensitive file has been read and so the " "verilog file must be treated case-insensitive to match.\n"); } else { diff --git a/tcltk/netgen.tcl.in b/tcltk/netgen.tcl.in index f63364f..440a733 100644 --- a/tcltk/netgen.tcl.in +++ b/tcltk/netgen.tcl.in @@ -393,7 +393,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { # If argument is a filename then read the list of cells from it; # otherwise, argument is the list of files itself in quotes or # braces. - if {![catch {file exists $value}]} { + if {![catch {file exists $value}] && [file exists $value]} { if {![catch {open $value r} fnf]} { while {[gets $fnf line] >= 0} { if {[lindex $line 0] != "#"} { @@ -567,8 +567,8 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { netgen::flatten class "[lindex $endval 1] $fnum2" } else { netgen::log put " Continuing with black-boxed subcircuits $endval\n" - lappend matcherr [lindex $endval 0]"($fnum1)" - lappend matcherr [lindex $endval 1]"($fnum2)" + lappend matcherr [lindex $endval 0]($fnum1) + lappend matcherr [lindex $endval 1]($fnum2) # Match pins netgen::log echo off if {$dolist == 1} { @@ -617,8 +617,8 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { netgen::flatten class "[lindex $endval 1] $fnum2" } else { netgen::log put " Continuing with black-boxed subcircuits $endval\n" - lappend matcherr [lindex $endval 0]"($fnum1)" - lappend matcherr [lindex $endval 0]"($fnum2)" + lappend matcherr [lindex $endval 0]($fnum1) + lappend matcherr [lindex $endval 0]($fnum2) # Match pins netgen::log echo off if {$dolist == 1} { diff --git a/tcltk/tclnetgen.c b/tcltk/tclnetgen.c index f6c573c..4e0c43f 100644 --- a/tcltk/tclnetgen.c +++ b/tcltk/tclnetgen.c @@ -2203,11 +2203,11 @@ _netcmp_compare(ClientData clientData, hascontents2 = HasContents(tp2); if (hascontents1 && !hascontents2 && (tp2->flags & CELL_PLACEHOLDER)) { - Fprintf(stdout, "Circuit 2 cell %s is a black box; will not flatten " + Fprintf(stdout, "\nCircuit 2 cell %s is a black-box; will not flatten " "Circuit 1\n", name2); } else if (hascontents2 && !hascontents1 && (tp1->flags & CELL_PLACEHOLDER)) { - Fprintf(stdout, "Circuit 1 cell %s is a black box; will not flatten " + Fprintf(stdout, "\nCircuit 1 cell %s is a black-box; will not flatten " "Circuit 2\n", name1); } else if (hascontents1 || hascontents2) { @@ -2223,6 +2223,10 @@ _netcmp_compare(ClientData clientData, DescribeContents(name1, fnum1, name2, fnum2); } } + else { // two empty subcircuits + Fprintf(stdout, "\nCircuit 1 cell %s and Circuit 2 cell %s are black-boxes.\n", + name1, name2); + } CreateTwoLists(name1, fnum1, name2, fnum2, dolist); // Return the names of the two cells being compared, if doing "compare @@ -3054,19 +3058,21 @@ _netcmp_equate(ClientData clientData, else if ((tp1->flags & CELL_PLACEHOLDER) || (tp2->flags & CELL_PLACEHOLDER)) { if (tp1->flags & CELL_PLACEHOLDER) { - Fprintf(stdout, "Warning: Equate pins: cell %s " - "is a placeholder, treated as a black box.\n", name1); + Fprintf(stdout, "Warning: Equate pins: cell %s(%d) " + "is a placeholder, treated as a black-box.\n", name1, file1); } if (tp2->flags & CELL_PLACEHOLDER) { - Fprintf(stdout, "Warning: Equate pins: cell %s " - "is a placeholder, treated as a black box.\n", name2); + Fprintf(stdout, "Warning: Equate pins: cell %s(%d) " + "is a placeholder, treated as a black-box.\n", name2, file2); } // If a cell in either circuit is marked as a black box, then // the cells in both circuits should be marked as a black box. tp1->flags |= CELL_PLACEHOLDER; tp2->flags |= CELL_PLACEHOLDER; } - else { + else if (doforce != TRUE) { + // when doforce is true, ElementClass has been set to NULL even though circuits contain elements. + // so this message is not correct. Fprintf(stdout, "Equate pins: cell %s and/or %s " "has no elements.\n", name1, name2); /* This is not necessarily an error, so go ahead and match pins. */ @@ -3124,7 +3130,7 @@ _netcmp_equate(ClientData clientData, /* Objects must be CLASS_MODULE or CLASS_SUBCKT */ if (tp1->class != CLASS_MODULE && tp1->class != CLASS_SUBCKT) { - Tcl_SetResult(interp, "Device class is not black box" + Tcl_SetResult(interp, "Device class is not black-box" " or subcircuit!", NULL); return TCL_ERROR; } From 0e6b6e1b5b06bf4036c6d83771d6df786dadac46 Mon Sep 17 00:00:00 2001 From: "D. Mitch Bailey" Date: Sun, 2 Jan 2022 08:26:13 -0800 Subject: [PATCH 3/5] Cosmetic changes Standardized "cell(file)" output to "cell (file)" --- base/flatten.c | 32 ++++++++++++++++---------------- base/netcmp.c | 14 +++++++------- tcltk/netgen.tcl.in | 8 ++++---- tcltk/tclnetgen.c | 4 ++-- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/base/flatten.c b/base/flatten.c index b54b463..9df6cbc 100644 --- a/base/flatten.c +++ b/base/flatten.c @@ -66,7 +66,7 @@ void flattenCell(char *name, int file) else ThisCell = LookupCellFile(name, file); if (ThisCell == NULL) { - Printf("No cell %s(%d) found.\n", name, file); + Printf("No cell %s (%d) found.\n", name, file); return; } FreeNodeNames(ThisCell); @@ -278,13 +278,13 @@ int flattenInstancesOf(char *name, int fnum, char *instance) } else { if (Debug) - Printf("Flattening instances of %s within cell: %s(%d)\n", instance, name, fnum); + Printf("Flattening instances of %s within cell: %s (%d)\n", instance, name, fnum); if (fnum == -1) ThisCell = LookupCell(name); else ThisCell = LookupCellFile(name, fnum); if (ThisCell == NULL) { - Printf("No cell %s(%d) found.\n", name, fnum); + Printf("No cell %s (%d) found.\n", name, fnum); return 0; } } @@ -370,7 +370,7 @@ int flattenInstancesOf(char *name, int fnum, char *instance) if (ChildListEnd == NULL) ChildListEnd = ChildEnd; - /* update node numbers in child to unique numbers + /* update node numbers in child to unique numbers by adding previous greatest node number. */ oldmax = 0; for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) { @@ -694,7 +694,7 @@ void convertGlobalsOf(char *name, int fnum, char *instance) else ThisCell = LookupCellFile(name, fnum); if (ThisCell == NULL) { - Printf("No cell %s(%d) found.\n", name, fnum); + Printf("No cell %s (%d) found.\n", name, fnum); return; } } @@ -1124,7 +1124,7 @@ int UniquePins(char *name, int filenum) ThisCell = LookupCellFile(name, filenum); if (ThisCell == NULL) { - Printf("No cell %s(%d) found.\n", name, filenum); + Printf("No cell %s (%d) found.\n", name, filenum); return 0; } @@ -1146,7 +1146,7 @@ int UniquePins(char *name, int filenum) if (ob->node > 0) { nodecount[ob->node]++; if (nodecount[ob->node] == 2) { - Printf("Duplicate pin %s in cell %s(%d)\n", ob->name, ThisCell->name, filenum); + Printf("Duplicate pin %s in cell %s (%d)\n", ob->name, ThisCell->name, filenum); } if (nodecount[ob->node] > 1) { /* Remove this node; prep for removal by marking with UNKNOWN */ @@ -1345,7 +1345,7 @@ int CleanupPins(char *name, int filenum) ThisCell = LookupCellFile(name, filenum); if (ThisCell == NULL) { - Printf("No cell %s(%d) found.\n", name, filenum); + Printf("No cell %s (%d) found.\n", name, filenum); return 0; } @@ -1613,13 +1613,13 @@ PrematchLists(char *name1, int file1, char *name2, int file2) } if (match) { if (ecomp->cell1 && (ecomp->num1 > 0)) { - Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" + Fprintf(stdout, "Flattening instances of %s in cell %s (%d)" " makes a better match\n", ecomp->cell1->name, name1, file1); flattenInstancesOf(name1, file1, ecomp->cell1->name); } if (ecomp->cell2 && (ecomp->num2 > 0)) { - Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" + Fprintf(stdout, "Flattening instances of %s in cell %s (%d)" " makes a better match\n", ecomp->cell2->name, name2, file2); flattenInstancesOf(name2, file2, ecomp->cell2->name); @@ -1702,7 +1702,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2) } if (match) { if (ecomp->cell2) { - Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" + Fprintf(stdout, "Flattening instances of %s in cell %s (%d)" " makes a better match\n", ecomp->cell2->name, name2, file2); flattenInstancesOf(name2, file2, ecomp->cell2->name); @@ -1760,7 +1760,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2) } if (match) { if (ecomp->cell1) { - Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" + Fprintf(stdout, "Flattening instances of %s in cell %s (%d)" " makes a better match\n", ecomp->cell1->name, name1, file1); flattenInstancesOf(name1, file1, ecomp->cell1->name); @@ -1843,7 +1843,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2) } if (found) { Fprintf(stdout, "Removing zero-valued device " - "%s from cell %s(%d) makes a better match\n", + "%s from cell %s (%d) makes a better match\n", tsub1->name, tc1->name, tc1->file); @@ -1954,7 +1954,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2) } if (found) { Fprintf(stdout, "Removing zero-valued device " - "%s from cell %s(%d) makes a better match\n", + "%s from cell %s (%d) makes a better match\n", tsub2->name, tc2->name, tc2->file); @@ -2046,7 +2046,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2) ecompX0->cell1->file, &compdict); if (dstr) *dstr = '['; if ((ncomp == ecomp0X) && (ecomp0X->num2 <= ecompX0->num1)) { - Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" + Fprintf(stdout, "Flattening instances of %s in cell %s (%d)" " makes a better match\n", ecompX0->cell1->name, name1, file1); flattenInstancesOf(name1, file1, ecompX0->cell1->name); @@ -2072,7 +2072,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2) ecomp0X->cell2->file, &compdict); if (dstr) *dstr = '['; if ((ncomp == ecompX0) && (ecompX0->num1 <= ecomp0X->num2)) { - Fprintf(stdout, "Flattening instances of %s in cell %s(%d)" + Fprintf(stdout, "Flattening instances of %s in cell %s (%d)" " makes a better match\n", ecomp0X->cell2->name, name2, file2); flattenInstancesOf(name2, file2, ecomp0X->cell2->name); diff --git a/base/netcmp.c b/base/netcmp.c index a1a1ff3..e8a8939 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -3457,7 +3457,7 @@ int FlattenUnmatched(struct nlist *tc, char *parent, int stoplevel, int loclevel if (loclevel == stoplevel && !(tc->flags & CELL_MATCHED)) { ClearDumpedList(); if (Debug == TRUE) Fprintf(stdout, "Level %d ", loclevel); - Fprintf(stdout, "Flattening unmatched subcell %s in circuit %s(%d)", + Fprintf(stdout, "Flattening unmatched subcell %s in circuit %s (%d)", tc->name, parent, tc->file); changed = flattenInstancesOf(parent, tc->file, tc->name); Fprintf(stdout, "(%d instance%s)\n", changed, ((changed == 1) ? "" : "s")); @@ -3810,11 +3810,11 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist) modified = CreateLists(name1, file1); if (Elements == NULL) { - Printf("\nCircuit %s(%d) contains no devices. Compared as black-box.\n", name1, file1); + Printf("\nCircuit %s (%d) contains no devices. Compared as black-box.\n", name1, file1); return; } if (Nodes == NULL) { - Printf("\nCircuit %s(%d) contains no nets. Compared as black-box.\n", name1, file1); + Printf("\nCircuit %s (%d) contains no nets. Compared as black-box.\n", name1, file1); return; } @@ -3855,13 +3855,13 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist) modified += CreateLists(name2, file2); if (Elements == NULL) { - Printf("\nCircuit %s(%d) contains no devices. Compared as black-box.\n", name2, file2); + Printf("\nCircuit %s (%d) contains no devices. Compared as black-box.\n", name2, file2); ResetState(); return; } if (Nodes == NULL) { - Printf("\nCircuit %s(%d) contains no nets. Compared as black-box.\n", name2, file2); + Printf("\nCircuit %s (%d) contains no nets. Compared as black-box.\n", name2, file2); ResetState(); return; } @@ -7885,10 +7885,10 @@ int EquivalentElement(char *name, struct nlist *circuit, struct objlist **retobj void FlattenCurrent() { if (Circuit1 != NULL && Circuit2 != NULL) { - Fprintf(stdout, "Flattening subcell %s(%d)\n", Circuit1->name, Circuit1->file); + Fprintf(stdout, "Flattening subcell %s (%d)\n", Circuit1->name, Circuit1->file); FlattenInstancesOf(Circuit1->name, Circuit1->file); - Fprintf(stdout, "Flattening subcell %s(%d)\n", Circuit2->name, Circuit2->file); + Fprintf(stdout, "Flattening subcell %s (%d)\n", Circuit2->name, Circuit2->file); FlattenInstancesOf(Circuit2->name, Circuit2->file); } } diff --git a/tcltk/netgen.tcl.in b/tcltk/netgen.tcl.in index 440a733..2270ec5 100644 --- a/tcltk/netgen.tcl.in +++ b/tcltk/netgen.tcl.in @@ -567,8 +567,8 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { netgen::flatten class "[lindex $endval 1] $fnum2" } else { netgen::log put " Continuing with black-boxed subcircuits $endval\n" - lappend matcherr [lindex $endval 0]($fnum1) - lappend matcherr [lindex $endval 1]($fnum2) + lappend matcherr [lindex $endval 0] ($fnum1) + lappend matcherr [lindex $endval 1] ($fnum2) # Match pins netgen::log echo off if {$dolist == 1} { @@ -617,8 +617,8 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { netgen::flatten class "[lindex $endval 1] $fnum2" } else { netgen::log put " Continuing with black-boxed subcircuits $endval\n" - lappend matcherr [lindex $endval 0]($fnum1) - lappend matcherr [lindex $endval 0]($fnum2) + lappend matcherr [lindex $endval 0] ($fnum1) + lappend matcherr [lindex $endval 0] ($fnum2) # Match pins netgen::log echo off if {$dolist == 1} { diff --git a/tcltk/tclnetgen.c b/tcltk/tclnetgen.c index 4e0c43f..83f41fb 100644 --- a/tcltk/tclnetgen.c +++ b/tcltk/tclnetgen.c @@ -3058,11 +3058,11 @@ _netcmp_equate(ClientData clientData, else if ((tp1->flags & CELL_PLACEHOLDER) || (tp2->flags & CELL_PLACEHOLDER)) { if (tp1->flags & CELL_PLACEHOLDER) { - Fprintf(stdout, "Warning: Equate pins: cell %s(%d) " + Fprintf(stdout, "Warning: Equate pins: cell %s (%d) " "is a placeholder, treated as a black-box.\n", name1, file1); } if (tp2->flags & CELL_PLACEHOLDER) { - Fprintf(stdout, "Warning: Equate pins: cell %s(%d) " + Fprintf(stdout, "Warning: Equate pins: cell %s (%d) " "is a placeholder, treated as a black-box.\n", name2, file2); } // If a cell in either circuit is marked as a black box, then From 00b3292dcca995944b2a9a183fefb3544776cad4 Mon Sep 17 00:00:00 2001 From: "D. Mitch Bailey" Date: Wed, 16 Mar 2022 16:42:00 -0700 Subject: [PATCH 4/5] Changed pin matching logic. Flatten if pin mismatches. Standardized file number printing. Include improved parallel property combination and flattening. --- VERSION | 2 +- base/netcmp.c | 656 +++++++++++++++++++++++--------------------- base/netgen.c | 54 ++-- tcltk/netgen.tcl.in | 266 ++++++++++++------ tcltk/tclnetgen.c | 87 +++++- 5 files changed, 634 insertions(+), 431 deletions(-) diff --git a/VERSION b/VERSION index 4ddfe6b..ff2d7ab 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.215 +1.5.215-P1 diff --git a/base/netcmp.c b/base/netcmp.c index e8a8939..062c585 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -3122,6 +3122,47 @@ struct nlist *LookupPrematchedClass(struct nlist *tc1, int file2) return tc2; } +/*----------------------------------------------------------------------*/ +/* Scan the property list of a device to find the number of devices */ +/* implied by the total of M records. If the device does not have a */ +/* property list, then return 1. If any property list does not have an */ +/* "M" record, treat it as 1. */ +/*----------------------------------------------------------------------*/ + +int GetNumDevices(struct objlist *ob) +{ + int p, found, M = 0; + struct objlist *obs; + struct valuelist *vl; + + obs = ob; + if (obs->type != PROPERTY) + for (obs = ob->next; obs && (obs->type != FIRSTPIN) && + (obs->type != PROPERTY); obs = obs->next); + + if ((obs == NULL) || (obs->type != PROPERTY)) return 1; + + while (obs && (obs->type == PROPERTY)) { + found = FALSE; + for (p = 0; ; p++) { + vl = &obs->instance.props[p]; + if (vl->type == PROP_ENDLIST) break; + if (vl->key == NULL) continue; + if ((*matchfunc)(vl->key, "M")) { + if (vl->type == PROP_DOUBLE) + M += (int)vl->value.dval; + else + M += vl->value.ival; + found = TRUE; + break; + } + } + if (found == FALSE) M++; + obs = obs->next; + } + return M; +} + /*----------------------------------------------------------------------*/ /* Attempt to define FirstElementPass that will generate element */ /* classes by names of pins, which will allow elements with different */ @@ -3143,7 +3184,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist) struct Element *Esrch, *Ecorr; struct NodeList *n; struct nlist *tp1, *tp2, *tp; - int C1, C2, i; + int C1, C2, M1, M2, i; char *ostr; int needflat = 0; #ifdef TCL_NETGEN @@ -3184,6 +3225,8 @@ int FirstElementPass(struct Element *E, int noflat, int dolist) Esrch->hashval = 1; C1 = 1; C2 = 0; + M2 = 0; + M1 = GetNumDevices(Esrch->object); tp1 = LookupCellFile(Esrch->object->model.class, Circuit1->file); tp2 = LookupClassEquivalent(Esrch->object->model.class, Circuit1->file, Circuit2->file); @@ -3195,6 +3238,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist) if (tp && tp2 && (tp->classhash == tp2->classhash)) { Ecorr->hashval = 1; C2++; + M2 += GetNumDevices(Ecorr->object); } } else if (Ecorr->graph == Circuit1->file) { @@ -3203,6 +3247,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist) if (tp && tp1 && (tp->classhash == tp1->classhash)) { Ecorr->hashval = 1; C1++; + M1 += GetNumDevices(Ecorr->object); } } } @@ -3219,10 +3264,19 @@ int FirstElementPass(struct Element *E, int noflat, int dolist) 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, "%s (%d)", Esrch->object->model.class, C1); - if (C2 > 0) - snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)%s", tp2->name, C2, - (C2 == C1) ? "" : " **Mismatch**"); + if (M1 == C1) + snprintf(ostr, left_col_end, "%s (%d)", Esrch->object->model.class, C1); + else + snprintf(ostr, left_col_end, "%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, + C2, (C2 == C1) ? "" : " **Mismatch**"); + else + snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d->%d)%s", + tp2->name, M2, C2, (C2 == C1) ? "" : " **Mismatch**"); + } else { snprintf(ostr + left_col_end + 1, left_col_end, "(no matching element)"); } @@ -3261,6 +3315,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist) if (Esrch->graph == Circuit2->file && Esrch->hashval == 0) { Esrch->hashval = 1; C2 = 1; + M2 = GetNumDevices(Esrch->object); tp2 = LookupCellFile(Esrch->object->model.class, Circuit2->file); tp1 = LookupClassEquivalent(Esrch->object->model.class, Circuit2->file, Circuit1->file); @@ -3272,6 +3327,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist) if (tp->classhash == tp2->classhash) { Ecorr->hashval = 1; C2++; + M2 += GetNumDevices(Ecorr->object); } } } @@ -3287,7 +3343,12 @@ int FirstElementPass(struct Element *E, int noflat, int dolist) 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)"); - snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)", Esrch->object->model.class, C2); + if (C2 == M2) + snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)", + Esrch->object->model.class, C2); + else + snprintf(ostr + left_col_end + 1, left_col_end, "%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); } @@ -4860,6 +4921,7 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series, // Now combine records with same properties by summing M (S). if (comb == FALSE) { for (i = 0; i < run - 1; i++) { + int nr_empty = 0; for (j = i + 1; j < run; j++) { pmatch = 0; for (p = 1; p < pcount; p++) { @@ -4983,8 +5045,14 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series, vlist[0][i]->value.ival += vlist[0][j]->value.ival; vlist[0][j]->value.ival = 0; } + else + nr_empty++; } } + // If everything from i to the end of the run has been matched + // and zeroed out, then nothing more can be merged. + if (nr_empty == (run - (i + 1))) + break; } } @@ -6113,7 +6181,8 @@ void PrintPropertyResults(int do_list) /*----------------------------------------------------------------------*/ /* Return 0 if perfect matching found, else return number of */ -/* automorphisms, and return -1 if invalid matching found. */ +/* automorphisms, and return -1 if invalid matching found, */ +/* return -2 if port count mismatch. */ /*----------------------------------------------------------------------*/ int VerifyMatching(void) @@ -6124,6 +6193,8 @@ int VerifyMatching(void) struct Element *E; struct Node *N; int C1, C2, result; + int P1, P2; + struct objlist *ob1, *ob2; if (BadMatchDetected) return(-1); @@ -6144,14 +6215,39 @@ int VerifyMatching(void) } } + int portMismatch = 0; + P1 = P2 = 0; for (NC = NodeClasses; NC != NULL; NC = NC->next) { C1 = C2 = 0; for (N = NC->nodes; N != NULL; N = N->next) { (N->graph == Circuit1->file) ? C1++ : C2++; + if (IsPort(N->object)) (N->graph == Circuit1->file) ? P1++ : P2++; } if (C1 != C2) return(-1); + if (P1 != P2) portMismatch = 1; // portCounts should match for each NodeClass if (C1 != 1) ret++; } + + P1 = P2 = 0; + if (ret == 0 ) { // automorphisms have precedence over port count mismatches + if (portMismatch) return(-2); + // Count ports in each circuit including disconnected ports + for (ob1 = Circuit1->cell; ob1 && IsPort(ob1); ob1 = ob1->next, P1++); + for (ob2 = Circuit2->cell; ob2 && IsPort(ob2); ob2 = ob2->next, P2++); + if (P1 == P2) { // pin counts match. Make sure disconnected pins match too. + for (ob1 = Circuit1->cell; ob1 && IsPort(ob1); ob1 = ob1->next) { + if (ob1->node == -1) { // disconnected pin + for (ob2 = Circuit2->cell; ob2 && IsPort(ob2); ob2 = ob2->next) { + if (ob2->node == -1 && strcmp(ob1->name, ob2->name) == 0) break; // disconnected pin match + } + if (ob2 == NULL) return(-2); // disconnected node mismatch + } + } + } else { // pin count mismatch + //Fprintf(stdout, "DEBUG: port mismatch %d %d\n", P1, P2); + return(-2); // Port count mismatch cause flattening + } + } return(ret); } @@ -6250,7 +6346,7 @@ int ResolveAutomorphsByPin() FractureElementClass(&ElementClasses); FractureNodeClass(&NodeClasses); ExhaustiveSubdivision = 1; - while (!Iterate() && VerifyMatching() != -1); + while (!Iterate() && VerifyMatching() >= 0); return(VerifyMatching()); } @@ -6353,7 +6449,7 @@ int ResolveAutomorphsByProperty() FractureElementClass(&ElementClasses); FractureNodeClass(&NodeClasses); ExhaustiveSubdivision = 1; - while (!Iterate() && VerifyMatching() != -1); + while (!Iterate() && VerifyMatching() >= 0); return(VerifyMatching()); } @@ -6430,7 +6526,7 @@ int ResolveAutomorphisms() FractureElementClass(&ElementClasses); FractureNodeClass(&NodeClasses); ExhaustiveSubdivision = 1; - while (!Iterate() && VerifyMatching() != -1); + while (!Iterate() && VerifyMatching() >= 0); return(VerifyMatching()); } @@ -7142,6 +7238,7 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata) /* circuit pair that has not been matched. If a */ /* circuit pair has been matched with automorphisms, */ /* then some pins may be matched arbitrarily. */ +/* Modified to handle unmatched circuit pairs */ /* */ /* If "dolist" is 1, append the list representing the */ /* output (if any) to variable tcl_out, if it exists. */ @@ -7149,17 +7246,18 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata) /* Return codes: */ /* 2: Neither cell had pins, so matching is unnecessary */ /* 1: Exact match */ -/* 0: Inexact match resolved by proxy pin insertion */ +/* 0: Circuit match, but pin name mismatch. Force match.*/ +/* -1: Pin mismatch. Flatten cell. */ /*------------------------------------------------------*/ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) { - char *cover, *ctemp; + char *cover1, *cover2, *ctemp; char *bangptr1, *bangptr2; struct objlist *ob1, *ob2, *obn, *obp, *ob1s, *ob2s, *obt; struct NodeClass *NC; struct Node *N1, *N2; - int i, j, k, m, a, b, swapped, numnodes, numorig; + int i, j, k, m, a, b, swapped, numnodes, numnodes2, numorig; int result = 1, haspins = 0, notempty = 0; int hasproxy1 = 0, hasproxy2 = 0; int needclean1 = 0, needclean2 = 0; @@ -7171,10 +7269,12 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) if (tc1 == NULL) tc1 = Circuit1; if (tc2 == NULL) tc2 = Circuit2; + numnodes2 = 0; for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) { if (ob2->type != PORT) break; else haspins = 1; ob2->model.port = -1; + numnodes2++; } numnodes = 0; for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next) { @@ -7189,7 +7289,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) return 2; } - cover = (char *)CALLOC(numnodes, sizeof(char)); + cover1 = (char *)CALLOC(numnodes, sizeof(char)); + cover2 = (char *)CALLOC(numnodes2, sizeof(char)); numorig = numnodes; #ifdef TCL_NETGEN @@ -7222,161 +7323,152 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) } for (NC = NodeClasses; NC != NULL; NC = NC->next) { - a = 0; + a = 0; // circuit1 node offset for (N1 = NC->nodes; N1 != NULL; N1 = N1->next) { if (N1->graph == Circuit1->file) { - obn = N1->object; - if (IsPort(obn)) { - i = 0; - for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next, i++) { - if ((IsPort(ob1)) - && (*matchfunc)(ob1->name, obn->name)) { - b = 0; - for (N2 = NC->nodes; N2 != NULL; N2 = N2->next) { - if (N2->graph != Circuit1->file) { - if (b == a) break; - else b++; - } - } - if (N2 == NULL) { -#ifdef TCL_NETGEN - if (dolist) { - Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, - Tcl_NewStringObj("pins", -1), - TCL_APPEND_VALUE | TCL_LIST_ELEMENT); - Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, mlist, - TCL_APPEND_VALUE | TCL_LIST_ELEMENT); - } -#endif - FREE(ostr); - return 1; - } + obn = N1->object; + b = 0; // circuit2 node offset + for (N2 = NC->nodes; N2 != NULL; N2 = N2->next) { + if (N2->graph != Circuit1->file) { + if (b == a) break; + else b++; + } + } + //Fprintf(stdout, "DEBUG: port match %s - %s\n", obn->name, (N2) ? N2->object->name : ""); - obp = N2->object; - j = 0; - for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next, j++) { - if ((IsPort(ob2)) - && (*matchfunc)(ob2->name, obp->name)) { - 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); - if ((*matchfunc)(obn->name, obp->name)) - snprintf(ostr + left_col_end + 1, left_col_end, "%s", obp->name); - else { - snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", obp->name); - /* Pins with different names are on different nets, - * so this should trigger an error return code. - */ - result = 0; - } - for (m = 0; m < right_col_end + 1; m++) - if (*(ostr + m) == '\0') *(ostr + m) = ' '; - Fprintf(stdout, ostr); - } - else { - Fprintf(stdout, "Circuit %s port %d \"%s\"" - " = cell %s port %d \"%s\"\n", - tc1->name, i, obn->name, - tc2->name, j, obp->name); - } + if (N2 == NULL) { // This should never occur in matched nets + continue; + /* #ifdef TCL_NETGEN - if (dolist) { - Tcl_ListObjAppendElement(netgeninterp, plist1, - Tcl_NewStringObj(obn->name, -1)); - Tcl_ListObjAppendElement(netgeninterp, plist2, - Tcl_NewStringObj(obp->name, -1)); - } -#endif - ob2->model.port = i; /* save order */ - *(cover + i) = (char)1; - break; - } - } - if (ob2 == NULL) { - if (Debug == 0) { - // If first cell has no pins but 2nd cell - // does, then "no matching pin" entries will - // be generated for all pins in the 2nd cell, - // 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); - } - } - else { - Fprintf(stderr, "No matching pin in cell %s for " - "cell %s pin %s\n", - tc2->name, tc1->name, obn->name); - } -#ifdef TCL_NETGEN - if (dolist && strcmp(obn->name, "(no pins)")) { - Tcl_ListObjAppendElement(netgeninterp, plist1, - Tcl_NewStringObj(obn->name, -1)); - Tcl_ListObjAppendElement(netgeninterp, plist2, - Tcl_NewStringObj("(no matching pin)", -1)); - } + if (dolist) { + Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, + Tcl_NewStringObj("pins", -1), + TCL_APPEND_VALUE | TCL_LIST_ELEMENT); + Tcl_SetVar2Ex(netgeninterp, "lvs_out", NULL, mlist, + TCL_APPEND_VALUE | TCL_LIST_ELEMENT); + } #endif - result = 0; - - /* Make a pass through circuit 1 to find out if */ - /* the pin really is connected to anything, or */ - /* has been left orphaned after flattening. If */ - /* disconnected, set its node number to -2. */ - - notempty = 0; - for (obt = ob1->next; obt; obt = obt->next) { - if (obt->type >= FIRSTPIN) { - notempty = 1; - if (obt->node == ob1->node) - break; - } - } - if ((obt == NULL) && (notempty == 1)) { - ob1->node = -2; // Will run this through cleanuppins - needclean1 = 1; - } - } - break; - } - } - - 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); - } - else { - Fprintf(stderr, "No netlist match for cell %s pin %s\n", - tc1->name, obn->name); - } + FREE(ostr); + return 1; + */ + } else { + obp = N2->object; + } + ob1 = NULL; + if (IsPort(obn)) { + i = 0; + for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next, i++) { + if ((IsPort(ob1)) + && (*matchfunc)(ob1->name, obn->name)) { + break; + } + } + //assert(ob1); // there should always be a port if obn is a port + *(cover1 + i) = (char)1; + } + ob2 = NULL; + if (obp && IsPort(obp)) { + j = 0; + for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next, j++) { + if ((IsPort(ob2)) + && (*matchfunc)(ob2->name, obp->name)) { + break; + } + } + //assert(ob2); // there should always be a port if obp is a port + *(cover2 + j) = (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) = ' '; + if (ob1 && ob2) { // pins both in the layout and the source + if (NC->legalpartition) { // net match + snprintf(ostr, left_col_end, "%s", obn->name); + if ((*matchfunc)(obn->name, obp->name)) + // MatchPins - case 1: portA(0) = portA(1) pin names match + snprintf(ostr + left_col_end + 1, left_col_end, "%s", obp->name); + else { + // MatchPins - case 2: portA(0) = portB(1) circuits match but pin names don't + snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", obp->name); + /* Pins with different names are on different nets, + * so this should trigger an error return code. + */ + result = (result == 1) ? 0 : result; // only set if 1 + } + ob2->model.port = i; /* save order */ + } else { + snprintf(ostr, left_col_end, "*%s", obn->name); + snprintf(ostr + left_col_end + 1, left_col_end, "*%s **Mismatch**", obp->name); + for (m = 0; m < right_col_end + 1; m++) + if (*(ostr + m) == '\0') *(ostr + m) = ' '; + result = -1; + } + } else if (ob1) { // implies (&& !ob2) + // MatchPins - case 3: portA(0) = netA(1) circuits match but source is missing pin + snprintf(ostr, left_col_end, "%s", obn->name); + if (NC->legalpartition) { // net match + snprintf(ostr + left_col_end + 1, left_col_end, "*%s **not a pin**", obp->name); + } else { + snprintf(ostr + left_col_end + 1, left_col_end, "*%s **Mismatch**", obp->name); + } + result = -1; + } else if (ob2) { // implies (&& !ob1) + // MatchPins - case 4: netA(0) = portA(1) circuits match but layout is missing pin + if (NC->legalpartition) { // net match + snprintf(ostr, left_col_end, "*%s **not pin**", obn->name); + } else { + snprintf(ostr, left_col_end, "*%s **Mismatch**", obn->name); + } + snprintf(ostr + left_col_end + 1, left_col_end, "%s", obp->name); + result = -1; + } + if (ob1 || ob2) { + for (m = 0; m < right_col_end + 1; m++) + if (*(ostr + m) == '\0') *(ostr + m) = ' '; + Fprintf(stdout, ostr); + } + } + else { + Fprintf(stdout, "Circuit %s port %d \"%s\"" + " = cell %s port %d \"%s\"\n", + tc1->name, i, (obn) ? obn->name : "", + tc2->name, j, (obp) ? obp->name : ""); + } #ifdef TCL_NETGEN - if (dolist) { - Tcl_ListObjAppendElement(netgeninterp, plist1, - Tcl_NewStringObj(obn->name, -1)); - Tcl_ListObjAppendElement(netgeninterp, plist2, - Tcl_NewStringObj("(no matching pin)", -1)); - } + if (dolist) { + Tcl_ListObjAppendElement(netgeninterp, plist1, + Tcl_NewStringObj((obn) ? obn->name : "", -1)); + Tcl_ListObjAppendElement(netgeninterp, plist2, + Tcl_NewStringObj((obp) ? obp->name : "", -1)); + } #endif - result = 0; - } - } a++; } } } + // Check for unconnected nodes in tc1 + for (ob1 = tc1->cell; ob1 && IsPort(ob1); ob1 = ob1->next ) { + if (ob1->node >= 0) { + /* Check if ob1->node might really be disconnected */ + for (obn = ob1->next; obn; obn = obn->next) { + if (obn->node == ob1->node) break; + } + if (obn == NULL) ob1->node = -1; /* Make disconnected */ + } + } + + // Check for unconnected nodes in tc2 + for (ob2 = tc2->cell; ob2 && IsPort(ob2); ob2 = ob2->next ) { + if (ob2->node >= 0) { + /* Check if ob2->node might really be disconnected */ + for (obp = ob2->next; obp; obp = obp->next) { + if (obp->node == ob2->node) break; + } + if (obp == NULL) ob2->node = -1; /* Make disconnected */ + } + } + /* Do any unmatched pins have the same name? */ /* This should not happen if unconnected pins are eliminated */ /* so apply only to black-box (CELL_PLACEHOLDER) entries. */ @@ -7388,13 +7480,16 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) *bangptr1 = '\0'; else bangptr1 = NULL; + int isBlackBox1 = (tc1->flags & CELL_PLACEHOLDER); + int isBlackBox2 = (tc2->flags & CELL_PLACEHOLDER); for (i = 0; i < numorig; i++) { - if (*(cover + i) == (char)0) { + if (*(cover1 + i) == (char)0) { j = 0; - for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) { + for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next, j++) { char *name1, *name2; if (!IsPort(ob2)) break; + if (*(cover2 + j) == (char)1) continue; // this port was processed bangptr2 = strrchr(ob2->name, '!'); if (bangptr2 && (*(bangptr2 + 1) == '\0')) @@ -7409,6 +7504,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) if (!strncmp(name2, "proxy", 5) && (ob1->node == -1)) name2 +=5; if ((*matchfunc)(name1, name2)) { + //Fprintf(stdout, "DEBUG: disconnected port match %s %d(%d) - %s %d(%d)\n", name1, i, ob1->node, name2, j, ob2->node); /* If both sides have unconnected nodes, then pins with */ /* matching names are an automatic match. Otherwise, if */ @@ -7416,18 +7512,20 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) /* matched by name. */ if (((ob1->node == -1) && (ob2->node == -1)) || - (((tc1->flags & CELL_PLACEHOLDER) && - (tc2->flags & CELL_PLACEHOLDER)) || - (NodeClasses == NULL))) { + (isBlackBox1 && isBlackBox2) || + (NodeClasses == NULL)) { ob2->model.port = i; /* save order */ - *(cover + i) = (char)1; + *(cover1 + i) = (char)1; + *(cover2 + j) = (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); + snprintf(ostr, left_col_end, + "%s %s", ob1->name, (ob1->node == -1 && ! isBlackBox1) ? "(disconnected)" : ""); + snprintf(ostr + left_col_end + 1, left_col_end, + "%s %s", ob2->name, (ob2->node == -1 && ! isBlackBox2) ? "(disconnected)" : ""); for (m = 0; m < right_col_end + 1; m++) if (*(ostr + m) == '\0') *(ostr + m) = ' '; Fprintf(stdout, ostr); @@ -7451,7 +7549,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) } } if (bangptr2) *bangptr2 = '!'; - j++; } } ob1 = ob1->next; @@ -7470,8 +7567,9 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) /* connections in the cell to the end. Create pins */ /* in tc1 to match. */ - for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) { + for (j = 0, ob2 = tc2->cell; ob2 != NULL; j++, ob2 = ob2->next) { if (ob2->type != PORT) break; + if (*(cover2 + j) == (char)1) continue; // this port was processed if (ob2->model.port == -1) { if (Debug == 0) { @@ -7479,8 +7577,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) 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); + snprintf(ostr, left_col_end, "**no match**"); + snprintf(ostr + left_col_end + 1, left_col_end, "%s %s", ob2->name, (ob2->node == -1) ? "(disconnected)" : ""); for (m = 0; m < right_col_end + 1; m++) if (*(ostr + m) == '\0') *(ostr + m) = ' '; Fprintf(stdout, ostr); @@ -7490,77 +7588,9 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) Fprintf(stderr, "No netlist match for cell %s pin %s\n", tc2->name, ob2->name); } - - /* Before making a proxy pin, check to see if */ - /* flattening instances has left a port with a */ - /* net number that doesn't connect to anything */ - - notempty = 0; - for (obt = ob2->next; obt; obt = obt->next) { - if (obt->type >= FIRSTPIN) { - notempty = 1; - if (obt->node == ob2->node) - break; - } - } - if ((obt == NULL) && (notempty == 1)) { - ob2->node = -2; // Will run this through cleanuppins - needclean2 = 1; - - /* On the top level, missing pins are an error, even if */ - /* they appear to match unconnected pins on the other side. */ - if (CompareQueue == NULL) - result = 0; - -#ifdef TCL_NETGEN - if (dolist) { - Tcl_ListObjAppendElement(netgeninterp, plist1, - Tcl_NewStringObj("(no pin)", -1)); - Tcl_ListObjAppendElement(netgeninterp, plist2, - Tcl_NewStringObj(ob2->name, -1)); - } -#endif - continue; - } - else if (notempty == 1) { - /* Flag this as an error */ - result = 0; -#ifdef TCL_NETGEN - if (dolist) { - Tcl_ListObjAppendElement(netgeninterp, plist1, - Tcl_NewStringObj("(no matching pin)", -1)); - Tcl_ListObjAppendElement(netgeninterp, plist2, - Tcl_NewStringObj(ob2->name, -1)); - } -#endif - } ob2->model.port = numnodes++; // Assign a port order + result = -1; - /* Add a proxy pin to tc1 */ - /* Technically, this should have a matching net number. */ - /* But nothing connects to it, so it is only needed to */ - /* make sure the "pin magic" numbers are correctly */ - /* assigned to both cells. */ - - obn = (struct objlist *)CALLOC(1, sizeof(struct objlist)); - obn->name = (char *)MALLOC(6 + strlen(ob2->name)); - sprintf(obn->name, "proxy%s", ob2->name); - obn->type = UNKNOWN; - // obn->model.port = -1; - obn->instance.name = NULL; - obn->node = -1; - if (ob1 == tc1->cell) { - obn->next = ob1; - tc1->cell = obn; - } - else { - obn->next = ob1->next; - ob1->next = obn; - } - ob1 = obn; - hasproxy1 = 1; - - HashPtrInstall(obn->name, obn, &(tc1->objdict)); } } @@ -7577,97 +7607,65 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) /* sequence, then fill in the missing numbers. Otherwise, add the */ /* extra nodes to the end. */ - j = 0; - for (i = 0; i < numorig; i++) { - if (*(cover + i) == (char)1) continue; + for (i = 0, ob1 = tc1->cell; i < numorig; i++, ob1 = ob1->next) { + if (*(cover1 + i) == (char)1) continue; /* If the equivalent node in tc1 is not disconnected */ /* (node != -1) then we should report a match error, */ /* although this does not necessarily imply an error in */ /* netlist connectivity. */ +/* ob1 = tc1->cell; for (k = i; k > 0 && ob1 != NULL; k--) ob1 = ob1->next; + */ - if (ob1 == NULL || ob1->type != PORT || ob1->node >= 0) { - /* Check if ob1->node might really be disconnected */ - for (obn = ob1->next; obn; obn = obn->next) { - if (obn->node == ob1->node) break; - } - if (obn == NULL) ob1->node = -1; /* Make disconnected */ - } - - if (ob1 == NULL || ob1->type != PORT || ob1->node >= 0 - || (ob1->node < 0 && tc1->class == CLASS_MODULE) - || (ob1->node < 0 && ob1->model.port == -1)) { - - /* Add a proxy pin to tc2 */ - obn = (struct objlist *)CALLOC(1, sizeof(struct objlist)); - if (ob1 == NULL) { - obn->name = (char *)MALLOC(15); - sprintf(obn->name, "proxy%d", rand() & 0x3ffffff); - } - else { - obn->name = (char *)MALLOC(6 + strlen(ob1->name)); - sprintf(obn->name, "proxy%s", ob1->name); - } - obn->type = UNKNOWN; - obn->model.port = (i - j); - 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; - } - else { - obn->next = ob2->next; - ob2->next = obn; - } - ob2 = obn; - hasproxy2 = 1; - - HashPtrInstall(obn->name, obn, &(tc2->objdict)); + 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 %s", ob1->name, (ob1->node == -1) ? "(disconnected)" : ""); + snprintf(ostr + left_col_end + 1, left_col_end, "**no match**"); + for (m = 0; m < right_col_end + 1; m++) + if (*(ostr + m) == '\0') *(ostr + m) = ' '; + Fprintf(stdout, ostr); + } + result = -1; } - - else if (ob1 != NULL && ob1->type == PORT) { - /* Disconnected node was not meaningful, has no pin match in */ - /* the compared circuit, and so should be discarded. */ - ob1->node = -2; - needclean1 = 1; - - /* Adjust numbering around removed node */ - for (ob2s = tc2->cell; ob2s != NULL && ob2s->type == PORT; ob2s = ob2s->next) { - if (ob2s->model.port > (i - j)) ob2s->model.port--; - } - j++; + else { + Fprintf(stderr, "No netlist match for cell %s pin %s\n", + tc1->name, ob1->name); } } - FREE(cover); + FREE(cover1); + FREE(cover2); if (Debug == 0) { for (i = 0; i < right_col_end; i++) *(ostr + i) = '-'; Fprintf(stdout, ostr); } + int hasDevices1 = 0; + int hasDevices2 = 0; + for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next) { + if (ob1->type == FIRSTPIN) { + hasDevices1 = 1; + break; + } + } + for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) { + if (ob2->type == FIRSTPIN) { + hasDevices2 = 1; + break; + } + } + if (hasDevices1 != hasDevices2) + result = -2; // Attempt to compare empty cell to non-empty cell + //Fprintf(stdout, "DEBUG: %s device check %d %d\n", tc1->name, hasDevices1, hasDevices2); + + if (result < 0) return result; + /* Run cleanuppins on circuit 1 */ if (needclean1) { CleanupPins(tc1->name, tc1->file); @@ -7707,7 +7705,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) } /* Check for ports that did not get ordered */ - for (obn = tc2->cell; obn && (obn->type == PORT); obn = obn->next) { + for (obn = tc2->cell; obn && IsPort(obn); obn = obn->next) { if (obn->model.port == -1) { if (obn->node == -1) { // This only happens when pins have become separated from any net. @@ -7959,6 +7957,35 @@ int Compare(char *cell1, char *cell2) PrintIllegalClasses(); return(0); } + if (automorphisms > 0) { + Fprintf(stdout, "Circuits match with %d automorphisms.\n", automorphisms); + if (VerboseOutput) PrintAutomorphisms(); + + /* arbitrarily resolve automorphisms */ + Fprintf(stdout, "\n"); + Fprintf(stdout, "Resolving automorphisms by arbitrary symmetry breaking:\n"); + while ((automorphisms = ResolveAutomorphisms()) > 0) ; + if (automorphisms == -1) { + MatchFail(cell1, cell2); + Fprintf(stdout, "Circuits do not match.\n"); + return(0); + } + } + if (automorphisms == -2) { // port count mismatch + Fprintf(stderr, "Port counts do not match(5).\n"); + //PrintPins(cell1, cell2, 0); + return(0); + } + if (PropertyErrorDetected == 1) { + Fprintf(stdout, "There were property errors.\n"); + PrintPropertyResults(0); + } + else if (PropertyErrorDetected == -1) { + Fprintf(stdout, "There were missing properties.\n"); + PrintPropertyResults(0); + } + else Fprintf(stdout, "Circuits match correctly.\n"); + /* if (automorphisms == 0) Fprintf(stdout, "Circuits match correctly.\n"); if (PropertyErrorDetected == 1) { Fprintf(stdout, "There were property errors.\n"); @@ -7983,6 +8010,7 @@ int Compare(char *cell1, char *cell2) return(0); } Fprintf(stdout, "Circuits match correctly.\n"); + */ return(1); } @@ -8037,6 +8065,10 @@ void NETCOMP(void) PrintIllegalClasses(); Fprintf(stdout, "Netlists do not match.\n"); } + else if (automorphisms == -2) { // port count mismatch + Fprintf(stdout, "Port counts do not match(1).\n"); + //PrintPins(Circuit1, Circuit2, 0); + } else { if (automorphisms) Printf("Circuits match with %d automorphisms.\n", automorphisms); @@ -8052,11 +8084,13 @@ void NETCOMP(void) while (!Iterate()) ; automorphisms = VerifyMatching(); if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n"); + else (automorphisms == -2) Fprintf(stdout, "Port counts do not match(2).\n"); else { Printf("Netlists match with %d automorphisms.\n", automorphisms); while ((automorphisms = ResolveAutomorphisms()) > 0) Printf(" automorphisms = %d.\n", automorphisms); if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n"); + else if (automorphisms == -2) Fprintf(stdout, "Port counts do not match(3).\n"); else Printf("Circuits match correctly.\n"); } } diff --git a/base/netgen.c b/base/netgen.c index dc15c7e..8b9d504 100644 --- a/base/netgen.c +++ b/base/netgen.c @@ -3337,16 +3337,13 @@ int CombineParallel(char *model, int file) /* "sob" to it. If "ob" does not have properties, then */ /* create a property record and set property "M" to 1. */ - /* Find last non-property record of sob ( = pob) */ - /* Find first property record of sob ( = spropfirst) */ - /* Find last property record of sob ( = sproplast) */ + /* Find last non-property record of sob ( = pob) */ + /* Find first property record of sob ( = spropfirst) */ - spropfirst = sproplast = NULL; + spropfirst = NULL; for (ob2 = sob; ob2->type > FIRSTPIN || ob2 == sob; ob2 = ob2->next) pob = ob2; if (ob2->type == PROPERTY) spropfirst = ob2; - for (; ob2->type == PROPERTY; ob2 = ob2->next) - sproplast = ob2; if (spropfirst == NULL) { /* Create new property instance record if one doesn't exist */ @@ -3372,8 +3369,9 @@ int CombineParallel(char *model, int file) nob->next = pob->next; pob->next = nob; + /* Handle case of contiguous entries */ if (lob == pob) lob = nob; - spropfirst = sproplast = nob; + spropfirst = nob; } if (propfirst == NULL) { /* Create new property instance record if one doesn't exist */ @@ -3396,27 +3394,26 @@ int CombineParallel(char *model, int file) kv->type = PROP_ENDLIST; kv->value.ival = 0; - /* Append to sob's property list */ - nob->next = sproplast->next; - sproplast->next = nob; - if (lob == sproplast) lob = nob; + /* Prepend to sob's property list */ + nob->next = pob->next; + pob->next = nob; + /* Handle case of contiguous entries */ + if (lob == pob) lob = nob; } - - if (propfirst != NULL) { + else { // Series/Parallel logic: - // If propfirst has _tag in properties, - // then add an "open" tag at propfirst - add_prop_tag(propfirst, '('); - - // if spropfirst has _tag in properties then add an "open" tag - // to spropfirst and a "close" tag to propfirst - if (add_prop_tag(spropfirst, '(')) add_prop_tag(propfirst, ')'); - - /* Append ob's property list to sob */ - proplast->next = sproplast->next; - sproplast->next = propfirst; - if (lob == sproplast) lob = proplast; + // If spropfirst has _tag in properties, + // then add an "open" tag at spropfirst + add_prop_tag(spropfirst, '('); + + // if propfirst has _tag in properties then add an "open" tag + // to propfirst and a "close" tag to spropfirst + if (add_prop_tag(propfirst, '(')) add_prop_tag(spropfirst, ')'); + + /* Prepend ob's property list to sob */ + proplast->next = pob->next; + pob->next = propfirst; } /* Link up around object to be removed */ @@ -3429,7 +3426,6 @@ int CombineParallel(char *model, int file) obr = nob; } dcnt++; - } FREE((char *)pstr); } @@ -3441,7 +3437,8 @@ int CombineParallel(char *model, int file) } HashKill(&devdict); if (dcnt > 0) { - Fprintf(stdout, "Class %s(%d): Merged %d parallel devices.\n", model, file, dcnt); + Fprintf(stdout, "Class %s (%d): Merged %d parallel devices.\n", + model, file, dcnt); } FREE(nodecount); return dcnt; @@ -3739,7 +3736,8 @@ int CombineSeries(char *model, int file) } FREE(instlist); if (scnt > 0) { - Fprintf(stdout, "Class %s(%d): Merged %d series devices.\n", model, file, scnt); + Fprintf(stdout, "Class %s (%d): Merged %d series devices.\n", + model, file, scnt); } return scnt; } diff --git a/tcltk/netgen.tcl.in b/tcltk/netgen.tcl.in index 2270ec5..c3f19b8 100644 --- a/tcltk/netgen.tcl.in +++ b/tcltk/netgen.tcl.in @@ -532,14 +532,25 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { } set properr {} set matcherr {} - set pinsgood -1 + set childMismatch 0 ; # 1 indicates black-box child subcircuit mismatch + #set pinsgood -1 while {$endval != {}} { if {$dolist == 1} { netgen::run -list converge } else { netgen::run converge } - netgen::log echo on + set pinMismatch 0 ; # indicates pinMismatch in current cell (only used for top cell) + #netgen::log echo on + set doCheckFlatten 0 + set doFlatten 0 + if {[netgen::print queue] == {}} { + set doEquatePins 1 ; # run equate pins top cell + } else { + set doEquatePins 0 ; # don't run equate pins unless unique match, property errors, and pin errors + } + set forceMatch 0 ; # for pin matching + netgen::log echo off if {[verify equivalent]} { # Resolve automorphisms by pin and property if {$dolist == 1} { @@ -548,96 +559,178 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { netgen::run resolve } set uresult [verify unique] + # -3 - unique with property error, -2 - equivalent with port errors, -1 - blackbox, 0 - equivalent but not unique, 1 - unique if {$uresult == 0} { + netgen::log echo on netgen::log put " Networks match locally but not globally.\n" netgen::log put " Probably connections are swapped.\n" netgen::log put " Check the end of logfile ${logfile} for implicated nodes.\n" + netgen::log echo off if {$dolist == 1} { verify -list nodes } else { verify nodes } + set doCheckFlatten 1 - # Flatten the non-matching subcircuit (but not the top-level cells) - 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\n" - netgen::flatten class "[lindex $endval 0] $fnum1" - netgen::flatten class "[lindex $endval 1] $fnum2" - } else { - netgen::log put " Continuing with black-boxed subcircuits $endval\n" - lappend matcherr [lindex $endval 0] ($fnum1) - lappend matcherr [lindex $endval 1] ($fnum2) - # 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 { - netgen::log echo off - if {$dolist == 1} { - set result [equate -list pins "$fnum1 [lindex $endval 0]" \ - "$fnum2 [lindex $endval 1]"] - } else { - set result [equate pins "$fnum1 [lindex $endval 0]" \ - "$fnum2 [lindex $endval 1]"] - } - if {$result != 0} { - equate classes "$fnum1 [lindex $endval 0]" \ - "$fnum2 [lindex $endval 1]" - } - # If $uresult == -1 then these are black-box entries and - # $pinsgood should not be set to the resulting value. - if {$uresult > 0} { - set pinsgood $result - } - netgen::log echo on + } else { ; # Equate pins for black boxes, unique matches (including property errors), and unique with port errors + set doEquatePins 1 + } + if {$uresult == -1} { ; # black box + set forceMatch 1 + } elseif {$uresult == -3} { ; # property error + lappend properr [lindex $endval 0] + } elseif {$uresult == -2} { ; # unmatched pins + set doCheckFlatten 1 } - if {$uresult == 2} {lappend properr [lindex $endval 0]} } else { - # Flatten the non-matching subcircuit (but not the top-level cells) + # not equivalent + netgen::log echo on + netgen::log put " DEBUG: not equivalent $endval\n" + netgen::log echo off + set doCheckFlatten 1 + } + if ($doCheckFlatten) { + # Flatten the non-matching subcircuit (but not the top-level cells, nor explicit no flat cells) 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\n" - netgen::flatten class "[lindex $endval 0] $fnum1" - netgen::flatten class "[lindex $endval 1] $fnum2" - } else { - netgen::log put " Continuing with black-boxed subcircuits $endval\n" - lappend matcherr [lindex $endval 0] ($fnum1) - lappend matcherr [lindex $endval 0] ($fnum2) - # 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 + if {([lsearch $noflat [lindex $endval 0]] == -1) && + ([lsearch $noflat [lindex $endval 1]] == -1)} { + set doFlatten 1 + } else { netgen::log echo on + netgen::log put " Continuing with unmatched black-boxed subcircuits $endval\n" + netgen::log echo off + lappend matcherr [lindex $endval 0]"($fnum1)" + lappend matcherr [lindex $endval 1]"($fnum2)" + set doEquatePins 1 + set childMismatch 1 + set forceMatch 1 + } + } + } + if {$doEquatePins} { + # Match pins + if {$dolist == 1} { + if {$forceMatch} { + set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \ + "$fnum2 [lindex $endval 1]"] + } else { + set result [equate -list pins "$fnum1 [lindex $endval 0]" \ + "$fnum2 [lindex $endval 1]"] + } + } else { + if {$forceMatch} { + set result [equate -force pins "$fnum1 [lindex $endval 0]" \ + "$fnum2 [lindex $endval 1]"] + } else { + set result [equate pins "$fnum1 [lindex $endval 0]" \ + "$fnum2 [lindex $endval 1]"] + } + } + if {$result >= 0} { + equate classes "$fnum1 [lindex $endval 0]" \ + "$fnum2 [lindex $endval 1]" + } + # Do not set pinMismatch for black boxes + if {$result < 0} { + #set pinMismatch 0 + if {$result == -1 && [netgen::print queue] != {} && $forceMatch != 1} { + # flatten pin mismatch, but not empty cells (-2) or top cell or noflatten cells + set doFlatten 1 } + } elseif { [netgen::print queue] == {} && $result == 0 } { + set pinMismatch 1 } } - netgen::log echo off + if {$doFlatten} { + netgen::log echo on + netgen::log put " Flattening non-matched subcircuits $endval\n" + netgen::log echo off + netgen::flatten class "[lindex $endval 0] $fnum1" + netgen::flatten class "[lindex $endval 1] $fnum2" + } + # if {} { + # if {} { +# # Flatten the non-matching subcircuit (but not the top-level cells) +# 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\n" +# netgen::flatten class "[lindex $endval 0] $fnum1" +# netgen::flatten class "[lindex $endval 1] $fnum2" +# } else { +# netgen::log put " Continuing with black-boxed subcircuits $endval\n" +# lappend matcherr [lindex $endval 0] ($fnum1) +# lappend matcherr [lindex $endval 1] ($fnum2) +# # 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 { +# netgen::log echo off +# if {$dolist == 1} { +# set result [equate -list pins "$fnum1 [lindex $endval 0]" \ +# "$fnum2 [lindex $endval 1]"] +# } else { +# set result [equate pins "$fnum1 [lindex $endval 0]" \ +# "$fnum2 [lindex $endval 1]"] +# } +# if {$result != 0} { +# equate classes "$fnum1 [lindex $endval 0]" \ +# "$fnum2 [lindex $endval 1]" +# } +# # If $uresult == -1 then these are black-box entries and +# # $pinsgood should not be set to the resulting value. +# if {$uresult > 0} { +# set pinsgood $result +# } +# netgen::log echo on +# } +# if {$uresult == 2} {lappend properr [lindex $endval 0]} +# } else { +# # Flatten the non-matching subcircuit (but not the top-level cells) +# 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\n" +# netgen::flatten class "[lindex $endval 0] $fnum1" +# netgen::flatten class "[lindex $endval 1] $fnum2" +# } else { +# netgen::log put " Continuing with black-boxed subcircuits $endval\n" +# lappend matcherr [lindex $endval 0] ($fnum1) +# lappend matcherr [lindex $endval 0] ($fnum2) +# # 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 if {$dolist == 1} { catch {lappend lvs_final $lvs_out} set lvs_out {} @@ -646,20 +739,29 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { set endval [netgen::compare hierarchical] } } - netgen::log echo off - puts stdout "Result: " nonewline + #netgen::log echo off + #puts stdout "Result: " nonewline netgen::log echo on - if {$pinsgood == 0} { - # NOTE: Need to disambiguate these two cases. . . - netgen::log put "Cells failed matching, or top level cell failed pin matching.\n" + #if {$pinsgood == 0} {} + # # NOTE: Need to disambiguate these two cases. . . + # netgen::log put "Cells failed matching, or top level cell failed pin matching.\n" + #put stdout "Result: " nonewline + netgen::log put "\nFinal result: " + if {$pinMismatch || $childMismatch} { + if {$childMismatch} { + netgen::log put "Subcell(s) failed matching.\n" + } + if {$pinMismatch} { + netgen::log put "Top level cell failed pin matching.\n" + } } else { verify only } if {$properr != {}} { - netgen::log put "The following cells had property errors:\n " [regsub -all { } $properr "\n "] "\n" + netgen::log put "\nThe following cells had property errors:\n " [regsub -all { } $properr "\n "] "\n" } if {$matcherr != {}} { - netgen::log put "The following subcells failed to match:\n " [regsub -all { } $matcherr "\n "] "\n" + netgen::log put "\nThe following subcells failed to match:\n " [regsub -all { } $matcherr "\n "] "\n" } if {$dolog} { netgen::log end diff --git a/tcltk/tclnetgen.c b/tcltk/tclnetgen.c index 83f41fb..c25a106 100644 --- a/tcltk/tclnetgen.c +++ b/tcltk/tclnetgen.c @@ -1931,9 +1931,17 @@ _netgen_log(ClientData clientData, switch(index) { case START_IDX: LoggingFile = fopen(LogFileName, "w"); + if (! LoggingFile) { + Tcl_SetResult(interp, "Could not open log file.", NULL); + return TCL_ERROR; + } break; case RESUME_IDX: LoggingFile = fopen(LogFileName, "a"); + if (! LoggingFile) { + Tcl_SetResult(interp, "Could not open log file.", NULL); + return TCL_ERROR; + } break; case END_IDX: fclose(LoggingFile); @@ -1942,6 +1950,10 @@ _netgen_log(ClientData clientData, case RESET_IDX: fclose(LoggingFile); LoggingFile = fopen(LogFileName, "w"); + if (! LoggingFile) { + Tcl_SetResult(interp, "Could not open log file.", NULL); + return TCL_ERROR; + } break; case SUSPEND_IDX: fclose(LoggingFile); @@ -2483,6 +2495,38 @@ _netcmp_run(ClientData clientData, ExhaustiveSubdivision = 1; while (!Iterate() && !InterruptPending); automorphisms = VerifyMatching(); + if (automorphisms > 0) { + // First try to resolve automorphisms uniquely using + // property matching + automorphisms = ResolveAutomorphsByProperty(); + if (automorphisms > 0) { + // Next, attempt to resolve automorphisms uniquely by + // using the pin names + automorphisms = ResolveAutomorphsByPin(); + } + if (automorphisms > 0) { + // Anything left is truly indistinguishable + while (ResolveAutomorphisms() > 0); + } + } + 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 == 0) + Fprintf(stdout, "Netlists match uniquely"); + else + Fprintf(stdout, "Netlists match with %d symmetr%s", + automorphisms, (automorphisms == 1) ? "y" : "ies"); + if (PropertyErrorDetected) { + Fprintf(stdout, " with property errors.\n"); + PrintPropertyResults(dolist); + } else + Fprintf(stdout, ".\n"); + } + disable_interrupt(); + /* if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n"); else if (automorphisms == 0) @@ -2518,6 +2562,7 @@ _netcmp_run(ClientData clientData, PrintPropertyResults(dolist); } disable_interrupt(); + */ } break; } @@ -2533,8 +2578,15 @@ _netcmp_run(ClientData clientData, /* all, or no option. */ /* Formerly: v */ /* Results: */ -/* For only, equivalent, unique: Return 1 if */ -/* verified, zero if not. */ +/* For only, equivalent, unique: Return */ +/* 1: verified */ +/* 0: not verified */ +/* -1: no elements or no nodes */ +/* -3: verified with property error */ +/* equiv option */ +/* n: number of automorphisms */ +/* unique option */ +/* -2: pin mismatch */ /* Side Effects: */ /* For options elements, nodes, and all without */ /* option -list: Write output to log file. */ @@ -2628,13 +2680,22 @@ _netcmp_verify(ClientData clientData, else Fprintf(stdout, "Netlists do not match.\n"); } + else if (automorphisms == -2) { + //result = MatchPins(Circuit1, Circuit2, dolist); + if (index == EQUIV_IDX) + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); + else if (index == UNIQUE_IDX) + Tcl_SetObjResult(interp, Tcl_NewIntObj(-2)); + else if (index > 0) + Fprintf(stdout, "Circuits match uniquely with port errors.\n"); + } else { if (automorphisms) { if (index == EQUIV_IDX) Tcl_SetObjResult(interp, Tcl_NewIntObj((int)automorphisms)); else if (index == UNIQUE_IDX) Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); - else + else if (index > 0) Printf("Circuits match with %d symmetr%s.\n", automorphisms, (automorphisms == 1) ? "y" : "ies"); } @@ -2643,12 +2704,14 @@ _netcmp_verify(ClientData clientData, if (PropertyErrorDetected == 0) Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); else - Tcl_SetObjResult(interp, Tcl_NewIntObj(2)); + Tcl_SetObjResult(interp, Tcl_NewIntObj(-3)); } - else { - Fprintf(stdout, "Circuits match uniquely.\n"); - if (PropertyErrorDetected != 0) - Fprintf(stdout, "Property errors were found.\n"); + else if (index > 0) { + Fprintf(stdout, "Circuits match uniquely"); + if (PropertyErrorDetected == 0) + Fprintf(stdout, ".\n"); + else + Fprintf(stdout, " with property errors.\n"); } } #if 0 @@ -3104,7 +3167,13 @@ _netcmp_equate(ClientData clientData, else if (result > 0) { Fprintf(stdout, "Cell pin lists are equivalent.\n"); } - else { + else if (result == -1) { + Fprintf(stdout, "Cell pin lists for %s and %s do not match.\n", + name1, name2); + } + else if (result == -2) { + Fprintf(stdout, "Attempt to match empty cell to non-empty cell.\n"); + } else { Fprintf(stdout, "Cell pin lists for %s and %s altered to match.\n", name1, name2); } From e1b5a2ecb896d4e9372844f4024dea780f4b16d6 Mon Sep 17 00:00:00 2001 From: "D. Mitch Bailey" Date: Mon, 2 May 2022 00:31:59 -0700 Subject: [PATCH 5/5] Pulled .git.ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index aa0d413..1b2fcdc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ config.log scripts/config.log config.status scripts/config.status +python/lvs_manager.py *.o *.so *~