From 9f5936c7cbf071cca64621b677c9252f73c8b29c Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 7 Feb 2019 10:54:07 -0500 Subject: [PATCH] Found an additional scaling-up problem in ext2spice (previously handled a scaling issue in extract) which was caused by the addition of hierarchical netlist generation. Finding hierarchical connections requires finding instances by name, so it is vastly better to create a hash table of instances instead of a linked list. --- ext2spice/ext2hier.c | 25 +++++++++------------ extflat/EFbuild.c | 53 +++++++++++++++++++++++++++++++++++++------- extflat/EFdef.c | 11 +++++---- extflat/EFflat.c | 15 +++++-------- extflat/EFhier.c | 12 ++++++++-- extflat/EFint.h | 4 +--- extflat/EFread.c | 9 +++++++- 7 files changed, 85 insertions(+), 44 deletions(-) diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index 6f600f2d..af204cdb 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -1552,7 +1552,8 @@ esMakePorts(hc, cdata) char *name, *portname, *tptr, *aptr, *locname; int j; - if (def->def_uses == NULL) return 0; /* Bottom of hierarchy */ + /* Done when the bottom of the hierarchy is reached */ + if (HashGetNumEntries(&def->def_uses) == 0) return 0; for (conn = (Connection *)def->def_conns; conn; conn = conn->conn_next) { @@ -1579,13 +1580,11 @@ esMakePorts(hc, cdata) // Find the cell for the instance portdef = NULL; - for (use = updef->def_uses; use; use = use->use_next) + he = HashFind(&updef->def_uses, portname); + if (he != NULL) { - if (!strcmp(use->use_id, portname)) - { - portdef = use->use_def; - break; - } + use = (Use *)HashGetValue(he); + portdef = use->use_def; } if ((aptr == NULL) || (aptr > tptr)) *tptr = '/'; @@ -1660,13 +1659,11 @@ esMakePorts(hc, cdata) // Find the cell for the instance portdef = NULL; - for (use = updef->def_uses; use; use = use->use_next) + he = HashFind(&updef->def_uses, portname); + if (he != NULL) { - if (!strcmp(use->use_id, portname)) - { - portdef = use->use_def; - break; - } + use = (Use *)HashGetValue(he); + portdef = use->use_def; } if ((aptr == NULL) || (aptr > tptr)) *tptr = '/'; @@ -1747,7 +1744,7 @@ esHierVisit(hc, cdata) if (def != topdef) { - if (def->def_devs == NULL && def->def_uses == NULL) + if ((def->def_devs == NULL) && (HashGetNumEntries(&def->def_uses) == 0)) { if (locDoSubckt == AUTO) { diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index 061dd12d..d6b11fd6 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -1098,6 +1098,7 @@ efBuildUse(def, subDefName, subUseId, ta, tb, tc, td, te, tf) Use *newuse; Def *newdef; char *cp; + HashEntry *he; newdef = efDefLook(subDefName); if (newdef == NULL) @@ -1111,8 +1112,6 @@ efBuildUse(def, subDefName, subUseId, ta, tb, tc, td, te, tf) newuse->use_trans.t_d = td; newuse->use_trans.t_e = te; newuse->use_trans.t_f = tf; - newuse->use_next = def->def_uses; - def->def_uses = newuse; /* Set the use identifier and array information */ if ((cp = strchr(subUseId, '[')) == NULL) @@ -1121,15 +1120,21 @@ efBuildUse(def, subDefName, subUseId, ta, tb, tc, td, te, tf) newuse->use_xlo = newuse->use_xhi = 0; newuse->use_ylo = newuse->use_yhi = 0; newuse->use_xsep = newuse->use_ysep = 0; - return; } - - *cp = '\0'; - newuse->use_id = StrDup((char **) NULL, subUseId); - *cp = '['; - (void) sscanf(cp, "[%d:%d:%d][%d:%d:%d]", + else + { + *cp = '\0'; + newuse->use_id = StrDup((char **) NULL, subUseId); + *cp = '['; + (void) sscanf(cp, "[%d:%d:%d][%d:%d:%d]", &newuse->use_xlo, &newuse->use_xhi, &newuse->use_xsep, &newuse->use_ylo, &newuse->use_yhi, &newuse->use_ysep); + } + + he = HashFind(&def->def_uses, newuse->use_id); + if (HashGetValue(he)) + TxError("Warning: use %s appears more than once in def!\n", newuse->use_id); + HashSetValue(he, (ClientData)newuse); } /* @@ -1646,6 +1651,38 @@ efNodeMerge(node1, node2) freeMagic((char *) node2); } + +/* + * ---------------------------------------------------------------------------- + * + * efFreeUseTable -- + * + * Free the cell IDs allocated for each entry in the use hash table, and + * the memory allocated by the cell use, leaving the hash entry null. + * + * ---------------------------------------------------------------------------- + */ + +void +efFreeUseTable(table) + HashTable *table; +{ + HashSearch hs; + HashEntry *he; + Use *use; + HierName *hn; + EFNodeName *nn; + + HashStartSearch(&hs); + while (he = HashNext(table, &hs)) + if (use = (Use *) HashGetValue(he)) + { + if (use->use_id != NULL) freeMagic((char *)use->use_id); + freeMagic(use); + } +} + + /* * ---------------------------------------------------------------------------- * diff --git a/extflat/EFdef.c b/extflat/EFdef.c index 13df4a61..0ef549f1 100644 --- a/extflat/EFdef.c +++ b/extflat/EFdef.c @@ -113,13 +113,10 @@ EFDone() freeMagic(def->def_name); efFreeNodeTable(&def->def_nodes); efFreeNodeList(&def->def_firstn); + efFreeUseTable(&def->def_uses); HashKill(&def->def_nodes); HashKill(&def->def_dists); - for (use = def->def_uses; use; use = use->use_next) - { - freeMagic(use->use_id); - freeMagic((char *) use); - } + HashKill(&def->def_uses); for (conn = def->def_conns; conn; conn = conn->conn_next) efFreeConn(conn); for (conn = def->def_caps; conn; conn = conn->conn_next) @@ -248,13 +245,15 @@ efDefNew(name) newdef->def_caps = (Connection *) NULL; newdef->def_resistors = (Connection *) NULL; newdef->def_devs = (Dev *) NULL; - newdef->def_uses = (Use *) NULL; newdef->def_kills = (Kill *) NULL; /* Initialize circular list of nodes */ newdef->def_firstn.efnode_next = (EFNodeHdr *) &newdef->def_firstn; newdef->def_firstn.efnode_prev = (EFNodeHdr *) &newdef->def_firstn; + /* Initialize hash table of uses */ + HashInit(&newdef->def_uses, INITNODESIZE, HT_STRINGKEYS); + /* Initialize hash table of node names */ HashInit(&newdef->def_nodes, INITNODESIZE, HT_STRINGKEYS); diff --git a/extflat/EFflat.c b/extflat/EFflat.c index c3e2ca20..27e8d4e3 100644 --- a/extflat/EFflat.c +++ b/extflat/EFflat.c @@ -193,16 +193,13 @@ EFFlatBuildOneLevel(def, flags) efFlatContext.hc_x = efFlatContext.hc_y = 0; efFlatRootUse.use_def = efFlatRootDef; - usecount = 0; - /* Record all nodes of the next level in the hierarchy */ efHierSrUses(&efFlatContext, efAddNodes, (ClientData)TRUE); /* Expand all subcells that contain connectivity information but */ /* no active devices (including those in subcells). */ - for (use = efFlatRootUse.use_def->def_uses; use; use = use->use_next) - usecount++; + usecount = HashGetNumEntries(&efFlatRootUse.use_def->def_uses); /* Recursively flatten uses that have no active devices */ if (usecount > 0) @@ -366,11 +363,10 @@ efFlatNodesDeviceless(hc, cdata) ClientData cdata; { int *usecount = (int *)cdata; - int newcount = 0; + int newcount; Use *use; - for (use = hc->hc_use->use_def->def_uses; use; use = use->use_next) - newcount++; + newcount = HashGetNumEntries(&hc->hc_use->use_def->def_uses); /* Recursively flatten uses that have no active devices */ if (newcount > 0) @@ -910,11 +906,10 @@ efFlatCapsDeviceless(hc) HierContext *hc; { Connection *conn; - int newcount = 0; + int newcount; Use *use; - for (use = hc->hc_use->use_def->def_uses; use; use = use->use_next) - newcount++; + newcount = HashGetNumEntries(&hc->hc_use->use_def->def_uses); /* Recursively flatten uses that have no active devices */ if (newcount > 0) diff --git a/extflat/EFhier.c b/extflat/EFhier.c index 599557c3..2b38443e 100644 --- a/extflat/EFhier.c +++ b/extflat/EFhier.c @@ -77,9 +77,13 @@ efHierSrUses(hc, func, cdata) HierContext newhc; Transform t; Use *u; + HashSearch hs; + HashEntry *he; - for (u = hc->hc_use->use_def->def_uses; u; u = u->use_next) + HashStartSearch(&hs); + while (he = HashNext(&hc->hc_use->use_def->def_uses, &hs)) { + u = (Use *)HashGetValue(he); newhc.hc_use = u; if (!IsArray(u)) { @@ -237,6 +241,8 @@ EFHierSrDefs(hc, func, cdata) HierContext newhc; Use *u; int retval; + HashSearch hs; + HashEntry *he; if (func == NULL) { @@ -251,8 +257,10 @@ EFHierSrDefs(hc, func, cdata) hc->hc_use->use_def->def_flags |= DEF_PROCESSED; } - for (u = hc->hc_use->use_def->def_uses; u; u = u->use_next) + HashStartSearch(&hs); + while (he = HashNext(&hc->hc_use->use_def->def_uses, &hs)) { + u = (Use *)HashGetValue(he); newhc.hc_use = u; newhc.hc_hierName = NULL; GeoTransTrans(&u->use_trans, &hc->hc_trans, &newhc.hc_trans); diff --git a/extflat/EFint.h b/extflat/EFint.h index eb819b49..6ec90eca 100644 --- a/extflat/EFint.h +++ b/extflat/EFint.h @@ -155,11 +155,11 @@ typedef struct def int def_flags; /* Flags -- see below */ HashTable def_nodes; /* Map names into EFNodeNames */ HashTable def_dists; /* Map pairs of names into Distances */ + HashTable def_uses; /* Hash children of this def by name */ EFNode def_firstn; /* Head of circular list of nodes */ /* The following are all NULL-terminated lists */ - struct use *def_uses; /* Children of this def */ Connection *def_conns; /* Hierarchical connections/adjustments */ Connection *def_caps; /* Two-terminal capacitors */ Connection *def_resistors; /* Two-terminal resistors */ @@ -199,8 +199,6 @@ typedef struct use { char *use_id; /* Use identifier (appears in hier paths) */ Def *use_def; /* Sub def being used */ - // EFNodeName *use_ports; /* Port connections, for hierarchical output */ - struct use *use_next; /* Next use in list (NULL-terminated) */ Transform use_trans; /* Transform up to parent coords (for fets) */ ArrayInfo use_array; /* Arraying information */ } Use; diff --git a/extflat/EFread.c b/extflat/EFread.c index 4ad44062..c8c4471e 100644 --- a/extflat/EFread.c +++ b/extflat/EFread.c @@ -184,6 +184,8 @@ efReadDef(def, dosubckt, resist, noscale, toplevel) bool rc = TRUE; bool DoResist = resist; bool DoSubCircuit = dosubckt; + HashSearch hs; + HashEntry *he; /* Mark def as available */ def->def_flags |= DEF_AVAILABLE; @@ -611,11 +613,16 @@ resistChanged: DoSubCircuit = FALSE; /* Read in each def that has not yet been read in */ - for (use = def->def_uses; use; use = use->use_next) + + HashStartSearch(&hs); + while (he = HashNext(&def->def_uses, &hs)) + { + use = (Use *)HashGetValue(he); if ((use->use_def->def_flags & DEF_AVAILABLE) == 0) if (efReadDef(use->use_def, DoSubCircuit, resist, noscale, FALSE) != TRUE) rc = FALSE; + } return rc; }