From 2569a06c1f30b88af1bb46d9829cd1970d57da78 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 13 Mar 2020 10:33:44 -0400 Subject: [PATCH 1/2] 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. --- .gitignore | 2 +- database/DBio.c | 3 +- extflat/EFbuild.c | 140 ++++++++++++++++++++++++------------------- extflat/EFflat.c | 31 +++++++--- extflat/extflat.h | 1 + extract/ExtHier.c | 1 - extract/ExtSubtree.c | 4 +- utils/Depend | 4 +- utils/hash.c | 5 +- 9 files changed, 114 insertions(+), 77 deletions(-) diff --git a/.gitignore b/.gitignore index beef7e8d..a632599a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ defs.mak -Depend +*/Depend config.cache config.log scripts/config.log diff --git a/database/DBio.c b/database/DBio.c index 9043c47f..0b74ef67 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -1455,7 +1455,8 @@ badTransform: 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 " "path %s but cell was previously read from %s.\n", diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index 46932d43..f4ba250b 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -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_ytop = newnode->efnode_loc.r_ybot + 1; newnode->efnode_client = (ClientData) NULL; + newnode->efnode_num = 1; if (layerName) newnode->efnode_type = efBuildAddStr(EFLayerNames, &EFLayerNumNames, MAXTYPES, layerName); else newnode->efnode_type = 0; @@ -464,7 +465,7 @@ efBuildEquiv(def, nodeName1, nodeName2) { if (efWarn) efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2); - efNodeMerge(nn1->efnn_node, nn2->efnn_node); + efNodeMerge(&nn1->efnn_node, &nn2->efnn_node); } return; } @@ -1580,70 +1581,86 @@ efNodeAddName(node, he, hn) */ void -efNodeMerge(node1, node2) - EFNode *node1, *node2; /* Hierarchical nodes */ +efNodeMerge(node1ptr, node2ptr) + EFNode **node1ptr, **node2ptr; /* Pointers to hierarchical nodes */ { EFNodeName *nn, *nnlast; EFAttr *ap; int n; + EFNode *keeping, *removing; /* Sanity check: ignore if same node */ - if (node1 == node2) + if (*node1ptr == *node2ptr) 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 (HashLookOnly(&efWatchTable, (char *) node1->efnode_name->efnn_hier) - || (node2->efnode_name + if (HashLookOnly(&efWatchTable, (char *) keeping->efnode_name->efnn_hier) + || (removing->efnode_name && HashLookOnly(&efWatchTable, - (char *) node2->efnode_name->efnn_hier))) + (char *) removing->efnode_name->efnn_hier))) { printf("\ncombine: %s\n", - EFHNToStr(node1->efnode_name->efnn_hier)); + EFHNToStr(keeping->efnode_name->efnn_hier)); printf(" with %s\n\n", - node2->efnode_name - ? EFHNToStr(node2->efnode_name->efnn_hier) + removing->efnode_name + ? EFHNToStr(removing->efnode_name->efnn_hier) : "(unnamed)"); } } /* Sum capacitances, perimeters, areas */ - node1->efnode_cap += node2->efnode_cap; + keeping->efnode_cap += removing->efnode_cap; for (n = 0; n < efNumResistClasses; n++) { - node1->efnode_pa[n].pa_area += node2->efnode_pa[n].pa_area; - node1->efnode_pa[n].pa_perim += node2->efnode_pa[n].pa_perim; + keeping->efnode_pa[n].pa_area += removing->efnode_pa[n].pa_area; + keeping->efnode_pa[n].pa_perim += removing->efnode_pa[n].pa_perim; } - /* Make all EFNodeNames point to node1 */ - if (node2->efnode_name) + /* Make all EFNodeNames point to "keeping" */ + 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; - nn->efnn_node = node1; + nn->efnn_node = keeping; } - topport1 = (node1->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE; - topport2 = (node2->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE; + topportk = (keeping->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE; + topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE; /* Concatenate list of EFNodeNames, taking into account precedence */ - if (!topport1 && (topport2 || EFHNBest(node2->efnode_name->efnn_hier, - node1->efnode_name->efnn_hier))) + if ((!keeping->efnode_name) || (!topportk && (topportr + || 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: - * node2-names, node1-names + * removing-names, keeping-names */ - nnlast->efnn_next = node1->efnode_name; - node1->efnode_name = node2->efnode_name; + nnlast->efnn_next = keeping->efnode_name; + keeping->efnode_name = removing->efnode_name; /* - * Choose the new location only if node2's location is a valid one, - * i.e, node2 wasn't created before it was mentioned. This is mainly + * Choose the new location only if "removing"'s location is a valid one, + * i.e, "removing" wasn't created before it was mentioned. This is mainly * to deal with new fets, resistors, and capacitors created by resistance * extraction, which appear with their full hierarchical names in the * .ext file for the root cell. @@ -1658,18 +1675,10 @@ efNodeMerge(node1, node2) * * Tim, 6/14/04 */ - if (node2->efnode_type > 0) + if (removing->efnode_type > 0) { - node1->efnode_loc = node2->efnode_loc; - node1->efnode_type = node2->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; - } + keeping->efnode_loc = removing->efnode_loc; + keeping->efnode_type = removing->efnode_type; } } else @@ -1677,52 +1686,59 @@ efNodeMerge(node1, node2) /* * Keep old official name. * 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; - node1->efnode_name->efnn_next = node2->efnode_name; + nnlast->efnn_next = keeping->efnode_name->efnn_next; + keeping->efnode_name->efnn_next = removing->efnode_name; } } + /* Merge list counts */ + keeping->efnode_num += removing->efnode_num; + /* Merge attribute lists */ - if (ap = node2->efnode_attrs) + if (ap = removing->efnode_attrs) { while (ap->efa_next) ap = ap->efa_next; - ap->efa_next = node1->efnode_attrs; - node1->efnode_attrs = ap; - node2->efnode_attrs = (EFAttr *) NULL; /* Sanity */ + ap->efa_next = keeping->efnode_attrs; + keeping->efnode_attrs = ap; + removing->efnode_attrs = (EFAttr *) NULL; /* Sanity */ } - /* Unlink node2 from list for def */ - node2->efnode_prev->efnhdr_next = node2->efnode_next; - node2->efnode_next->efnhdr_prev = node2->efnode_prev; + /* Unlink "removing" from list for def */ + removing->efnode_prev->efnhdr_next = removing->efnode_next; + removing->efnode_next->efnhdr_prev = removing->efnode_prev; /* * Only if both nodes were EF_DEVTERM do we keep EF_DEVTERM set * in the resultant node. */ - if ((node2->efnode_flags & EF_DEVTERM) == 0) - node1->efnode_flags &= ~EF_DEVTERM; + if ((removing->efnode_flags & EF_DEVTERM) == 0) + 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. */ - if (node2->efnode_flags & EF_PORT) - node1->efnode_flags |= EF_PORT; - if (node2->efnode_flags & EF_TOP_PORT) - node1->efnode_flags |= EF_TOP_PORT; + if (removing->efnode_flags & EF_PORT) + keeping->efnode_flags |= EF_PORT; + if (removing->efnode_flags & EF_TOP_PORT) + keeping->efnode_flags |= EF_TOP_PORT; /* - * If node2 has the EF_SUBS_NODE flag set, then copy the port - * record in the flags to node1. + * If "removing" has the EF_SUBS_NODE flag set, then copy the port + * record in the flags to "keeping". */ - if (node2->efnode_flags & EF_SUBS_NODE) - node1->efnode_flags |= EF_SUBS_NODE; + if (removing->efnode_flags & EF_SUBS_NODE) + keeping->efnode_flags |= EF_SUBS_NODE; - /* Get rid of node2 */ - freeMagic((char *) node2); + /* Get rid of "removing" */ + freeMagic((char *) removing); + + /* Make sure that the active node is always node1 */ + *node1ptr = keeping; + *node2ptr = (EFNode *)NULL; /* Sanity check */ } diff --git a/extflat/EFflat.c b/extflat/EFflat.c index 239edb25..3e4f6fda 100644 --- a/extflat/EFflat.c +++ b/extflat/EFflat.c @@ -62,6 +62,11 @@ int efAddNodes(HierContext *, bool); int efAddConns(HierContext *, 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) efFlatNodesStdCell(&efFlatContext); else - efFlatNodes(&efFlatContext, FALSE, TRUE); + { + int flags = FLATNODE_DOWARN; /* No FLATNODE_STDCELL flag */ + efFlatNodes(&efFlatContext, (ClientData)flags); + } efFlatKills(&efFlatContext); if (!(flags & EF_NONAMEMERGE)) efFlatGlob(); @@ -166,6 +174,7 @@ EFFlatBuildOneLevel(def, flags) Use *use; int efFlatNodesDeviceless(); /* Forward declaration */ int efFlatCapsDeviceless(); /* Forward declaration */ + int flatnodeflags; efFlatRootDef = def; @@ -195,7 +204,8 @@ EFFlatBuildOneLevel(def, flags) efFlatRootUse.use_def = efFlatRootDef; /* 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 */ /* no active devices (including those in subcells). */ @@ -292,10 +302,16 @@ EFFlatDone() */ int -efFlatNodes(hc, stdcell, doWarn) +efFlatNodes(hc, clientData) 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 */ efAddNodes(hc, stdcell); @@ -466,6 +482,7 @@ efAddNodes(hc, stdcell) newnode->efnode_client = (ClientData) NULL; newnode->efnode_flags = node->efnode_flags; newnode->efnode_type = node->efnode_type; + newnode->efnode_num = 1; if (!stdcell) bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa, efNumResistClasses * sizeof (EFPerimArea)); @@ -514,7 +531,7 @@ efAddNodes(hc, stdcell) if (hierName != nn->efnn_hier) EFHNFree(hierName, hc->hc_hierName, HN_CONCAT); if (oldname->efnn_node != newnode) - efNodeMerge(oldname->efnn_node, newnode); + efNodeMerge(&oldname->efnn_node, &newnode); newnode = oldname->efnn_node; continue; } @@ -638,7 +655,7 @@ efAddOneConn(hc, name1, name2, conn, doWarn) return 0; newnode = ((EFNodeName *) HashGetValue(he2))->efnn_node; if (node != newnode) - efNodeMerge(node, newnode); + efNodeMerge(&node, &newnode); } return 0; @@ -744,7 +761,7 @@ efFlatGlob() { efFlatGlobError(nameGlob, nameFlat); } - efNodeMerge(nodeFlat, nodeGlob); + efNodeMerge(&nodeFlat, &nodeGlob); nameGlob->efnn_node = nodeFlat; } } diff --git a/extflat/extflat.h b/extflat/extflat.h index d7dec156..86eda232 100644 --- a/extflat/extflat.h +++ b/extflat/extflat.h @@ -212,6 +212,7 @@ typedef struct efnode EFCapValue efnode_cap; /* Total capacitance to ground for this 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 * node. This information is provided in the * .ext file so it will be easy to map between diff --git a/extract/ExtHier.c b/extract/ExtHier.c index f08a6e18..1ad5ad57 100644 --- a/extract/ExtHier.c +++ b/extract/ExtHier.c @@ -107,7 +107,6 @@ extHierSubstrate(ha, use, x, y) /* Make sure substrate labels are represented */ ExtLabelRegions(use->cu_def, ExtCurStyle->exts_nodeConn, &nodeList, &TiPlaneRect); - ExtResetTiles(use->cu_def, extUnInit); name2 = extNodeName(temp_subsnode); diff --git a/extract/ExtSubtree.c b/extract/ExtSubtree.c index 24c91726..7b553ad9 100644 --- a/extract/ExtSubtree.c +++ b/extract/ExtSubtree.c @@ -145,6 +145,7 @@ extSubtree(parentUse, reg, f) bool result; int cuts, totcuts; float pdone, plast; + SearchContext scx; if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST)) != (EXT_DOCOUPLING|EXT_DOADJUST)) @@ -231,9 +232,8 @@ extSubtree(parentUse, reg, f) { /* Make sure substrate connections have been handled */ /* 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_area = r; scx.scx_use = ha.ha_parentUse; diff --git a/utils/Depend b/utils/Depend index 56e88bb4..4f469cb1 100644 --- a/utils/Depend +++ b/utils/Depend @@ -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 dqueue.o: dqueue.c ../utils/magic.h ../utils/dqueue.h ../utils/malloc.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 fraction.o: fraction.c ../utils/magic.h ../utils/geometry.h geometry.o: geometry.c ../utils/magic.h ../utils/geometry.h \ diff --git a/utils/hash.c b/utils/hash.c index ca231369..7c20582e 100644 --- a/utils/hash.c +++ b/utils/hash.c @@ -220,14 +220,15 @@ hash(table, key) char *key; { unsigned *up; - int i, j; + unsigned long i; + int j; i = 0; switch (table->ht_ptrKeys) { /* Add up the characters as though this were a number */ case HT_STRINGKEYS: - while (*key != 0) i = (i*10) + (*key++ - '0'); + while (*key != 0) i = (*key++) + (i << 6) + (i << 16) - i; break; /* Map the key into another 32-bit value if necessary */ From 2788fd70ab2e5eeec3f3920ec8d39c4031904792 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 13 Mar 2020 11:36:42 -0400 Subject: [PATCH 2/2] One more change to the extraction method to avoid extracting the substrate more than once for the same subcell, since the substrate extraction method scans the entire plane area; this was making large standard cell layouts extract very slowly, as every component cell was causing the substrate search to be repeated. --- calma/CalmaRdcl.c | 5 +++++ database/database.h.in | 5 +++++ extract/ExtHier.c | 4 ++++ extract/ExtSubtree.c | 25 +++++++++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/calma/CalmaRdcl.c b/calma/CalmaRdcl.c index 8ddb065f..d6c4d1af 100644 --- a/calma/CalmaRdcl.c +++ b/calma/CalmaRdcl.c @@ -345,6 +345,7 @@ calmaParseStructure(filename) } } cifReadCellDef = calmaFindCell(strname, &was_called); + def->cd_flags &= ~CDDEREFERENCE; DBCellClearDef(cifReadCellDef); DBCellSetAvail(cifReadCellDef); HashSetValue(he, cifReadCellDef); @@ -664,6 +665,10 @@ calmaElementSref(filename) TxPrintf("Cell definition %s does not exist!\n", sname); fseek(calmaInputFile, originalFilePos, SEEK_SET); def = calmaFindCell(sname, NULL); + /* Cell flags set to "dereferenced" in case there is no */ + /* definition in the GDS file. If there is a definition */ + /* made after the instance, then the flag will be cleared. */ + def->cd_flags |= CDDEREFERENCE; } } diff --git a/database/database.h.in b/database/database.h.in index d3aec04a..2aa64832 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -498,6 +498,11 @@ typedef struct celluse */ #define CU_SELECT_NET 0x02 #define CU_SELECT_CHUNK 0x04 +/* CU_SUB_EXTRACTED is a temporary flag indicating that the substrate + * of the use has been extracted and the extraction + * does not need to be repeated for this use. + */ +#define CU_SUB_EXTRACTED 0x08 /* Character prefix used to denote a locked cell use in a .mag file */ #define CULOCKCHAR '*' diff --git a/extract/ExtHier.c b/extract/ExtHier.c index 1ad5ad57..f5a4dfe1 100644 --- a/extract/ExtHier.c +++ b/extract/ExtHier.c @@ -91,6 +91,10 @@ extHierSubstrate(ha, use, x, y) /* define a substrate plane or substrate connections. */ if (glob_subsnode == NULL) return; + /* If the substrate has already been extracted for this use */ + /* then there is no need to do it again. */ + if (use->cu_flags & CU_SUB_EXTRACTED) return; + def = (CellDef *)ha->ha_parentUse->cu_def; /* Register the name of the parent's substrate */ diff --git a/extract/ExtSubtree.c b/extract/ExtSubtree.c index 7b553ad9..b3da7956 100644 --- a/extract/ExtSubtree.c +++ b/extract/ExtSubtree.c @@ -93,6 +93,26 @@ void extSubtreeAdjustInit(); void extSubtreeOutputCoupling(); void extSubtreeHardSearch(); +/* + * ---------------------------------------------------------------------------- + * + * extClearUseFlags -- + * + * Callback function to clear the CU_SUB_EXTRACTED flag from each child + * use of a CellDef. + * + * ---------------------------------------------------------------------------- + */ + +int +extClearUseFlags(use, clientData) + CellUse *use; + ClientData clientData; +{ + use->cu_flags &= ~CU_SUB_EXTRACTED; + return 0; +} + /* * ---------------------------------------------------------------------------- @@ -292,6 +312,9 @@ done: /* Output connections and node adjustments */ extOutputConns(&ha.ha_connHash, f); HashKill(&ha.ha_connHash); + + /* Clear the CU_SUB_EXTRACTED flag from all children instances */ + DBCellEnum(def, extClearUseFlags, (ClientData)NULL); } #ifdef exactinteractions @@ -800,6 +823,8 @@ extSubtreeFunc(scx, ha) for (y = use->cu_ylo; y <= use->cu_yhi; y++) extHierSubstrate(ha, use, x, y); } + /* Mark substrate as having been extracted for this use. */ + use->cu_flags |= CU_SUB_EXTRACTED; /* Free the cumulative node list we extracted above */ if (ha->ha_cumFlat.et_nodes)