From b9e26f6fce49d0e9431ad3d94aa82e894eb39f52 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 20 Jun 2017 22:50:31 -0400 Subject: [PATCH] Implemented better black-box handling. Netlist with "stub" entries for subcircuits (.subckt ... .ends pair with cellname and pin names and pin order, but no contents) are automatically treated as black- box circuits if found and if the "-blackbox" option is passed to the "lvs" (scripted) command. The "equate pins" command can be used outside of a comparison to force two circuits (black-box or otherwise) to be matched by pin name (if not a black-box circuit, then this is a provisional name match, as a circuit comparison will order based on connectivity first, not pin names). So two sets of black-box circuit libraries can be used as long as their pin names match. One hack added to ignore the "!" at the end of global names when comparing pin names for matching. Otherwise, pin names must compare by case-insensitive string match. --- base/flatten.c | 4 ++++ base/netcmp.c | 21 +++++++++++++++++--- base/spice.c | 2 +- tcltk/netgen.tcl.in | 1 - tcltk/tclnetgen.c | 47 ++++++++++++++++++++++++++++++--------------- 5 files changed, 55 insertions(+), 20 deletions(-) diff --git a/base/flatten.c b/base/flatten.c index c9b3784..3859cf0 100644 --- a/base/flatten.c +++ b/base/flatten.c @@ -1230,6 +1230,10 @@ int CleanupPins(char *name, int filenum) return 0; } + // If cell is type MODULE, this is a black-box circuit and + // pins are expected to be disconnected (so don't remove them). + if (ThisCell->class == CLASS_MODULE) return 0; + // Avoid a loop through all cells unless we have to do it. for (ob = ThisCell->cell; ob != NULL; ob = ob->next) { diff --git a/base/netcmp.c b/base/netcmp.c index ca774ab..d34b952 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -6274,6 +6274,7 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata) int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) { char *cover, *ctemp; + char *bangptr1, *bangptr2; struct objlist *ob1, *ob2, *obn, *obp, *ob1s, *ob2s, *obt; struct NodeClass *NC; struct Node *N1, *N2; @@ -6486,13 +6487,25 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) /* Do any unmatched pins have the same name? */ /* (This should not happen if unconnected pins are eliminated) */ + /* (Semi-hack: Allow "!" global flag) */ ob1 = tc1->cell; + bangptr1 = strrchr(ob1->name, '!'); + if (bangptr1 && (*(bangptr1 + 1) == '\0')) + *bangptr1 = '\0'; + else bangptr1 = NULL; + for (i = 0; i < numorig; i++) { if (*(cover + i) == (char)0) { j = 0; for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) { if (!IsPort(ob2)) break; + + bangptr2 = strrchr(ob2->name, '!'); + if (bangptr2 && (*(bangptr2 + 1) == '\0')) + *bangptr2 = '\0'; + else bangptr2 = NULL; + if ((*matchfunc)(ob1->name, ob2->name)) { ob2->model.port = i; /* save order */ *(cover + i) = (char)1; @@ -6521,11 +6534,13 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) } #endif } + if (bangptr2) *bangptr2 = '!'; j++; } } ob1 = ob1->next; } + if (bangptr1) *bangptr1 = '!'; /* Find the end of the pin list in tc1, for adding proxy pins */ @@ -6709,7 +6724,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) /* Clean up "UNKNOWN" records from Circuit1 */ - for (obn = tc1->cell; ; obn = obn->next) { + for (obn = tc1->cell; obn; obn = obn->next) { if (obn->type == UNKNOWN) obn->type = PORT; else if (obn->type != PORT) break; } @@ -6728,13 +6743,13 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist) /* Clean up "UNKNOWN" records from Circuit2 */ - for (obn = tc2->cell; ; obn = obn->next) { + for (obn = tc2->cell; obn; obn = obn->next) { if (obn->type == UNKNOWN) obn->type = PORT; else if (obn->type != PORT) break; } /* Check for ports that did not get ordered */ - for (obn = tc2->cell; obn->type == PORT; obn = obn->next) { + for (obn = tc2->cell; obn && (obn->type == PORT); obn = obn->next) { if (obn->model.port == -1) { if (obn->node == -1) { // This only happens when pins have become separated from any net. diff --git a/base/spice.c b/base/spice.c index f82f861..4168c5d 100644 --- a/base/spice.c +++ b/base/spice.c @@ -626,7 +626,7 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr, } SpiceTokNoNewline(); } - SetClass((blackbox) ? CLASS_MODULE : CLASS_SUBCKT); + SetClass((blackbox) ? CLASS_MODULE : CLASS_SUBCKT); if (hasports == 0) { // If the cell defines no ports, then create a proxy diff --git a/tcltk/netgen.tcl.in b/tcltk/netgen.tcl.in index bd721a5..03ba378 100644 --- a/tcltk/netgen.tcl.in +++ b/tcltk/netgen.tcl.in @@ -370,7 +370,6 @@ proc netgen::convert_to_json {filename lvs_final} { proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { set dolist 0 set dojson 0 - puts stdout "Diagnostic version" foreach arg $args { if {$arg == "-list"} { puts stdout "Generating list result" diff --git a/tcltk/tclnetgen.c b/tcltk/tclnetgen.c index ae0e562..3a23036 100644 --- a/tcltk/tclnetgen.c +++ b/tcltk/tclnetgen.c @@ -1676,6 +1676,13 @@ _netgen_model(ClientData clientData, retclass = modelclasses[SUBCKT_IDX]; break; + case CLASS_MODULE: + if (auto_blackbox) + retclass = modelclasses[BLACKBOX_IDX]; + else + retclass = modelclasses[MODULE_IDX]; + break; + default: /* (includes case CLASS_UNDEF) */ retclass = modelclasses[UNDEF_IDX]; break; @@ -2713,10 +2720,10 @@ _netcmp_equate(ClientData clientData, }; int result, index; char *name1 = NULL, *name2 = NULL, *optstart; - struct nlist *tp1, *tp2; + struct nlist *tp1, *tp2, *SaveC1, *SaveC2; struct objlist *ob1, *ob2; int file1, file2; - int i, l1, l2, ltest, lent, dolist; + int i, l1, l2, ltest, lent, dolist = 0; Tcl_Obj *tobj1, *tobj2, *tobj3; if (objc > 1) { @@ -2884,7 +2891,7 @@ _netcmp_equate(ClientData clientData, break; case PINS_IDX: - if (ElementClasses == NULL) { + if ((ElementClasses == NULL) && (auto_blackbox == FALSE)) { if (CurrentCell == NULL) Fprintf(stderr, "Equate elements: no current cell.\n"); Fprintf(stderr, "Equate pins: cell %s and/or %s has no elements.\n", @@ -2892,20 +2899,30 @@ _netcmp_equate(ClientData clientData, Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); return TCL_OK; } - if (tp1 == Circuit1 && tp2 == Circuit2) { - int result; - if (MatchPins(tp1, tp2, dolist)) { - Fprintf(stdout, "Cell pin lists are equivalent.\n"); - Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); - } - else { - Fprintf(stdout, "Cell pin lists for %s and %s altered to match.\n", - name1, name2); - Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); - } + else if (ElementClasses == NULL) { + /* This has been called outside of a netlist compare, */ + /* probably to force name matching of pins on black-box */ + /* devices. But MatchPins only works if tp1 == Circuit1 */ + /* and tp2 == Circuit2, so preserve these values and */ + /* recover afterward (what a hack). */ + SaveC1 = Circuit1; + SaveC2 = Circuit2; + Circuit1 = tp1; + Circuit2 = tp2; + } + if (MatchPins(tp1, tp2, dolist)) { + Fprintf(stdout, "Cell pin lists are equivalent.\n"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); } else { - Fprintf(stderr, "Function not defined outside of LVS scope.\n"); + Fprintf(stdout, "Cell pin lists for %s and %s altered to match.\n", + name1, name2); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + } + if (ElementClasses == NULL) { + /* Recover temporarily set global variables (see above) */ + Circuit1 = SaveC1; + Circuit2 = SaveC2; } break;