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.
This commit is contained in:
Tim Edwards 2019-02-07 10:54:07 -05:00
parent c669d83dc6
commit 9f5936c7cb
7 changed files with 85 additions and 44 deletions

View File

@ -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)
{

View File

@ -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);
}
}
/*
* ----------------------------------------------------------------------------
*

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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;
}