Claude Fable 5 implemented capacitance checking at shape corners,

after much discussion about the implementation.  Since it is not
exactly clear what the field lines do at corners, the implementation
depends largely on an unknown and presumably global constant
multiplier;  this has provisionally been set to 1 but needs to be
determined empirically with a field equation solver.  At least one
rational approximation suggests a value of pi/2 instead of 1.  The
corner capacitance can be considered a refinement of existing
parasitic capacitance extraction, and since it takes a non-trivial
additional amount of computation, it is left as an option to
"extract" that can be turned on when a more accurate result is
preferred at the expense of a longer extraction time.
This commit is contained in:
R. Timothy Edwards 2026-07-08 09:13:07 -04:00
parent 443045b331
commit 718e02ec3f
7 changed files with 891 additions and 11 deletions

View File

@ -1 +1 @@
8.3.671
8.3.672

View File

@ -1039,15 +1039,16 @@ cmdExpandFunc(
#define DOADJUST 0
#define DOALL 1
#define DOCAPACITANCE 2
#define DOCOUPLING 3
#define DOEXTRESIST 4
#define DOLENGTH 5
#define DOLOCAL 6
#define DORESISTANCE 7
#define DOLABELCHECK 8
#define DOALIASES 9
#define DOUNIQUE 10
#define DOEXTRESIST2 11
#define DOCORNERS 3
#define DOCOUPLING 4
#define DOEXTRESIST 5
#define DOLENGTH 6
#define DOLOCAL 7
#define DORESISTANCE 8
#define DOLABELCHECK 9
#define DOALIASES 10
#define DOUNIQUE 11
#define DOEXTRESIST2 12
#define LENCLEAR 0
#define LENDRIVER 1
@ -1089,6 +1090,8 @@ CmdExtract(
"adjust compensate R and C hierarchically",
"all all options",
"capacitance extract substrate capacitance",
"corners [value] extract corner fringe capacitance,\n"
" optionally setting the model scale factor",
"coupling extract coupling capacitance",
"extresist extract resistance",
"length compute driver-receiver pathlengths",
@ -1397,6 +1400,8 @@ CmdExtract(
TxPrintf("The following are the extractor option settings:\n");
TxPrintf("%s adjust\n", OPTSET(EXT_DOADJUST));
TxPrintf("%s capacitance\n", OPTSET(EXT_DOCAPACITANCE));
TxPrintf("%s corners (scale factor %g)\n", OPTSET(EXT_DOCORNERS),
ExtCornerFactor);
TxPrintf("%s coupling\n", OPTSET(EXT_DOCOUPLING));
TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH));
TxPrintf("%s lumped R\n", OPTSET(EXT_DORESISTANCE));
@ -1429,6 +1434,20 @@ CmdExtract(
case DOADJUST: option = EXT_DOADJUST; break;
case DOALL: option = EXT_DOALL; break;
case DOCAPACITANCE: option = EXT_DOCAPACITANCE; break;
case DOCORNERS:
if (argc == 4)
{
double kval;
if (sscanf(argv[3], "%lf", &kval) == 1)
ExtCornerFactor = kval;
else
{
TxError("Usage: extract do corners [value]\n");
return;
}
}
option = EXT_DOCORNERS;
break;
case DOCOUPLING: option = EXT_DOCOUPLING; break;
case DOLENGTH: option = EXT_DOLENGTH; break;
case DORESISTANCE: option = EXT_DORESISTANCE; break;

View File

@ -45,6 +45,26 @@ Circuit netlist extractor
<DT> <B>coupling</B>
<DD> Extract the parasitic coupling capacitance between
nodes.
<DT> <B>corners</B> [<I>value</I>]
<DD> (Added in magic version 8.3.672) Extract the fringe
capacitance at the corners of shapes. The fringe
capacitance model measures capacitance outward from
shape edges, which does not account for the part of
the fringe field at a convex corner that couples to
shapes diagonal to the corner, or for the
double-counting of the fringe field from the two
edges meeting at a concave corner. With this option
enabled, the corner fringe capacitance is modeled as
a superposition of the fields of the two edges
meeting at each corner, and is added to (convex) or
subtracted from (concave) both the substrate
capacitance and the coupling capacitance.
The optional <I>value</I> (default 1.0) is a
dimensionless scale factor on the corner capacitance
model. This is a second-order correction which
increases extraction time, so it is disabled by
default, and is not included in the options enabled
by "<B>all</B>".
<DT> <B>lumped</B>
<DD> Extract lumped resistance values.
The values extracted are "lumped" resistance and

View File

@ -5294,6 +5294,151 @@ extSubsFunc3(tile, dinfo, clientdata)
return 1;
}
/*
* ----------------------------------------------------------------------------
*
* extNodeCornerCap --
*
* Check the endpoints of a horizontal perimeter segment for convex and
* concave corners of the node region, and adjust the substrate fringe
* capacitance of the region accordingly. Called from extNodeAreaFunc()
* for each segment between 'tile' (inside the region) and 'tp' (the
* neighbor above or below), when option EXT_DOCORNERS is set and the
* segment has nonzero perimeter capacitance. Since every corner joins
* exactly one horizontal and one vertical edge, checking only horizontal
* segments considers each corner exactly once.
*
* The perimeter capacitance models the fringe field perpendicular to an
* edge, so the field in the quadrant diagonal to a convex corner is not
* counted, while the field in the free quadrant at a concave corner is
* counted once by each of the two edges meeting at the corner. The
* total fringe capacitance of an unobstructed corner quadrant is modeled
* as that of a straight edge of length (ExtCornerFactor / mult), where
* "mult" is the fringe halo multiplier to the substrate; this amount is
* added for each convex corner and subtracted for each concave corner.
* Portions of the corner fringe blocked by shapes between the corner and
* the substrate are adjusted in extCornerOverlap() (see ExtCouple.c)
* when coupling capacitance is extracted.
*
* A convex corner is one where the tile beyond the endpoint on the
* inside of the segment and the tile diagonally beyond the endpoint are
* both space; a concave corner is one where both of those tiles are
* material connected to the region. Anything else (a segment fractured
* by tile splits, or shapes of different nodes meeting at a point) is
* left uncorrected, as are corners adjacent to non-Manhattan geometry
* (work to be done, eventually).
*
* Results:
* None.
*
* Side effects:
* May adjust reg->nreg_cap.
*
* ----------------------------------------------------------------------------
*/
void
extNodeCornerCap(
Tile *tile, /* Tile inside the node region */
Tile *tp, /* Neighbor tile outside the segment */
bool topside, /* TRUE if tp is above 'tile', FALSE if below */
NodeRegion *reg, /* Node region being accumulated */
TileType residue, /* Type of 'tile', with contacts reverted to residues */
TileTypeBitMask *mask, /* Connectivity mask of the type of 'tile' */
CapValue capval) /* Perimeter capacitance per unit length of the edge */
{
int end, cx, cy;
double mult;
Tile *t2, *tcont, *tdiag;
TileType conttype, diagtype;
CapValue cornercap;
mult = (double)ExtCurStyle->exts_overlapMult[residue][0];
if (mult <= 0) return;
/* Corners adjacent to non-Manhattan geometry are not handled. */
if (IsSplit(tile) || IsSplit(tp)) return;
cy = (topside) ? TOP(tile) : BOTTOM(tile);
cornercap = capval * (ExtCornerFactor / mult);
for (end = 0; end < 2; end++) /* 0 = left endpoint, 1 = right */
{
cx = (end == 1) ? MIN(RIGHT(tile), RIGHT(tp))
: MAX(LEFT(tile), LEFT(tp));
/* When extracting within a clip area, count only corners */
/* inside the area, treating the area as half-open so that */
/* corners on a boundary between abutting clip areas are */
/* counted exactly once. */
if (extNodeClipArea)
if ((cx < extNodeClipArea->r_xbot) || (cx >= extNodeClipArea->r_xtop)
|| (cy < extNodeClipArea->r_ybot)
|| (cy >= extNodeClipArea->r_ytop))
continue;
/* Find the tile continuing beyond the endpoint on the inside */
/* side of the segment (tcont), and the tile diagonally beyond */
/* the endpoint on the outside side (tdiag), using the corner */
/* stitches of the two tiles. */
if (end == 1) /* Right endpoint */
{
if (RIGHT(tile) > cx)
tcont = tile;
else if (topside)
tcont = TR(tile);
else
{
for (t2 = TR(tile); BOTTOM(t2) > cy; t2 = LB(t2));
tcont = t2;
}
if (RIGHT(tp) > cx)
tdiag = tp;
else if (topside)
{
for (t2 = TR(tp); BOTTOM(t2) > cy; t2 = LB(t2));
tdiag = t2;
}
else
tdiag = TR(tp);
}
else /* Left endpoint */
{
if (LEFT(tile) < cx)
tcont = tile;
else if (topside)
{
for (t2 = BL(tile); TOP(t2) < cy; t2 = RT(t2));
tcont = t2;
}
else
tcont = BL(tile);
if (LEFT(tp) < cx)
tdiag = tp;
else if (topside)
tdiag = BL(tp);
else
{
for (t2 = BL(tp); TOP(t2) < cy; t2 = RT(t2));
tdiag = t2;
}
}
if (IsSplit(tcont) || IsSplit(tdiag)) continue;
conttype = TiGetTypeExact(tcont);
diagtype = TiGetTypeExact(tdiag);
if ((conttype == TT_SPACE) && (diagtype == TT_SPACE))
reg->nreg_cap += cornercap; /* Convex corner */
else if (TTMaskHasType(mask, conttype) && TTMaskHasType(mask, diagtype))
reg->nreg_cap -= cornercap; /* Concave corner */
}
}
int
extNodeAreaFunc(tile, dinfo, arg)
Tile *tile;
@ -5311,6 +5456,14 @@ extNodeAreaFunc(tile, dinfo, arg)
NodeRegion *old;
Rect r;
PlaneAndArea pla;
bool doCorners;
/* Extract corner fringe capacitance to substrate only when */
/* selected by "extract do corners", and only with the distributed */
/* (halo) fringe capacitance model. */
doCorners = ((ExtOptions & EXT_DOCORNERS) && (ExtOptions & EXT_DOFRINGEHALO)
&& (ExtCurStyle->exts_sideCoupleHalo > 0)) ? TRUE : FALSE;
if (tile && IsSplit(tile))
{
@ -5489,7 +5642,11 @@ topside:
}
tres = (DBIsContact(t)) ? DBPlaneToResidue(t, tilePlaneNum) : t;
if ((capval = ExtCurStyle->exts_perimCap[residue][tres]) != (CapValue) 0)
{
reg->nreg_cap += capval * len;
if (doCorners)
extNodeCornerCap(tile, tp, TRUE, reg, residue, mask, capval);
}
if (TTMaskHasType(resMask, tres) && resistClass != -1)
extResistPerim[resistClass] += len;
}
@ -5590,7 +5747,11 @@ bottomside:
}
tres = (DBIsContact(t)) ? DBPlaneToResidue(t, tilePlaneNum) : t;
if ((capval = ExtCurStyle->exts_perimCap[residue][tres]) != (CapValue) 0)
{
reg->nreg_cap += capval * len;
if (doCorners)
extNodeCornerCap(tile, tp, FALSE, reg, residue, mask, capval);
}
if (TTMaskHasType(resMask, tres) && resistClass != -1)
extResistPerim[resistClass] += len;
}

View File

@ -51,6 +51,9 @@ int extAddOverlap(), extAddCouple();
int extSideLeft(), extSideRight(), extSideBottom(), extSideTop();
int extWalkLeft(), extWalkRight(), extWalkBottom(), extWalkTop();
int extSideOverlap(), extSideOverlapHalo(), extFindOverlap();
int extCornerOverlap(), extSubtractCornerOverlap(), extSubtractCornerOverlap2();
double extCornerFrac();
void extAddCornerCouple();
void extSideCommon();
/* Structure to pass on to the coupling and sidewall capacitance */
@ -86,6 +89,24 @@ typedef struct _esws {
CellDef *def;
} extSidewallStruct;
/* Structure to pass information about a corner of a node region */
/* found at the endpoint of a boundary, for computing corner fringe */
/* capacitance (see extAddCornerCouple). */
typedef struct _ecns {
extSidewallStruct *ec_esws; /* Info from the boundary owning the corner */
Point ec_corner; /* Position of the corner */
int ec_quadrant; /* Quadrant of the fringe field relative to
* the corner (GEO_NORTHEAST, etc.)
*/
int ec_sign; /* +1 for a convex corner (fringe cap is
* added), -1 for a concave corner (fringe
* cap double-counted by the two edges
* meeting at the corner is subtracted).
*/
Rect ec_area; /* Quadrant halo search area */
} extCornerStruct;
/* --------------------- Debugging stuff ---------------------- */
#define CAP_DEBUG FALSE
@ -412,6 +433,17 @@ struct sideoverlap
TileType so_ctype;
};
struct corneroverlap
{
Rect co_clip;
double co_coupfrac;
double co_subfrac;
extCornerStruct *co_ecos;
PlaneMask co_pmask;
TileTypeBitMask co_tmask;
TileType co_ctype;
};
int
extAddOverlap(tbelow, dinfo, ecpls)
Tile *tbelow;
@ -1186,6 +1218,21 @@ extAddCouple(bp, ecs)
extSideBottom, bp, &esws);
break;
}
/* If corner extraction is selected ("extract do corners"), check */
/* the endpoints of horizontal boundaries for convex and concave */
/* corners of the node region, and add (convex) or subtract */
/* (concave) the corner fringe capacitance. Only horizontal */
/* boundaries are checked; since every corner joins exactly one */
/* horizontal and one vertical edge, this considers each corner */
/* exactly once. The corner model only applies to the distributed */
/* (halo) fringe model. */
if ((ExtOptions & EXT_DOCORNERS) && esws.fringe_halo
&& (esws.extOverlapList != NULL))
if ((bp->b_direction == BD_TOP) || (bp->b_direction == BD_BOTTOM))
extAddCornerCouple(&esws, tin, tout);
return 0;
}
@ -1734,6 +1781,623 @@ extSideOverlap(tp, dinfo, esws)
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extCornerFrac --
*
* Compute the fraction of the fringe capacitance field from a corner of
* a node region that is intercepted by the rectangle 'r', which must lie
* within the quadrant 'quadrant' (GEO_NORTHEAST, etc.) diagonal to the
* corner point 'corner'. Following the superposition model, the corner
* field is the product of the fields of the two edges meeting at the
* corner, each modeled as an arctangent with halo multiplier 'mult':
*
* Fx * Fy, where Fx = 0.6366 * (atan(mult * dxfar) - atan(mult * dxnear))
*
* and dxnear, dxfar are the distances of the near and far sides of 'r'
* from the vertical edge at the corner (likewise Fy for the horizontal
* edge). The product approaches 1 for a rectangle filling the entire
* quadrant.
*
* Results:
* The fraction (0.0 to 1.0) of the corner fringe cap seen by 'r'.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
double
extCornerFrac(
Rect *r, /* Area intercepting the corner fringe field */
Point *corner, /* Position of the corner */
int quadrant, /* Quadrant of the field relative to the corner */
double mult) /* Fringe halo multiplier */
{
int dxnear, dxfar, dynear, dyfar;
double fx, fy;
switch (quadrant)
{
case GEO_NORTHEAST:
case GEO_SOUTHEAST: /* r is to the right of the corner */
dxnear = r->r_xbot - corner->p_x;
dxfar = r->r_xtop - corner->p_x;
break;
default: /* r is to the left of the corner */
dxnear = corner->p_x - r->r_xtop;
dxfar = corner->p_x - r->r_xbot;
break;
}
switch (quadrant)
{
case GEO_NORTHEAST:
case GEO_NORTHWEST: /* r is above the corner */
dynear = r->r_ybot - corner->p_y;
dyfar = r->r_ytop - corner->p_y;
break;
default: /* r is below the corner */
dynear = corner->p_y - r->r_ytop;
dyfar = corner->p_y - r->r_ybot;
break;
}
if (dxnear < 0) dxnear = 0; /* Don't count underlap */
if (dynear < 0) dynear = 0;
fx = 0.6366 * (atan(mult * dxfar) - atan(mult * dxnear));
fy = 0.6366 * (atan(mult * dyfar) - atan(mult * dynear));
return fx * fy;
}
/*
* ----------------------------------------------------------------------------
*
* extSubtractCornerOverlap --
*
* Corner version of extSubtractSideOverlap. The fraction of the corner
* fringe capacitance shielded by this tile's area is added to the running
* totals cov->co_coupfrac (using the halo multiplier of the coupling
* layer) and cov->co_subfrac (using the halo multiplier of the substrate),
* so that it can be subtracted from the unshielded corner fraction.
*
* Results:
* Returns 0 to keep DBSrPaintArea() going.
*
* Side effects:
* Updates cov->co_coupfrac and cov->co_subfrac.
*
* ----------------------------------------------------------------------------
*/
int
extSubtractCornerOverlap(
Tile *tile,
TileType dinfo, /* (unused) */
struct corneroverlap *cov)
{
extCornerStruct *ecos = cov->co_ecos;
Boundary *bp = ecos->ec_esws->bp;
Rect r;
TileType ta, tb;
double mult;
TITORECT(tile, &r);
GEOCLIP(&r, &cov->co_clip);
if ((r.r_xtop <= r.r_xbot) || (r.r_ytop <= r.r_ybot)) return 0;
ta = TiGetType(bp->b_inside);
tb = cov->co_ctype;
mult = (double)ExtCurStyle->exts_overlapMult[ta][0];
if (mult > 0)
cov->co_subfrac += extCornerFrac(&r, &ecos->ec_corner,
ecos->ec_quadrant, mult);
/* Do the same calculation with the overlap multiplier for the */
/* coupling layer, since the fringe capacitance has a different */
/* halo than for the substrate. */
mult = (double)ExtCurStyle->exts_overlapMult[ta][tb];
if (mult > 0)
cov->co_coupfrac += extCornerFrac(&r, &ecos->ec_corner,
ecos->ec_quadrant, mult);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* extSubtractCornerOverlap2 --
*
* Recursive shielding corner overlap check; the corner version of
* extSubtractSideOverlap2. If the tile shields, then the shielded
* fraction is accumulated. If not, then this routine is called
* recursively on the next shielding plane.
*
* Results:
* Returns 0 to keep DBSrPaintArea() going.
*
* Side effects:
* Updates cov->co_coupfrac and cov->co_subfrac.
*
* ----------------------------------------------------------------------------
*/
int
extSubtractCornerOverlap2(
Tile *tile,
TileType dinfo,
struct corneroverlap *cov)
{
TileType ttype;
struct corneroverlap covnew;
int pNum;
Rect r;
if (IsSplit(tile))
ttype = (dinfo & TT_SIDE) ? TiGetRightType(tile) : TiGetLeftType(tile);
else
ttype = TiGetTypeExact(tile);
TITORECT(tile, &r);
GEOCLIP(&r, &cov->co_clip);
if ((r.r_xtop <= r.r_xbot) || (r.r_ytop <= r.r_ybot)) return 0;
/* This tile shields everything below */
if (TTMaskHasType(&cov->co_tmask, ttype))
{
extSubtractCornerOverlap(tile, dinfo, cov);
return 0;
}
/* Tile doesn't shield, so search next plane */
covnew = *cov;
covnew.co_clip = r;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (!PlaneMaskHasPlane(covnew.co_pmask, pNum)) continue;
covnew.co_pmask &= ~(PlaneNumToMaskBit(pNum));
if (covnew.co_pmask == 0)
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &covnew.co_clip, &covnew.co_tmask,
extSubtractCornerOverlap, (ClientData) &covnew);
}
else
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &covnew.co_clip, &DBAllTypeBits,
extSubtractCornerOverlap2, (ClientData) &covnew);
}
break;
}
cov->co_coupfrac = covnew.co_coupfrac;
cov->co_subfrac = covnew.co_subfrac;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* extCornerOverlap --
*
* A corner of the node region of tile esws->bp->b_inside (described by
* 'ecos') has fringe capacitance into the quadrant ecos->ec_area, where
* the tile 'tp' has been found on another plane. Compute the fraction
* of the corner fringe capacitance coupling to 'tp' using the
* superposition product model (see extCornerFrac), reduced by any
* shielding layers, and update the coupling capacitance hash table.
* The total capacitance of an unobstructed corner is modeled as that of
* a straight edge of length (ExtCornerFactor / mult), where "mult" is
* the fringe halo multiplier of the coupling layers.
*
* For a concave corner (ecos->ec_sign < 0), the fringe capacitance in
* the quadrant has been counted twice, once by each of the two edges
* meeting at the corner, so the corner term is subtracted instead of
* added.
*
* The corner fringe capacitance to the substrate, which was added
* (convex) or subtracted (concave) along with the perimeter capacitance
* in extNodeCornerCap() (see ExtBasic.c), is likewise adjusted here for
* the portion blocked by the coupling tile when the tile lies between
* the corner and the substrate.
*
* Results:
* Returns 0 to keep DBSrPaintArea() going.
*
* Side effects:
* Updates the coupling capacitance between node(bp->b_inside) and
* node(tp) if the two nodes are different. May update the
* substrate capacitance of node(bp->b_inside).
*
* ----------------------------------------------------------------------------
*/
int
extCornerOverlap(
Tile *tp, /* Coupling tile in the corner quadrant */
TileType dinfo, /* Split tile information */
extCornerStruct *ecos) /* Corner and boundary information */
{
extSidewallStruct *esws = ecos->ec_esws;
Boundary *bp = esws->bp; /* Boundary owning the corner */
NodeRegion *rtp = (NodeRegion *) ExtGetRegion(tp, dinfo);
NodeRegion *rbp = (NodeRegion *) ExtGetRegion(bp->b_inside, (TileType)0);
TileType ta, tb;
struct corneroverlap cov;
HashEntry *he;
EdgeCap *e;
int pNum;
double mult, cfrac, subfrac;
CapValue cap;
CoupleKey ck;
/* Nothing to do for space tiles, so just return. */
if (IsSplit(tp))
tb = (dinfo & TT_SIDE) ? TiGetRightType(tp) : TiGetLeftType(tp);
else
tb = TiGetTypeExact(tp);
if (tb == TT_SPACE) return 0;
/* Get the area of the coupling tile, clipped to the corner quadrant */
TITORECT(tp, &cov.co_clip);
GEOCLIP(&cov.co_clip, &ecos->ec_area);
if ((cov.co_clip.r_xtop <= cov.co_clip.r_xbot) ||
(cov.co_clip.r_ytop <= cov.co_clip.r_ybot))
return 0;
/* ta is the tile type of the region corner generating the fringe cap. */
ta = TiGetType(bp->b_inside);
/* Revert any contacts to their residues */
if (DBIsContact(ta))
ta = DBPlaneToResidue(ta, esws->plane_of_boundary);
if (DBIsContact(tb))
tb = DBPlaneToResidue(tb, esws->plane_checked);
/* Apply each rule, incorporating shielding into the fraction. */
cap = (CapValue) 0;
subfrac = (double)0.0;
for (e = esws->extOverlapList; e; e = e->ec_next)
{
/* Only apply rules for the plane in which they are declared */
if (!PlaneMaskHasPlane(e->ec_pmask, esws->plane_checked)) continue;
/* Does this rule "e" include the tile we found? */
if (TTMaskHasType(&e->ec_near, tb))
{
mult = (double)ExtCurStyle->exts_overlapMult[ta][tb];
if (mult <= 0) continue;
cfrac = extCornerFrac(&cov.co_clip, &ecos->ec_corner,
ecos->ec_quadrant, mult);
/* We have a possible capacitor, but are the tiles shielded
* from each other part of the way?
*/
cov.co_ecos = ecos;
cov.co_ctype = tb;
cov.co_coupfrac = (double)0.0;
cov.co_subfrac = (double)0.0;
cov.co_pmask = ExtCurStyle->exts_sideOverlapShieldPlanes[ta][tb];
if (cov.co_pmask)
{
cov.co_tmask = e->ec_far; /* Actually shieldtypes. */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
/* Each call to DBSrPaintArea has an opportunity to
* subtract a partial capacitance from the total.
*/
if (!PlaneMaskHasPlane(cov.co_pmask, pNum)) continue;
cov.co_pmask &= ~(PlaneNumToMaskBit(pNum));
if (cov.co_pmask == 0)
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &cov.co_clip,
&cov.co_tmask, extSubtractCornerOverlap,
(ClientData) &cov);
}
else
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &cov.co_clip,
&DBAllTypeBits,
extSubtractCornerOverlap2, (ClientData) &cov);
}
break;
}
}
cfrac -= cov.co_coupfrac;
if (cfrac < 0) cfrac = 0;
if (rtp != rbp)
{
cap += e->ec_cap * (ExtCornerFactor / mult) * cfrac;
subfrac += cov.co_subfrac; /* Just add the shielded fraction */
}
}
}
if (rbp != (NodeRegion *)CLIENTDEFAULT)
{
int oa = ExtCurStyle->exts_planeOrder[esws->plane_of_boundary];
int ob = ExtCurStyle->exts_planeOrder[esws->plane_checked];
if (oa > ob)
{
/* The overlapped tile is between the substrate and the
* corner, and blocks the corner fringe capacitance to the
* substrate, which was added (convex) or subtracted
* (concave) with the perimeter capacitance in
* extNodeCornerCap() (see ExtBasic.c). For a convex
* corner, subtract the blocked portion. For a concave
* corner, each of the two edges meeting at the corner will
* have subtracted the blocked substrate fringe capacitance
* over this (shared) area, so add one portion back.
*/
mult = (double)ExtCurStyle->exts_overlapMult[ta][0];
if (mult > 0)
{
CapValue subcap;
double sfrac;
sfrac = extCornerFrac(&cov.co_clip, &ecos->ec_corner,
ecos->ec_quadrant, mult);
sfrac -= subfrac;
if (sfrac < 0) sfrac = 0;
subcap = (CapValue)ecos->ec_sign *
ExtCurStyle->exts_perimCap[ta][0] *
(ExtCornerFactor / mult) * sfrac;
rbp->nreg_cap -= subcap;
/* Ignore residual error at ~zero zeptoFarads */
if ((rbp->nreg_cap > -0.001) && (rbp->nreg_cap < 0.001))
rbp->nreg_cap = 0;
if (CAP_DEBUG)
extNregAdjustCap(rbp, -subcap, "corner_subcap");
}
}
}
/* Add (convex) or subtract (concave) the corner capacitance. */
if (cap == (CapValue) 0) return 0;
if (rtp == rbp) return 0;
if (rtp == (NodeRegion *)CLIENTDEFAULT) return 0;
if (rbp == (NodeRegion *)CLIENTDEFAULT) return 0;
if (rtp < rbp)
{
ck.ck_1 = rtp;
ck.ck_2 = rbp;
}
else
{
ck.ck_1 = rbp;
ck.ck_2 = rtp;
}
cap *= (CapValue)ecos->ec_sign;
he = HashFind(extCoupleHashPtr, (char *) &ck);
if (CAP_DEBUG) extAdjustCouple(he, cap, "corneroverlap");
extSetCapValue(he, cap + extGetCapValue(he));
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* extAddCornerCouple --
*
* Check the two endpoints of the horizontal boundary esws->bp for convex
* and concave corners of the node region of bp->b_inside, and for each
* corner found, search the quadrant of the fringe halo diagonal to the
* corner for tiles on other planes that couple to the corner fringe
* capacitance (see extCornerOverlap). Called only for boundaries with
* direction BD_TOP or BD_BOTTOM; since every corner joins exactly one
* horizontal and one vertical edge, checking only horizontal boundaries
* considers each corner exactly once.
*
* A convex corner is one where the tile beyond the endpoint on the
* inside of the boundary and the tile diagonally beyond the endpoint
* are both space; the corner fringe occupies the quadrant diagonally
* outward from the corner and is added to the coupling capacitance.
* A concave corner is one where both of those tiles belong to the same
* node region as bp->b_inside; the fringe capacitance in the free
* quadrant between the two edges meeting at the corner has been counted
* once by each edge, so the corner term is subtracted. Anything else
* (a boundary fractured by tile splits, or shapes of different nodes
* meeting at a point) is left uncorrected.
*
* In-plane material within the quadrant does not clip the corner fringe
* (unlike the edge fringe, which is clipped to the nearest coupling
* neighbor by extWalk*()); this is a second-order effect of a second-
* order correction. Shielding by layers on planes between the corner
* and the coupling tile is handled.
*
* Results:
* None.
*
* Side effects:
* See extCornerOverlap().
*
* ----------------------------------------------------------------------------
*/
void
extAddCornerCouple(
extSidewallStruct *esws, /* Boundary and plane information */
TileType tin, /* Type inside boundary (residue if contact) */
TileType tout) /* Type outside boundary (residue if contact) */
{
Boundary *bp = esws->bp;
NodeRegion *rbp;
PlaneMask pMask;
int halo = ExtCurStyle->exts_sideCoupleHalo;
int end, pNum, cx, cy;
extCornerStruct ecos;
pMask = ExtCurStyle->exts_sideOverlapOtherPlanes[tin][tout];
if (pMask == 0) return;
/* Corners adjacent to non-Manhattan geometry are not handled. */
if (IsSplit(bp->b_inside) || IsSplit(bp->b_outside)) return;
rbp = (NodeRegion *) ExtGetRegion(bp->b_inside, (TileType)0);
cy = (bp->b_direction == BD_TOP) ?
bp->b_segment.r_ur.p_y : bp->b_segment.r_ll.p_y;
for (end = 0; end < 2; end++) /* 0 = left endpoint, 1 = right */
{
Tile *tp, *tcont, *tdiag;
bool contsame, diagsame;
cx = (end == 1) ? bp->b_segment.r_xtop : bp->b_segment.r_xbot;
/* Find the tile continuing beyond the endpoint on the inside */
/* side of the boundary (tcont), and the tile diagonally */
/* beyond the endpoint on the outside side (tdiag), using the */
/* corner stitches of the boundary tiles. */
if (end == 1) /* Right endpoint */
{
if (RIGHT(bp->b_inside) > cx)
tcont = bp->b_inside;
else if (bp->b_direction == BD_TOP)
tcont = TR(bp->b_inside);
else
{
for (tp = TR(bp->b_inside); BOTTOM(tp) > cy; tp = LB(tp));
tcont = tp;
}
if (RIGHT(bp->b_outside) > cx)
tdiag = bp->b_outside;
else if (bp->b_direction == BD_TOP)
{
for (tp = TR(bp->b_outside); BOTTOM(tp) > cy; tp = LB(tp));
tdiag = tp;
}
else
tdiag = TR(bp->b_outside);
}
else /* Left endpoint */
{
if (LEFT(bp->b_inside) < cx)
tcont = bp->b_inside;
else if (bp->b_direction == BD_TOP)
{
for (tp = BL(bp->b_inside); TOP(tp) < cy; tp = RT(tp));
tcont = tp;
}
else
tcont = BL(bp->b_inside);
if (LEFT(bp->b_outside) < cx)
tdiag = bp->b_outside;
else if (bp->b_direction == BD_TOP)
tdiag = BL(bp->b_outside);
else
{
for (tp = BL(bp->b_outside); TOP(tp) < cy; tp = RT(tp));
tdiag = tp;
}
}
if (IsSplit(tcont) || IsSplit(tdiag)) continue;
contsame = (ExtGetRegion(tcont, (TileType)0) == (ExtRegion *)rbp)
? TRUE : FALSE;
diagsame = (ExtGetRegion(tdiag, (TileType)0) == (ExtRegion *)rbp)
? TRUE : FALSE;
if (!contsame && !diagsame)
{
/* Convex corner, but only if the corner faces open space */
if ((TiGetTypeExact(tcont) != TT_SPACE) ||
(TiGetTypeExact(tdiag) != TT_SPACE))
continue;
/* Fringe quadrant is diagonally outward from the corner */
ecos.ec_sign = 1;
if (bp->b_direction == BD_TOP)
ecos.ec_quadrant = (end == 1) ? GEO_NORTHEAST : GEO_NORTHWEST;
else
ecos.ec_quadrant = (end == 1) ? GEO_SOUTHEAST : GEO_SOUTHWEST;
}
else if (contsame && diagsame)
{
/* Concave corner, but only if the free quadrant between */
/* the two edges is open space (which is the tile on the */
/* outside of the boundary). */
if (TiGetTypeExact(bp->b_outside) != TT_SPACE)
continue;
/* Free quadrant is on the outside of the boundary, on the */
/* segment side of the endpoint. */
ecos.ec_sign = -1;
if (bp->b_direction == BD_TOP)
ecos.ec_quadrant = (end == 1) ? GEO_NORTHWEST : GEO_NORTHEAST;
else
ecos.ec_quadrant = (end == 1) ? GEO_SOUTHWEST : GEO_SOUTHEAST;
}
else
{
/* Straight continuation of the edge (boundary fractured */
/* by a tile split on the other side), or shapes meeting */
/* only at a point; no corner processing. */
continue;
}
ecos.ec_esws = esws;
ecos.ec_corner.p_x = cx;
ecos.ec_corner.p_y = cy;
switch (ecos.ec_quadrant)
{
case GEO_NORTHEAST:
ecos.ec_area.r_xbot = cx;
ecos.ec_area.r_ybot = cy;
ecos.ec_area.r_xtop = cx + halo;
ecos.ec_area.r_ytop = cy + halo;
break;
case GEO_NORTHWEST:
ecos.ec_area.r_xbot = cx - halo;
ecos.ec_area.r_ybot = cy;
ecos.ec_area.r_xtop = cx;
ecos.ec_area.r_ytop = cy + halo;
break;
case GEO_SOUTHEAST:
ecos.ec_area.r_xbot = cx;
ecos.ec_area.r_ybot = cy - halo;
ecos.ec_area.r_xtop = cx + halo;
ecos.ec_area.r_ytop = cy;
break;
case GEO_SOUTHWEST:
ecos.ec_area.r_xbot = cx - halo;
ecos.ec_area.r_ybot = cy - halo;
ecos.ec_area.r_xtop = cx;
ecos.ec_area.r_ytop = cy;
break;
}
extOverlapDef = esws->def;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(pMask, pNum))
{
esws->plane_checked = pNum;
(void) DBSrPaintArea((Tile *) NULL, esws->def->cd_planes[pNum],
&ecos.ec_area,
&ExtCurStyle->exts_sideOverlapOtherTypes[tin][tout],
extCornerOverlap, (ClientData) &ecos);
}
}
}
/*
* ----------------------------------------------------------------------------
*

View File

@ -58,6 +58,17 @@ int ExtDoWarn = EXTWARN_DUP|EXTWARN_FETS;
int ExtOptions = EXT_DOALL|EXT_DOLABELCHECK|EXT_DOALIASES;
char *ExtLocalPath = NULL;
/*
* Scale factor "k" for the corner fringe capacitance model (see
* ExtCouple.c), used when option EXT_DOCORNERS is set. The total
* capacitance of an unobstructed convex corner is modeled as the
* capacitance of a straight edge of length k / mult, where "mult"
* is the fringe halo multiplier for the coupling layers. The
* value can be set with "extract do corners <value>" and is meant
* to be calibrated against field equation solver results.
*/
double ExtCornerFactor = 1.0;
/* --------------------------- Global data ---------------------------- */
/* Cumulative yank buffer for hierarchical circuit extraction */

View File

@ -77,9 +77,14 @@ extern const char * const extDevTable[];
#define EXT_DOALIASES 0x080 /* Output all node aliases */
#define EXT_DOEXTRESIST 0x200 /* Do full R-C extraction */
#define EXT_DOUNIQNOTOPPORTS 0x400 /* Ignore top cell ports w/EXT_DOUNIQUE */
#define EXT_DOCORNERS 0x800 /* Extract fringe capacitance at shape
* corners. Adds compute time, and so
* is not included in EXT_DOALL.
*/
extern int ExtOptions; /* Bitmask of above */
extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
extern double ExtCornerFactor; /* Scale factor for corner fringe cap model */
/* Options for "extract unique" */
#define EXT_UNIQ_ALL 0