From 4b120eb41794c8c9ee5bb78a08607f27761a8381 Mon Sep 17 00:00:00 2001 From: "R. Timothy Edwards" Date: Fri, 30 Jan 2026 16:47:36 -0500 Subject: [PATCH] Corrected two errors related to extraction: (1) All parasitic extraction: The "defaultperimeter" and the "defaultsideoverlap" commands were failing to exempt types other than space from the list of edges from which fringing capacitance is evaluated. This led to incorrectly considering the boundary between types such as poly and nfet, or between metal1 and rm1, to be sidewall areas. The "default" statements are supposed to consider the most common usage, so the code has been changed to make sure that only edges from material to space are considered. In the rare case that a material-to-material edge in the same plane should be considered a sidewall, the non-default statements can be used instead. (2) Hierarchical parasitic extraction: Magic was incorrectly adding capacitances for subcells which had been output already when handling subcircuit connections during "ext2spice". This duplicate counting has been eliminated. --- VERSION | 2 +- extflat/EFflat.c | 60 ++++++++++++++++++++++++++++++----------------- extract/ExtTech.c | 24 +++++++++++++------ 3 files changed, 56 insertions(+), 30 deletions(-) diff --git a/VERSION b/VERSION index 8e69c3b2..8f604f6c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.597 +8.3.598 diff --git a/extflat/EFflat.c b/extflat/EFflat.c index 70bdc198..60e303a3 100644 --- a/extflat/EFflat.c +++ b/extflat/EFflat.c @@ -61,15 +61,17 @@ int efFlatGlobHash(HierName *); bool efFlatGlobCmp(HierName *, HierName *); char *efFlatGlobCopy(HierName *); void efFlatGlobError(EFNodeName *nameGlob, EFNodeName *nameFlat); -int efAddNodes(HierContext *hc, bool stdcell); -int efAddConns(HierContext *hc, bool doWarn); -int efAddOneConn(HierContext *hc, char *name1, char *name2, Connection *conn, bool doWarn); +int efAddNodes(HierContext *hc, int flags); +int efAddConns(HierContext *hc, int flags); +int efAddOneConn(HierContext *hc, char *name1, char *name2, Connection *conn, int flags); /* Flags passed to efFlatNode() */ #define FLATNODE_STDCELL 0x01 #define FLATNODE_DOWARN 0x02 #define FLATNODE_NOABSTRACT 0x04 +#define FLATNODE_HIER 0x08 +#define FLATNODE_CHILD 0x10 /* @@ -216,7 +218,7 @@ EFFlatBuildOneLevel(def, flags) efFlatRootUse.use_def = efFlatRootDef; /* Record all nodes down the hierarchy from here */ - flatnodeflags = 0; /* No FLATNODE_DOWARN */ + flatnodeflags = FLATNODE_HIER; /* No FLATNODE_DOWARN */ efFlatNodes(&efFlatContext, INT2CD(flatnodeflags)); /* Expand all subcells that contain connectivity information but */ @@ -320,9 +322,7 @@ efFlatNodes(hc, clientData) ClientData clientData; { int flags = (int)CD2INT(clientData); - - bool stdcell = (flags & FLATNODE_STDCELL) ? TRUE : FALSE; - bool doWarn = (flags & FLATNODE_DOWARN) ? TRUE : FALSE; + int hierflags = 0; if (flags & FLATNODE_NOABSTRACT) { @@ -332,13 +332,19 @@ efFlatNodes(hc, clientData) def->def_name); } - (void) efHierSrUses(hc, efFlatNodes, clientData); + /* If called with FLATNODE_HIER set, then set the FLATNODE_CHILD + * flag while calling efHierSrUses(), to prevent efAddNodes() from + * duplicating the capacitance of nodes in child cells. + */ + + hierflags = flags | ((flags & FLATNODE_HIER) ? FLATNODE_CHILD : 0); + (void) efHierSrUses(hc, efFlatNodes, INT2CD(hierflags)); /* Add all our own nodes to the table */ - efAddNodes(hc, stdcell); + efAddNodes(hc, flags); /* Process our own connections and adjustments */ - (void) efAddConns(hc, doWarn); + (void) efAddConns(hc, flags); return (0); } @@ -386,11 +392,11 @@ efFlatNodesStdCell(hc) } /* Add all our own nodes to the table */ - efAddNodes(hc, TRUE); + efAddNodes(hc, (int)FLATNODE_STDCELL); /* Process our own connections and adjustments */ if (!(hc->hc_use->use_def->def_flags & DEF_SUBCIRCUIT)) - (void) efAddConns(hc, TRUE); + (void) efAddConns(hc, (int)FLATNODE_DOWARN); return (0); } @@ -413,10 +419,10 @@ efFlatNodesDeviceless(hc, cdata) if ((HashGetNumEntries(&hc->hc_use->use_def->def_devs) == 0) && (newcount == 0)) { /* Add all our own nodes to the table */ - efAddNodes(hc, TRUE); + efAddNodes(hc, (int)FLATNODE_STDCELL); /* Process our own connections and adjustments */ - efAddConns(hc, TRUE); + efAddConns(hc, (int)FLATNODE_DOWARN); /* Mark this definition as having no devices, so it will not be visited */ hc->hc_use->use_def->def_flags |= DEF_NODEVICES; @@ -455,7 +461,7 @@ efFlatNodesDeviceless(hc, cdata) int efAddNodes( HierContext *hc, - bool stdcell) + int flags) { Def *def = hc->hc_use->use_def; EFNodeName *nn, *newname, *oldname; @@ -465,6 +471,8 @@ efAddNodes( HierName *hierName; int size, asize; HashEntry *he; + bool stdcell = (flags & FLATNODE_STDCELL) ? TRUE : FALSE; + bool is_child = (flags & FLATNODE_CHILD) ? TRUE : FALSE; bool is_subcircuit = (def->def_flags & DEF_SUBCIRCUIT) ? TRUE : FALSE; size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea); @@ -503,12 +511,15 @@ efAddNodes( // If called with "hierarchy on", all local node caps and adjustments // have been output and should be ignored. - newnode->efnode_cap = (!stdcell) ? node->efnode_cap : (EFCapValue)0.0; + if (!stdcell && !is_child) + newnode->efnode_cap = node->efnode_cap; + else + newnode->efnode_cap = (EFCapValue)0.0; newnode->efnode_client = (ClientData) NULL; newnode->efnode_flags = node->efnode_flags; newnode->efnode_type = node->efnode_type; newnode->efnode_num = 1; - if (!stdcell) + if (!stdcell && !is_child) bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa, efNumResistClasses * sizeof (EFPerimArea)); else @@ -601,7 +612,7 @@ efAddNodes( int efAddConns( HierContext *hc, - bool doWarn) + int flags) { Connection *conn; @@ -614,9 +625,9 @@ efAddConns( { /* Special case for speed when no array info is present */ if (conn->conn_1.cn_nsubs == 0) - efAddOneConn(hc, conn->conn_name1, conn->conn_name2, conn, doWarn); + efAddOneConn(hc, conn->conn_name1, conn->conn_name2, conn, flags); else - efHierSrArray(hc, conn, efAddOneConn, INT2CD(doWarn)); + efHierSrArray(hc, conn, efAddOneConn, INT2CD(flags)); } return (0); @@ -648,18 +659,23 @@ efAddOneConn( char *name1, /* These are strings, not HierNames */ char *name2, Connection *conn, - bool doWarn) + int flags) { HashEntry *he1, *he2; EFNode *node, *newnode; int n; + bool doWarn = (flags & FLATNODE_DOWARN) ? TRUE : FALSE; + bool doHier = (flags & FLATNODE_HIER) ? TRUE : FALSE; + he1 = EFHNLook(hc->hc_hierName, name1, (doWarn) ? "connect(1)" : NULL); if (he1 == NULL) return 0; - /* Adjust the resistance and capacitance of its corresponding node */ node = ((EFNodeName *) HashGetValue(he1))->efnn_node; + + /* Adjust the resistance and capacitance of its corresponding node */ + node->efnode_cap += conn->conn_cap; for (n = 0; n < efNumResistClasses; n++) { diff --git a/extract/ExtTech.c b/extract/ExtTech.c index 973c8179..e4884054 100644 --- a/extract/ExtTech.c +++ b/extract/ExtTech.c @@ -1368,7 +1368,7 @@ ExtTechSimplePerimCap(argc, argv) if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder) { - TechError("Cannot parse area cap line without plane ordering!\n"); + TechError("Cannot parse perimeter cap line without plane ordering!\n"); return; } @@ -1376,9 +1376,14 @@ ExtTechSimplePerimCap(argc, argv) TTMaskSetMask(allExtractTypes, &types); plane1 = DBTechNoisyNamePlane(argv[2]); - TTMaskCom2(¬types, &types); + /* As part of the "simple perimeter" simplifications, "nottypes" can + * only be space. This prevents perimeter edges from being seen + * between, e.g., poly and transistor gates, or metal and metal + * resistors. + */ + TTMaskSetOnlyType(¬types, TT_SPACE); + TTMaskAndMask(&types, &DBPlaneTypes[plane1]); - TTMaskAndMask(¬types, &DBPlaneTypes[plane1]); capVal = aToCap(argv[argc - 1]); @@ -1632,7 +1637,7 @@ ExtTechSimpleOverlapCap(argv) if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder) { - TechError("Cannot parse area cap line without plane ordering!\n"); + TechError("Cannot parse overlap cap line without plane ordering!\n"); return; } @@ -1732,7 +1737,7 @@ ExtTechSimpleSideOverlapCap(argv) if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder) { - TechError("Cannot parse area cap line without plane ordering!\n"); + TechError("Cannot parse side overlap cap line without plane ordering!\n"); return; } @@ -1740,9 +1745,14 @@ ExtTechSimpleSideOverlapCap(argv) TTMaskSetMask(allExtractTypes, &types); plane1 = DBTechNoisyNamePlane(argv[2]); - TTMaskCom2(¬types, &types); + /* As part of the "simple sideoverlap" simplifications, "nottypes" + * can only be space. This prevents perimeter edges from being + * seen between, e.g., poly and transistor gates, or metal and + * metal resistors. + */ + TTMaskSetOnlyType(¬types, TT_SPACE); + TTMaskAndMask(&types, &DBPlaneTypes[plane1]); - TTMaskAndMask(¬types, &DBPlaneTypes[plane1]); DBTechNoisyNameMask(argv[3], &ov); TTMaskSetMask(allExtractTypes, &ov);