From 65ef9a1ad3e4aecc20a27d9529974d4842f2d70c Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 19 Nov 2022 22:02:44 -0500 Subject: [PATCH] Final (I hope!) corrections to the "def write" command. --- VERSION | 2 +- ext2sim/ext2sim.c | 1 - ext2spice/ext2hier.c | 10 ++-- ext2spice/ext2spice.c | 2 - extcheck/extcheck.c | 1 - extflat/EFbuild.c | 99 +++++++++++++++++++------------ extflat/EFflat.c | 10 ++++ extflat/EFread.c | 16 +++-- extflat/extflat.h | 21 ++----- lef/defWrite.c | 135 +++++++++++++++++++++++------------------- 10 files changed, 167 insertions(+), 130 deletions(-) diff --git a/VERSION b/VERSION index 2e737e3b..ab619304 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.342 +8.3.343 diff --git a/ext2sim/ext2sim.c b/ext2sim/ext2sim.c index fcf703a5..8f00ea58 100644 --- a/ext2sim/ext2sim.c +++ b/ext2sim/ext2sim.c @@ -1596,7 +1596,6 @@ int simnodeVisit(node, res, cap) char *fmt; EFAttr *ap; - if (node->efnode_flags & EF_UNIQUE_NODE) return 0; if (esDevNodesOnly && node->efnode_client == (ClientData) NULL) return 0; diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index 22ab9a35..8b3f9a31 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -1252,7 +1252,6 @@ spcsubHierVisit(hc, node, res, cap, resstrptr) HierName *hierName; char *nsn; - if (node->efnode_flags & EF_UNIQUE_NODE) return 0; if (node->efnode_flags & EF_GLOB_SUBS_NODE) { hierName = (HierName *) node->efnode_name->efnn_hier; @@ -1293,7 +1292,6 @@ spcnodeHierVisit(hc, node, res, cap) char *fmt, *nsn; EFAttr *ap; - if (node->efnode_flags & EF_UNIQUE_NODE) return 0; if (node->efnode_client) { if (esDistrJunct) @@ -1735,8 +1733,8 @@ esMakePorts(hc, cdata) nn = (EFNodeName *) HashGetValue(he); if (nn == NULL) { - efBuildNode(portdef, FALSE, FALSE, portname, 0.0, - 0, 0, NULL, NULL, 0); + efBuildNode(portdef, FALSE, FALSE, FALSE, portname, + 0.0, 0, 0, NULL, NULL, 0); nn = (EFNodeName *) HashGetValue(he); } @@ -1869,8 +1867,8 @@ esMakePorts(hc, cdata) nn = (EFNodeName *) HashGetValue(he); if (nn == NULL) { - efBuildNode(portdef, FALSE, FALSE, portname, 0.0, - 0, 0, NULL, NULL, 0); + efBuildNode(portdef, FALSE, FALSE, FALSE, portname, + 0.0, 0, 0, NULL, NULL, 0); nn = (EFNodeName *) HashGetValue(he); } diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 7a6a97f6..6ca1b9c6 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -3344,7 +3344,6 @@ spcsubVisit(node, res, cap, resstr) HierName *hierName; char *nsn; - if (node->efnode_flags & EF_UNIQUE_NODE) return 0; if (node->efnode_flags & EF_GLOB_SUBS_NODE) { hierName = (HierName *) node->efnode_name->efnn_hier; @@ -3384,7 +3383,6 @@ spcnodeVisit(node, res, cap) char *fmt, *nsn; EFAttr *ap; - if (node->efnode_flags & EF_UNIQUE_NODE) return 0; if (node->efnode_client) { isConnected = (esDistrJunct) ? diff --git a/extcheck/extcheck.c b/extcheck/extcheck.c index e592e39b..ed0f66ee 100644 --- a/extcheck/extcheck.c +++ b/extcheck/extcheck.c @@ -135,7 +135,6 @@ nodeVisit(node, res, cap) cap = (cap + 500) / 1000; res = (res + 500) / 1000; - if (node->efnode_flags & EF_UNIQUE_NODE) return 0; ecNumNodes++; if (EFHNIsGlob(node->efnode_name->efnn_hier)) ecNumGlobalNodes++; diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index 41731f60..a167878d 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -89,7 +89,7 @@ extern float locScale; * node, or added to the values already stored in an existing one. * * Results: - * None. + * Return a pointer to the new node. * * Side effects: * Updates the HashTable and node list of 'def'. @@ -139,10 +139,12 @@ extern float locScale; */ void -efBuildNode(def, isSubsnode, isDevSubsnode, nodeName, nodeCap, x, y, layerName, av, ac) +efBuildNode(def, isSubsnode, isDevSubsnode, isExtNode, nodeName, nodeCap, + x, y, layerName, av, ac) Def *def; /* Def to which this connection is to be added */ bool isSubsnode; /* TRUE if the node is the global substrate */ bool isDevSubsnode; /* TRUE if the node is a device body connection */ + bool isExtNode; /* TRUE if this was a "node" or "substrate" in .ext */ char *nodeName; /* One of the names for this node */ double nodeCap; /* Capacitance of this node to ground */ int x; int y; /* Location of a point inside this node */ @@ -155,8 +157,9 @@ efBuildNode(def, isSubsnode, isDevSubsnode, nodeName, nodeCap, x, y, layerName, HashEntry *he; unsigned size; int n; - char *uqname = nodeName; - int uqidx; + LinkedRect *lr; + Rect rnew; + int tnew = 0; he = HashFind(&def->def_nodes, nodeName); if (newname = (EFNodeName *) HashGetValue(he)) @@ -186,31 +189,30 @@ efBuildNode(def, isSubsnode, isDevSubsnode, nodeName, nodeCap, x, y, layerName, if (isSubsnode == TRUE) newnode->efnode_flags |= EF_GLOB_SUBS_NODE; - - /* For tracking unique nodes (see below), the first - * node entry for a port is not considered unique, - * since the port itself is not a node. - */ - if (newnode->efnode_flags & EF_PORT_NONODE) - { - newnode->efnode_flags &= ~EF_PORT_NONODE; - return; - } - /* If tracking unique nodes (for "def write", for example), - * collect unique node positions in the client data so that - * all of them can be visited. - */ - uqname = mallocMagic(strlen(nodeName) + 8); - uqidx = 0; - while (1) + /* The node is a duplicate port name at a different location. */ + /* If EFSaveLocs is TRUE, then save the layer and position in */ + /* newnode's efnode_disjoint list. */ + + if ((EFSaveLocs == TRUE) && (isExtNode == TRUE)) { - sprintf(uqname, "%s_uq%d", nodeName, uqidx); - he = HashFind(&def->def_nodes, uqname); - if ((newname = (EFNodeName *)HashGetValue(he)) == NULL) - break; - uqidx++; + rnew.r_xbot = (int)(0.5 + (float)x * locScale); + rnew.r_ybot = (int)(0.5 + (float)y * locScale); + rnew.r_xtop = rnew.r_xbot + 1; + rnew.r_ytop = rnew.r_ybot + 1; + + if (layerName) + tnew = efBuildAddStr(EFLayerNames, &EFLayerNumNames, + MAXTYPES, layerName); + else + tnew = 0; + lr = (LinkedRect *)mallocMagic(sizeof(LinkedRect)); + lr->r_r = rnew; + lr->r_type = tnew; + lr->r_next = newnode->efnode_disjoint; + newnode->efnode_disjoint = lr; } + return; } } @@ -218,7 +220,7 @@ efBuildNode(def, isSubsnode, isDevSubsnode, nodeName, nodeCap, x, y, layerName, { /* Allocate a new node with 'nodeName' as its single name */ newname = (EFNodeName *) mallocMagic((unsigned)(sizeof (EFNodeName))); - newname->efnn_hier = EFStrToHN((HierName *) NULL, uqname); + newname->efnn_hier = EFStrToHN((HierName *) NULL, nodeName); newname->efnn_port = -1; /* No port assignment */ newname->efnn_refc = 0; /* Only reference is self */ newname->efnn_next = NULL; @@ -265,11 +267,17 @@ efBuildNode(def, isSubsnode, isDevSubsnode, nodeName, nodeCap, x, y, layerName, /* If isSubsnode was TRUE, then turn off backwards compatibility mode */ if (isSubsnode == TRUE) EFCompat = FALSE; - if (uqname != nodeName) + /* Save location of top-level geometry if EFSaveLocs is TRUE */ + if ((EFSaveLocs == TRUE) && (isExtNode == TRUE)) { - newnode->efnode_flags |= EF_UNIQUE_NODE; - freeMagic(uqname); + lr = (LinkedRect *)mallocMagic(sizeof(LinkedRect)); + lr->r_r = newnode->efnode_loc; + lr->r_type = newnode->efnode_type; + lr->r_next = (LinkedRect *)NULL; + newnode->efnode_disjoint = lr; } + else + newnode->efnode_disjoint = (LinkedRect *)NULL; } /* @@ -510,7 +518,7 @@ efBuildEquiv(def, nodeName1, nodeName2, resist) { if (efWarn) efReadError("Creating new node %s\n", nodeName1); - efBuildNode(def, FALSE, FALSE, + efBuildNode(def, FALSE, FALSE, FALSE, nodeName1, (double)0, 0, 0, (char *) NULL, (char **) NULL, 0); nn1 = (EFNodeName *) HashGetValue(he1); @@ -1123,14 +1131,10 @@ efBuildPortNode(def, name, idx, x, y, layername, toplevel) if (nn == (EFNodeName *) NULL) { /* Create node if it doesn't already exist */ - efBuildNode(def, FALSE, FALSE, name, (double)0, x, y, + efBuildNode(def, FALSE, FALSE, FALSE, name, (double)0, x, y, layername, (char **) NULL, 0); nn = (EFNodeName *) HashGetValue(he); - - /* Flag this as a port where the corresponding node has not been seen. */ - if (nn != (EFNodeName *) NULL) - nn->efnn_node->efnode_flags |= EF_PORT_NONODE; } if (nn != (EFNodeName *) NULL) { @@ -1221,7 +1225,7 @@ efBuildDevNode(def, name, isSubsNode) /* Create node if it doesn't already exist */ if (efWarn && !isSubsNode) efReadError("Node %s doesn't exist so creating it\n", name); - efBuildNode(def, FALSE, isSubsNode, name, (double)0, 0, 0, + efBuildNode(def, FALSE, isSubsNode, FALSE, name, (double)0, 0, 0, (char *) NULL, (char **) NULL, 0); nn = (EFNodeName *) HashGetValue(he); @@ -1901,7 +1905,22 @@ efNodeMerge(node1ptr, node2ptr) if (removing->efnode_flags & EF_SUBS_NODE) keeping->efnode_flags |= EF_SUBS_NODE; - /* Test! */ + /* If EFSaveLocs is set, then merge any disjoint segments from + * removing to keeping. + */ + if (EFSaveLocs == TRUE) + { + LinkedRect *lr; + + if (keeping->efnode_disjoint == NULL) + keeping->efnode_disjoint = removing->efnode_disjoint; + else + { + for (lr = keeping->efnode_disjoint; lr->r_next; lr = lr->r_next); + lr->r_next = removing->efnode_disjoint; + } + } + removing->efnode_flags = 0; /* Get rid of "removing" */ @@ -2059,6 +2078,7 @@ efFreeNodeList(head, func) { EFNode *node; EFAttr *ap; + LinkedRect *lr; for (node = (EFNode *) head->efnode_next; node != head; @@ -2072,6 +2092,9 @@ efFreeNodeList(head, func) (*func)(node->efnode_client); freeMagic((char *)node->efnode_client); } + for (lr = node->efnode_disjoint; lr; lr = lr->r_next) + freeMagic((char *)lr); + freeMagic((char *) node); } } diff --git a/extflat/EFflat.c b/extflat/EFflat.c index 2d9900ef..10250868 100644 --- a/extflat/EFflat.c +++ b/extflat/EFflat.c @@ -461,6 +461,7 @@ efAddNodes(hc, stdcell) EFNodeName *nn, *newname, *oldname; EFNode *node, *newnode; EFAttr *ap, *newap; + LinkedRect *lr, *newlr; HierName *hierName; int size, asize; HashEntry *he; @@ -489,6 +490,15 @@ efAddNodes(hc, stdcell) newap->efa_next = newnode->efnode_attrs; newnode->efnode_attrs = newap; } + newnode->efnode_disjoint = (LinkedRect *)NULL; + for (lr = node->efnode_disjoint; lr; lr = lr->r_next) + { + newlr = (LinkedRect *)mallocMagic(sizeof(LinkedRect)); + newlr->r_r = lr->r_r; + newlr->r_type = lr->r_type; + newlr->r_next = newnode->efnode_disjoint; + newnode->efnode_disjoint = newlr; + } // If called with "hierarchy on", all local node caps and adjustments // have been output and should be ignored. diff --git a/extflat/EFread.c b/extflat/EFread.c index c5d31d16..889d9c82 100644 --- a/extflat/EFread.c +++ b/extflat/EFread.c @@ -102,6 +102,7 @@ keyTable[] = char *efReadFileName; /* Name of file currently being read */ int efReadLineNum; /* Current line number in above file */ float locScale; /* Multiply values in the file by this on read-in */ +bool EFSaveLocs; /* If TRUE, save location of merged top-level nodes */ /* Data local to this file */ static bool efReadDef(); @@ -181,6 +182,7 @@ efReadDef(def, dosubckt, resist, noscale, toplevel) int argc, ac, n; CellDef *dbdef; EFCapValue cap; + EFNode *node; char *line = NULL, *argv[128], *name, *attrs; int size = 0; int rscale = 1; /* Multiply resistances by this */ @@ -241,6 +243,13 @@ efReadDef(def, dosubckt, resist, noscale, toplevel) } readfile: + /* NOTE: noscale == TRUE means that coordinates should be in database + * coordinates. EFSaveLocs == TRUE means save the coordinates of + * merged nodes for later searching. Since coordinates can only be + * searched if they are in database units, these two settings are + * effectively equivalent (and both are used by "def write" only). + */ + EFSaveLocs = noscale; efReadLineNum = 0; while ((argc = efReadLine(&line, &size, inf, argv)) >= 0) { @@ -424,7 +433,7 @@ readfile: cap = atoCap(argv[3])*cscale; efBuildNode(def, (keyTable[n].k_key == SUBSTRATE) ? TRUE : FALSE, - FALSE, + FALSE, (toplevel) ? TRUE : FALSE, argv[1], (double) cap, atoi(argv[4]), atoi(argv[5]), argv[6], &argv[7], ac); @@ -451,7 +460,7 @@ readfile: */ case RNODE: cap = atoCap(argv[3])*cscale; - efBuildNode(def, FALSE, FALSE, argv[1], (double) cap, + efBuildNode(def, FALSE, FALSE, FALSE, argv[1], (double) cap, atoi(argv[4]), atoi(argv[5]), argv[6], (char **) NULL, 0); break; @@ -639,8 +648,7 @@ resistChanged: { use = (Use *)HashGetValue(he); if ((use->use_def->def_flags & DEF_AVAILABLE) == 0) - if (efReadDef(use->use_def, DoSubCircuit, resist, noscale, FALSE) - != TRUE) + if (efReadDef(use->use_def, DoSubCircuit, resist, noscale, FALSE) != TRUE) rc = FALSE; } diff --git a/extflat/extflat.h b/extflat/extflat.h index d7f847fd..6d767c94 100644 --- a/extflat/extflat.h +++ b/extflat/extflat.h @@ -212,21 +212,6 @@ typedef struct efnhdr * line of the .ext file as the global default substrate node. */ #define EF_GLOB_SUBS_NODE 0x80 - /* - * EF_UNIQUE_NODE marks a node that has the same name as another - * node, indicating that the nodes are electrically connected only - * by name. The processing routine can determine whether to - * process these individually. The capacitance and resistance - * values are merged with the first node of the same name. The - * location is maintained so that the net fragment can be found. - */ -#define EF_UNIQUE_NODE 0x100 - /* - * EF_PORT_NONODE is used to mark a port for which no "node" - * record has been seen. When a corresponding node record is - * found, this flag is cleared. - */ -#define EF_PORT_NONODE 0x200 extern int efNumResistClasses; /* Number of resistance classes in efResists */ @@ -246,6 +231,9 @@ typedef struct efnode * .ext file so it will be easy to map between * node names and locations. */ + LinkedRect *efnode_disjoint; /* List of disjoint node locations, created + * if EFSaveLocs is TRUE. + */ EFAttr *efnode_attrs; /* Node attribute list */ ClientData efnode_client; /* For hire */ EFPerimArea efnode_pa[1]; /* Dummy; each node actually has @@ -356,6 +344,9 @@ extern int EFLayerNumNames; /* Output control flags */ extern int EFOutputFlags; + /* Behavior regarding disjoint node segments */ +extern bool EFSaveLocs; + /* -------------------------- Exported procedures --------------------- */ extern char *EFArgs(); diff --git a/lef/defWrite.c b/lef/defWrite.c index 7f091cfd..40756f26 100644 --- a/lef/defWrite.c +++ b/lef/defWrite.c @@ -320,7 +320,7 @@ defnodeCount(node, res, cap, total) if (pwr) { /* Diagnostic */ - TxPrintf("Node %s is defined in the \"globals\" array\n", pwr); + TxPrintf("Node %s is defined in the \"globals\" array\n", cp); node->efnode_flags |= EF_SPECIAL; } @@ -665,7 +665,9 @@ defnodeVisit(node, res, cap, defdata) CellDef *def = defdata->def; float oscale = defdata->scale; TileTypeBitMask tmask, *rmask; - TileType magictype; + TileType nodetype, magictype; + Rect *nodeloc; + LinkedRect *lr; EFNodeName *thisnn; int defNetGeometryFunc(); /* Forward declaration */ @@ -732,76 +734,85 @@ defnodeVisit(node, res, cap, defdata) } } - /* TT_SPACE indicates that a layer name must be the next */ - /* thing to be written to the DEF file. */ + /* TT_SPACE indicates that a layer name must be the */ + /* next thing to be written to the DEF file. */ defdata->type = TT_SPACE; defdata->tile = (Tile *)NULL; - /* Net geometry (this should be an option!)--- */ - /* Use the DBconnect routines to find all geometry */ - /* connected to a specific node. This is a */ - /* redundant search---we've already done this once */ - /* when extracting the circuit. But, because the */ - /* DEF file requires a count of nodes up front, we */ - /* would have to do it twice anyway. In this case, */ - /* we only do it once here, since the results of */ - /* the first pass are picked up from the .ext file. */ + /* Process all disjoint segments of the node */ - magictype = DBTechNameType(EFLayerNames[node->efnode_type]); - - /* Note that the type of the node might be defined by the type */ - /* in the subcircuit itself, so we need to search for any type */ - /* that might validly connect to it, not just the type itself. */ - /* TTMaskSetOnlyType(&tmask, magictype); */ - TTMaskZero(&tmask); - TTMaskSetMask(&tmask, &DBConnectTbl[magictype]); - - DBSrConnect(def, &node->efnode_loc, &tmask, DBConnectTbl, - &TiPlaneRect, defNetGeometryFunc, - (ClientData)defdata); - - if (defdata->tile == (Tile *)NULL) + for (lr = node->efnode_disjoint; lr; lr = lr->r_next) { - /* No route layer? It's possible that something connects to */ - /* the port location but doesn't overlap. Try painting the */ - /* node type in def and trying again. */ + /* Watch for entries created from the substrate node */ + if ((lr->r_r.r_ll.p_x <= (MINFINITY + 2)) || + (lr->r_r.r_ll.p_y <= (MINFINITY + 2))) + continue; - Rect rport; - SearchContext scx; - int defPortTileFunc(); /* Fwd declaration */ + /* Net geometry (this should be an option!)--- */ + /* Use the DBconnect routines to find all geometry */ + /* connected to a specific node. This is a */ + /* redundant search---we've already done this once */ + /* when extracting the circuit. But, because the */ + /* DEF file requires a count of nodes up front, we */ + /* would have to do it twice anyway. In this case, */ + /* we only do it once here, since the results of */ + /* the first pass are picked up from the .ext file. */ - scx.scx_area = node->efnode_loc; - scx.scx_use = def->cd_parents; - scx.scx_trans = GeoIdentityTransform; + magictype = DBTechNameType(EFLayerNames[lr->r_type]); - rport = GeoNullRect; - DBTreeSrUniqueTiles(&scx, &tmask, 0, defPortTileFunc, (ClientData)&rport); + /* Note that the type of the node might be defined by the type */ + /* in the subcircuit itself, so we need to search for any type */ + /* that might validly connect to it, not just the type itself. */ + /* TTMaskSetOnlyType(&tmask, magictype); */ + TTMaskZero(&tmask); + TTMaskSetMask(&tmask, &DBConnectTbl[magictype]); - /* Add the residue types to any contact type */ - if (DBIsContact(magictype)) - { - rmask = DBResidueMask(magictype); - TTMaskSetMask(&tmask, rmask); - TTMaskSetType(&tmask, magictype); - } - - /* Check if anything was found in the location (e.g., .ext file - * could be invalid or outdated). - */ - if (GEO_RECTNULL(&rport)) - TxError("Nothing found at node %s location (bad .ext file?)!\n", ndn); - else - { - - /* Expand the rectangle around the port to overlap any */ - /* connecting material. */ - rport.r_xbot--; - rport.r_ybot--; - rport.r_xtop++; - rport.r_ytop++; - DBSrConnect(def, &rport, &tmask, DBConnectTbl, &TiPlaneRect, + DBSrConnect(def, &lr->r_r, &tmask, DBConnectTbl, &TiPlaneRect, defNetGeometryFunc, (ClientData)defdata); - } + + if (defdata->tile == (Tile *)NULL) + { + /* No route layer? It's possible that something connects */ + /* to the port location but doesn't overlap. Try painting */ + /* the node type in def and trying again. */ + + Rect rport; + SearchContext scx; + int defPortTileFunc(); /* Fwd declaration */ + + scx.scx_area = node->efnode_loc; + scx.scx_use = def->cd_parents; + scx.scx_trans = GeoIdentityTransform; + + rport = GeoNullRect; + DBTreeSrUniqueTiles(&scx, &tmask, 0, defPortTileFunc, (ClientData)&rport); + + /* Add the residue types to any contact type */ + if (DBIsContact(magictype)) + { + rmask = DBResidueMask(magictype); + TTMaskSetMask(&tmask, rmask); + TTMaskSetType(&tmask, magictype); + } + + /* Check if anything was found in the location (e.g., .ext file + * could be invalid or outdated). + */ + if (GEO_RECTNULL(&rport)) + TxError("Nothing found at node %s location (floating label?)!\n", ndn); + else + { + + /* Expand the rectangle around the port to overlap any */ + /* connecting material. */ + rport.r_xbot--; + rport.r_ybot--; + rport.r_xtop++; + rport.r_ytop++; + DBSrConnect(def, &rport, &tmask, DBConnectTbl, &TiPlaneRect, + defNetGeometryFunc, (ClientData)defdata); + } + } } /* Was there a last record pending? If so, write it. */