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.
This commit is contained in:
R. Timothy Edwards 2026-01-30 16:47:36 -05:00
parent 55eadcfb90
commit 4b120eb417
3 changed files with 56 additions and 30 deletions

View File

@ -1 +1 @@
8.3.597
8.3.598

View File

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

View File

@ -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(&nottypes, &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(&nottypes, TT_SPACE);
TTMaskAndMask(&types, &DBPlaneTypes[plane1]);
TTMaskAndMask(&nottypes, &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(&nottypes, &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(&nottypes, TT_SPACE);
TTMaskAndMask(&types, &DBPlaneTypes[plane1]);
TTMaskAndMask(&nottypes, &DBPlaneTypes[plane1]);
DBTechNoisyNameMask(argv[3], &ov);
TTMaskSetMask(allExtractTypes, &ov);