Substantial improvements on several fronts, mostly to do with

extraction:  Fixed a problem causing long extraction times, at
least some of which had to do with a poor string hash function
implementation.  Fixed a huge problem in ext2spice, where the
node merge function was particularly poorly implemented, causing
exponentially increasing processing times with layout size.
Corrected a minor issue with ext2spice where arguments were
improperly specified, causing unnecessary error messages to be
issued.  Fixed an error in the "load -dereference" command option,
which again caused unnecessary error messages to be issued.
Changed .gitignore to ignore Depend files, which are now regenerated
on every build.
This commit is contained in:
Tim Edwards 2020-03-13 10:33:44 -04:00
parent aa738bb350
commit 2569a06c1f
9 changed files with 114 additions and 77 deletions

2
.gitignore vendored
View File

@ -1,5 +1,5 @@
defs.mak defs.mak
Depend */Depend
config.cache config.cache
config.log config.log
scripts/config.log scripts/config.log

View File

@ -1455,7 +1455,8 @@ badTransform:
pathOK = TRUE; pathOK = TRUE;
} }
if ((pathOK == FALSE) && strcmp(subCellDef->cd_file, pathptr)) if ((pathOK == FALSE) && strcmp(subCellDef->cd_file, pathptr)
&& (dereference == FALSE))
{ {
TxError("Duplicate cell in %s: Instance of cell %s is from " TxError("Duplicate cell in %s: Instance of cell %s is from "
"path %s but cell was previously read from %s.\n", "path %s but cell was previously read from %s.\n",

View File

@ -184,6 +184,7 @@ efBuildNode(def, isSubsnode, nodeName, nodeCap, x, y, layerName, av, ac)
newnode->efnode_loc.r_xtop = newnode->efnode_loc.r_xbot + 1; newnode->efnode_loc.r_xtop = newnode->efnode_loc.r_xbot + 1;
newnode->efnode_loc.r_ytop = newnode->efnode_loc.r_ybot + 1; newnode->efnode_loc.r_ytop = newnode->efnode_loc.r_ybot + 1;
newnode->efnode_client = (ClientData) NULL; newnode->efnode_client = (ClientData) NULL;
newnode->efnode_num = 1;
if (layerName) newnode->efnode_type = if (layerName) newnode->efnode_type =
efBuildAddStr(EFLayerNames, &EFLayerNumNames, MAXTYPES, layerName); efBuildAddStr(EFLayerNames, &EFLayerNumNames, MAXTYPES, layerName);
else newnode->efnode_type = 0; else newnode->efnode_type = 0;
@ -464,7 +465,7 @@ efBuildEquiv(def, nodeName1, nodeName2)
{ {
if (efWarn) if (efWarn)
efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2); efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2);
efNodeMerge(nn1->efnn_node, nn2->efnn_node); efNodeMerge(&nn1->efnn_node, &nn2->efnn_node);
} }
return; return;
} }
@ -1580,70 +1581,86 @@ efNodeAddName(node, he, hn)
*/ */
void void
efNodeMerge(node1, node2) efNodeMerge(node1ptr, node2ptr)
EFNode *node1, *node2; /* Hierarchical nodes */ EFNode **node1ptr, **node2ptr; /* Pointers to hierarchical nodes */
{ {
EFNodeName *nn, *nnlast; EFNodeName *nn, *nnlast;
EFAttr *ap; EFAttr *ap;
int n; int n;
EFNode *keeping, *removing;
/* Sanity check: ignore if same node */ /* Sanity check: ignore if same node */
if (node1 == node2) if (*node1ptr == *node2ptr)
return; return;
/* Keep the node with the greater number of entries, and merge */
/* the node with fewer entries into it. */
if ((*node1ptr)->efnode_num >= (*node2ptr)->efnode_num)
{
keeping = *node1ptr;
removing = *node2ptr;
}
else
{
keeping = *node2ptr;
removing = *node1ptr;
}
if (efWatchNodes) if (efWatchNodes)
{ {
if (HashLookOnly(&efWatchTable, (char *) node1->efnode_name->efnn_hier) if (HashLookOnly(&efWatchTable, (char *) keeping->efnode_name->efnn_hier)
|| (node2->efnode_name || (removing->efnode_name
&& HashLookOnly(&efWatchTable, && HashLookOnly(&efWatchTable,
(char *) node2->efnode_name->efnn_hier))) (char *) removing->efnode_name->efnn_hier)))
{ {
printf("\ncombine: %s\n", printf("\ncombine: %s\n",
EFHNToStr(node1->efnode_name->efnn_hier)); EFHNToStr(keeping->efnode_name->efnn_hier));
printf(" with %s\n\n", printf(" with %s\n\n",
node2->efnode_name removing->efnode_name
? EFHNToStr(node2->efnode_name->efnn_hier) ? EFHNToStr(removing->efnode_name->efnn_hier)
: "(unnamed)"); : "(unnamed)");
} }
} }
/* Sum capacitances, perimeters, areas */ /* Sum capacitances, perimeters, areas */
node1->efnode_cap += node2->efnode_cap; keeping->efnode_cap += removing->efnode_cap;
for (n = 0; n < efNumResistClasses; n++) for (n = 0; n < efNumResistClasses; n++)
{ {
node1->efnode_pa[n].pa_area += node2->efnode_pa[n].pa_area; keeping->efnode_pa[n].pa_area += removing->efnode_pa[n].pa_area;
node1->efnode_pa[n].pa_perim += node2->efnode_pa[n].pa_perim; keeping->efnode_pa[n].pa_perim += removing->efnode_pa[n].pa_perim;
} }
/* Make all EFNodeNames point to node1 */ /* Make all EFNodeNames point to "keeping" */
if (node2->efnode_name) if (removing->efnode_name)
{ {
bool topport1, topport2; bool topportk, topportr;
for (nn = node2->efnode_name; nn; nn = nn->efnn_next) for (nn = removing->efnode_name; nn; nn = nn->efnn_next)
{ {
nnlast = nn; nnlast = nn;
nn->efnn_node = node1; nn->efnn_node = keeping;
} }
topport1 = (node1->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE; topportk = (keeping->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
topport2 = (node2->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE; topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
/* Concatenate list of EFNodeNames, taking into account precedence */ /* Concatenate list of EFNodeNames, taking into account precedence */
if (!topport1 && (topport2 || EFHNBest(node2->efnode_name->efnn_hier, if ((!keeping->efnode_name) || (!topportk && (topportr
node1->efnode_name->efnn_hier))) || EFHNBest(removing->efnode_name->efnn_hier,
keeping->efnode_name->efnn_hier))))
{ {
/* /*
* New official name is that of node2. * New official name is that of "removing".
* The new list of names is: * The new list of names is:
* node2-names, node1-names * removing-names, keeping-names
*/ */
nnlast->efnn_next = node1->efnode_name; nnlast->efnn_next = keeping->efnode_name;
node1->efnode_name = node2->efnode_name; keeping->efnode_name = removing->efnode_name;
/* /*
* Choose the new location only if node2's location is a valid one, * Choose the new location only if "removing"'s location is a valid one,
* i.e, node2 wasn't created before it was mentioned. This is mainly * i.e, "removing" wasn't created before it was mentioned. This is mainly
* to deal with new fets, resistors, and capacitors created by resistance * to deal with new fets, resistors, and capacitors created by resistance
* extraction, which appear with their full hierarchical names in the * extraction, which appear with their full hierarchical names in the
* .ext file for the root cell. * .ext file for the root cell.
@ -1658,18 +1675,10 @@ efNodeMerge(node1, node2)
* *
* Tim, 6/14/04 * Tim, 6/14/04
*/ */
if (node2->efnode_type > 0) if (removing->efnode_type > 0)
{ {
node1->efnode_loc = node2->efnode_loc; keeping->efnode_loc = removing->efnode_loc;
node1->efnode_type = node2->efnode_type; keeping->efnode_type = removing->efnode_type;
if (node2->efnode_loc.r_ybot < node1->efnode_loc.r_ybot
|| (node2->efnode_loc.r_ybot == node1->efnode_loc.r_ybot
&& node2->efnode_loc.r_xbot < node1->efnode_loc.r_xbot))
{
// node1->efnode_loc = node2->efnode_loc;
// node1->efnode_type = node2->efnode_type;
}
} }
} }
else else
@ -1677,52 +1686,59 @@ efNodeMerge(node1, node2)
/* /*
* Keep old official name. * Keep old official name.
* The new list of names is: * The new list of names is:
* node1-names[0], node2-names, node1-names[1-] * keeping-names[0], removing-names, keeping-names[1-]
*/ */
nnlast->efnn_next = node1->efnode_name->efnn_next; nnlast->efnn_next = keeping->efnode_name->efnn_next;
node1->efnode_name->efnn_next = node2->efnode_name; keeping->efnode_name->efnn_next = removing->efnode_name;
} }
} }
/* Merge list counts */
keeping->efnode_num += removing->efnode_num;
/* Merge attribute lists */ /* Merge attribute lists */
if (ap = node2->efnode_attrs) if (ap = removing->efnode_attrs)
{ {
while (ap->efa_next) while (ap->efa_next)
ap = ap->efa_next; ap = ap->efa_next;
ap->efa_next = node1->efnode_attrs; ap->efa_next = keeping->efnode_attrs;
node1->efnode_attrs = ap; keeping->efnode_attrs = ap;
node2->efnode_attrs = (EFAttr *) NULL; /* Sanity */ removing->efnode_attrs = (EFAttr *) NULL; /* Sanity */
} }
/* Unlink node2 from list for def */ /* Unlink "removing" from list for def */
node2->efnode_prev->efnhdr_next = node2->efnode_next; removing->efnode_prev->efnhdr_next = removing->efnode_next;
node2->efnode_next->efnhdr_prev = node2->efnode_prev; removing->efnode_next->efnhdr_prev = removing->efnode_prev;
/* /*
* Only if both nodes were EF_DEVTERM do we keep EF_DEVTERM set * Only if both nodes were EF_DEVTERM do we keep EF_DEVTERM set
* in the resultant node. * in the resultant node.
*/ */
if ((node2->efnode_flags & EF_DEVTERM) == 0) if ((removing->efnode_flags & EF_DEVTERM) == 0)
node1->efnode_flags &= ~EF_DEVTERM; keeping->efnode_flags &= ~EF_DEVTERM;
/* /*
* If node2 has the EF_PORT flag set, then copy the port * If "removing" has the EF_PORT flag set, then copy the port
* record in the flags to node1. * record in the flags to node1.
*/ */
if (node2->efnode_flags & EF_PORT) if (removing->efnode_flags & EF_PORT)
node1->efnode_flags |= EF_PORT; keeping->efnode_flags |= EF_PORT;
if (node2->efnode_flags & EF_TOP_PORT) if (removing->efnode_flags & EF_TOP_PORT)
node1->efnode_flags |= EF_TOP_PORT; keeping->efnode_flags |= EF_TOP_PORT;
/* /*
* If node2 has the EF_SUBS_NODE flag set, then copy the port * If "removing" has the EF_SUBS_NODE flag set, then copy the port
* record in the flags to node1. * record in the flags to "keeping".
*/ */
if (node2->efnode_flags & EF_SUBS_NODE) if (removing->efnode_flags & EF_SUBS_NODE)
node1->efnode_flags |= EF_SUBS_NODE; keeping->efnode_flags |= EF_SUBS_NODE;
/* Get rid of node2 */ /* Get rid of "removing" */
freeMagic((char *) node2); freeMagic((char *) removing);
/* Make sure that the active node is always node1 */
*node1ptr = keeping;
*node2ptr = (EFNode *)NULL; /* Sanity check */
} }

View File

@ -62,6 +62,11 @@ int efAddNodes(HierContext *, bool);
int efAddConns(HierContext *, bool); int efAddConns(HierContext *, bool);
int efAddOneConn(HierContext *, char *, char *, Connection *, bool); int efAddOneConn(HierContext *, char *, char *, Connection *, bool);
/* Flags passed to efFlatNode() */
#define FLATNODE_STDCELL 0x01
#define FLATNODE_DOWARN 0x02
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
@ -127,7 +132,10 @@ EFFlatBuild(name, flags)
if (flags & EF_NOFLATSUBCKT) if (flags & EF_NOFLATSUBCKT)
efFlatNodesStdCell(&efFlatContext); efFlatNodesStdCell(&efFlatContext);
else else
efFlatNodes(&efFlatContext, FALSE, TRUE); {
int flags = FLATNODE_DOWARN; /* No FLATNODE_STDCELL flag */
efFlatNodes(&efFlatContext, (ClientData)flags);
}
efFlatKills(&efFlatContext); efFlatKills(&efFlatContext);
if (!(flags & EF_NONAMEMERGE)) if (!(flags & EF_NONAMEMERGE))
efFlatGlob(); efFlatGlob();
@ -166,6 +174,7 @@ EFFlatBuildOneLevel(def, flags)
Use *use; Use *use;
int efFlatNodesDeviceless(); /* Forward declaration */ int efFlatNodesDeviceless(); /* Forward declaration */
int efFlatCapsDeviceless(); /* Forward declaration */ int efFlatCapsDeviceless(); /* Forward declaration */
int flatnodeflags;
efFlatRootDef = def; efFlatRootDef = def;
@ -195,7 +204,8 @@ EFFlatBuildOneLevel(def, flags)
efFlatRootUse.use_def = efFlatRootDef; efFlatRootUse.use_def = efFlatRootDef;
/* Record all nodes down the hierarchy from here */ /* Record all nodes down the hierarchy from here */
efFlatNodes(&efFlatContext, (ClientData)TRUE, (ClientData)FALSE); flatnodeflags = FLATNODE_STDCELL; /* No FLATDNODE_DOWARN flag */
efFlatNodes(&efFlatContext, (ClientData)flatnodeflags);
/* Expand all subcells that contain connectivity information but */ /* Expand all subcells that contain connectivity information but */
/* no active devices (including those in subcells). */ /* no active devices (including those in subcells). */
@ -292,10 +302,16 @@ EFFlatDone()
*/ */
int int
efFlatNodes(hc, stdcell, doWarn) efFlatNodes(hc, clientData)
HierContext *hc; HierContext *hc;
ClientData clientData;
{ {
(void) efHierSrUses(hc, efFlatNodes); int flags = (int)clientData;
bool stdcell = (flags & FLATNODE_STDCELL) ? TRUE : FALSE;
bool doWarn = (flags & FLATNODE_DOWARN) ? TRUE : FALSE;
(void) efHierSrUses(hc, efFlatNodes, clientData);
/* Add all our own nodes to the table */ /* Add all our own nodes to the table */
efAddNodes(hc, stdcell); efAddNodes(hc, stdcell);
@ -466,6 +482,7 @@ efAddNodes(hc, stdcell)
newnode->efnode_client = (ClientData) NULL; newnode->efnode_client = (ClientData) NULL;
newnode->efnode_flags = node->efnode_flags; newnode->efnode_flags = node->efnode_flags;
newnode->efnode_type = node->efnode_type; newnode->efnode_type = node->efnode_type;
newnode->efnode_num = 1;
if (!stdcell) if (!stdcell)
bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa, bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa,
efNumResistClasses * sizeof (EFPerimArea)); efNumResistClasses * sizeof (EFPerimArea));
@ -514,7 +531,7 @@ efAddNodes(hc, stdcell)
if (hierName != nn->efnn_hier) if (hierName != nn->efnn_hier)
EFHNFree(hierName, hc->hc_hierName, HN_CONCAT); EFHNFree(hierName, hc->hc_hierName, HN_CONCAT);
if (oldname->efnn_node != newnode) if (oldname->efnn_node != newnode)
efNodeMerge(oldname->efnn_node, newnode); efNodeMerge(&oldname->efnn_node, &newnode);
newnode = oldname->efnn_node; newnode = oldname->efnn_node;
continue; continue;
} }
@ -638,7 +655,7 @@ efAddOneConn(hc, name1, name2, conn, doWarn)
return 0; return 0;
newnode = ((EFNodeName *) HashGetValue(he2))->efnn_node; newnode = ((EFNodeName *) HashGetValue(he2))->efnn_node;
if (node != newnode) if (node != newnode)
efNodeMerge(node, newnode); efNodeMerge(&node, &newnode);
} }
return 0; return 0;
@ -744,7 +761,7 @@ efFlatGlob()
{ {
efFlatGlobError(nameGlob, nameFlat); efFlatGlobError(nameGlob, nameFlat);
} }
efNodeMerge(nodeFlat, nodeGlob); efNodeMerge(&nodeFlat, &nodeGlob);
nameGlob->efnn_node = nodeFlat; nameGlob->efnn_node = nodeFlat;
} }
} }

View File

@ -212,6 +212,7 @@ typedef struct efnode
EFCapValue efnode_cap; /* Total capacitance to ground for this node */ EFCapValue efnode_cap; /* Total capacitance to ground for this node */
int efnode_type; /* Index into type table for node */ int efnode_type; /* Index into type table for node */
int efnode_num; /* Number of items in efnode_hdr list */
Rect efnode_loc; /* Location of a 1x1 rect contained in this Rect efnode_loc; /* Location of a 1x1 rect contained in this
* node. This information is provided in the * node. This information is provided in the
* .ext file so it will be easy to map between * .ext file so it will be easy to map between

View File

@ -107,7 +107,6 @@ extHierSubstrate(ha, use, x, y)
/* Make sure substrate labels are represented */ /* Make sure substrate labels are represented */
ExtLabelRegions(use->cu_def, ExtCurStyle->exts_nodeConn, &nodeList, ExtLabelRegions(use->cu_def, ExtCurStyle->exts_nodeConn, &nodeList,
&TiPlaneRect); &TiPlaneRect);
ExtResetTiles(use->cu_def, extUnInit); ExtResetTiles(use->cu_def, extUnInit);
name2 = extNodeName(temp_subsnode); name2 = extNodeName(temp_subsnode);

View File

@ -145,6 +145,7 @@ extSubtree(parentUse, reg, f)
bool result; bool result;
int cuts, totcuts; int cuts, totcuts;
float pdone, plast; float pdone, plast;
SearchContext scx;
if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST)) if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST))
!= (EXT_DOCOUPLING|EXT_DOADJUST)) != (EXT_DOCOUPLING|EXT_DOADJUST))
@ -231,9 +232,8 @@ extSubtree(parentUse, reg, f)
{ {
/* Make sure substrate connections have been handled */ /* Make sure substrate connections have been handled */
/* even if there were no other interactions found. */ /* even if there were no other interactions found. */
SearchContext scx;
GEOCLIP(&ha.ha_clipArea, &r); ha.ha_clipArea = r;
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
scx.scx_area = r; scx.scx_area = r;
scx.scx_use = ha.ha_parentUse; scx.scx_use = ha.ha_parentUse;

View File

@ -2,7 +2,9 @@ args.o: args.c ../utils/magic.h ../utils/utils.h
child.o: child.c ../utils/utils.h ../utils/magic.h ../utils/malloc.h child.o: child.c ../utils/utils.h ../utils/magic.h ../utils/malloc.h
dqueue.o: dqueue.c ../utils/magic.h ../utils/dqueue.h ../utils/malloc.h dqueue.o: dqueue.c ../utils/magic.h ../utils/dqueue.h ../utils/malloc.h
finddisp.o: finddisp.c ../utils/magic.h ../utils/utils.h finddisp.o: finddisp.c ../utils/magic.h ../utils/utils.h
flock.o: flock.c flock.o: flock.c ../utils/magic.h ../utils/hash.h ../utils/geometry.h \
../tiles/tile.h ../database/database.h ../windows/windows.h \
../utils/malloc.h
flsbuf.o: flsbuf.c flsbuf.o: flsbuf.c
fraction.o: fraction.c ../utils/magic.h ../utils/geometry.h fraction.o: fraction.c ../utils/magic.h ../utils/geometry.h
geometry.o: geometry.c ../utils/magic.h ../utils/geometry.h \ geometry.o: geometry.c ../utils/magic.h ../utils/geometry.h \

View File

@ -220,14 +220,15 @@ hash(table, key)
char *key; char *key;
{ {
unsigned *up; unsigned *up;
int i, j; unsigned long i;
int j;
i = 0; i = 0;
switch (table->ht_ptrKeys) switch (table->ht_ptrKeys)
{ {
/* Add up the characters as though this were a number */ /* Add up the characters as though this were a number */
case HT_STRINGKEYS: case HT_STRINGKEYS:
while (*key != 0) i = (i*10) + (*key++ - '0'); while (*key != 0) i = (*key++) + (i << 6) + (i << 16) - i;
break; break;
/* Map the key into another 32-bit value if necessary */ /* Map the key into another 32-bit value if necessary */