Added an important new method: If the keyword "fringeshieldhalo"

is specified in the extraction section of the techfile, then magic
will compute the effect of a nearby shape partially shielding the
sidewall overlap capacitance, which approaches 100% shielding as
the shapes converge to zero separation.  This method prevents
magic from vastly overestimating the fringe capacitance of closely
spaced wires, which was magic's worst problem with parasitic
accuracy.  The "fringeshieldhalo" value is the distance at which
the fringe shielding becomes negligible.  Typically, it will be
about three times the distance at which half the fringe value is
shielded.  It may be necessary at some point to make both the
fringe shielding halo and the sidewall halo values per-type values
(or per-plane, at least).  For now, it should suffice to bring
Magic's parasitic extraction back in line with other tools.
This commit is contained in:
Tim Edwards 2022-03-17 17:35:41 -04:00
parent 083c0c10e9
commit d98645afc1
4 changed files with 330 additions and 14 deletions

View File

@ -1 +1 @@
8.3.276
8.3.277

View File

@ -22,6 +22,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#endif /* not lint */
#include <stdio.h>
#include <math.h> /* For sin() */
#include "utils/magic.h"
#include "utils/geometry.h"
@ -53,6 +54,7 @@ int extAddOverlap(), extAddCouple();
int extSideLeft(), extSideRight(), extSideBottom(), extSideTop();
int extSideOverlap();
void extSideCommon();
int extShieldLeft(), extShieldRight(), extShieldBottom(), extShieldTop();
/* Structure to pass on to the coupling and sidewall capacitance */
/* routines to include the current cell definition and the current */
@ -79,8 +81,16 @@ typedef struct _esws {
Boundary *bp;
int plane_of_boundary;
int plane_checked;
float shieldfrac;
} extSidewallStruct;
/* Structure to pass the value for fringe shielding */
typedef struct _efss {
Boundary *bp;
float shieldfrac; // Fraction of fringe capacitance shielded
} extFringeShieldStruct;
/* --------------------- Debugging stuff ---------------------- */
#define CAP_DEBUG FALSE
@ -138,6 +148,15 @@ void extAdjustCouple(he, c, str)
* hash table. (We may want to deduct the perimeter capacitance
* to substrate?).
*
* and a mitigating effect:
*
* Sidewall
* shield. When another shape on the same plane is in the proximity of
* a sidewall edge, then the other shape partially shields the
* fringe (sidewall overlap) capacitance. The amount of shielding
* is modeled by an ellipse between the fringe effect distance
* exts_fringeShieldHalo (no shielding) and zero (full shielding).
*
* Requires that ExtFindRegions has been run on 'def' to label all its
* tiles with NodeRegions. Also requires that the HashTable 'table'
* has been initialized by the caller.
@ -688,13 +707,6 @@ extAddCouple(bp, ecs)
GEOCLIP(&bp->b_segment, extCoupleSearchArea);
/* Fixed 2/27/2017 by Tim
* GEO_RECTNULL should not be applied to boundaries, which are
* segments and therefore have no area. This causes the function
* to always return.
*/
/* if (GEO_RECTNULL(&bp->b_segment)) return (0); */
if ((bp->b_segment.r_ytop <= bp->b_segment.r_ybot) &&
(bp->b_segment.r_xtop <= bp->b_segment.r_xbot))
return 0;
@ -730,6 +742,70 @@ extAddCouple(bp, ecs)
&r, &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout],
proc, (ClientData) bp);
if (extCoupleList && extOverlapList && (ExtCurStyle->exts_fringeShieldHalo > 0))
{
extFringeShieldStruct efss;
NodeRegion *rbp;
/* Resize r for fringe shield calculation */
switch (bp->b_direction)
{
case BD_LEFT: /* Along left */
r.r_xbot += ExtCurStyle->exts_sideCoupleHalo ;
r.r_xbot -= ExtCurStyle->exts_fringeShieldHalo ;
proc = extShieldLeft;
break;
case BD_RIGHT: /* Along right */
r.r_xtop -= ExtCurStyle->exts_sideCoupleHalo ;
r.r_xtop += ExtCurStyle->exts_fringeShieldHalo ;
proc = extShieldRight;
break;
case BD_TOP: /* Along top */
r.r_ytop -= ExtCurStyle->exts_sideCoupleHalo ;
r.r_ytop += ExtCurStyle->exts_fringeShieldHalo ;
proc = extShieldTop;
break;
case BD_BOTTOM: /* Along bottom */
r.r_ybot += ExtCurStyle->exts_sideCoupleHalo ;
r.r_ybot -= ExtCurStyle->exts_fringeShieldHalo ;
proc = extShieldBottom;
break;
}
/* Find fringe shielding amount */
efss.bp = bp;
efss.shieldfrac = 0.0;
(void) DBSrPaintArea((Tile *) NULL, def->cd_planes[ecs->plane],
&r, &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout],
proc, (ClientData) &efss);
esws.shieldfrac = efss.shieldfrac;
/* Remove the part of the capacitance to substrate that came from
* the sidewall overlap and that was shielded by the nearby shape.
*/
if (esws.shieldfrac > 0.0)
{
int length;
CapValue subcap;
if (bp->b_segment.r_xtop == bp->b_segment.r_xbot)
length = bp->b_segment.r_ytop - bp->b_segment.r_ybot;
else
length = bp->b_segment.r_xtop - bp->b_segment.r_xbot;
subcap = ExtCurStyle->exts_perimCap[tin][tout] * length * esws.shieldfrac;
rbp = (NodeRegion *) extGetRegion(bp->b_inside);
rbp->nreg_cap -= subcap;
}
}
else
esws.shieldfrac = 0.0;
if (extOverlapList)
{
pMask = ExtCurStyle->exts_sideOverlapOtherPlanes[tin][tout];
@ -861,7 +937,7 @@ extSideOverlap(tp, esws)
}
}
if (rtp != rbp)
cap += e->ec_cap * ov.o_area;
cap += e->ec_cap * ov.o_area * (1.0 - esws->shieldfrac);
areaAccountedFor += ov.o_area;
}
}
@ -889,6 +965,7 @@ extSideOverlap(tp, esws)
outtype = DBPlaneToResidue(outtype, esws->plane_of_boundary);
subcap = (ExtCurStyle->exts_perimCap[ta][outtype] *
(1.0 - esws->shieldfrac) *
MIN(areaAccountedFor, length));
rbp->nreg_cap -= subcap;
/* Ignore residual error at ~zero zeptoFarads. Probably */
@ -1175,3 +1252,216 @@ extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep)
}
extSetCapValue(he, cap);
}
/*
* ----------------------------------------------------------------------------
*
* extShieldLeft --
*
* Searching to the left of the boundary 'bp', we found the tile
* 'tpfar' which may lie on the far side of an edge to which the
* edge bp->b_inside | bp->b_outside shields the fringing capacitance.
*
* Walk along the right-hand side of 'tpfar' searching for such edges,
* and recording the amount of shielding in the passed structure.
*
* Results:
* Returns 0 always.
*
* Side effects:
* Updates efss->shieldfrac
*
* ----------------------------------------------------------------------------
*/
int
extShieldLeft(tpfar, efss)
Tile *tpfar;
extFringeShieldStruct *efss;
{
Boundary *bp = efss->bp;
Tile *tpnear;
float fshield; /* fraction shielded for this segment */
float frac; /* ratio of segment to boundary length */
int sep = bp->b_segment.r_xbot - RIGHT(tpfar);
int limit = MAX(bp->b_segment.r_ybot, BOTTOM(tpfar));
int start = MIN(bp->b_segment.r_ytop, TOP(tpfar));
float halo = (float)ExtCurStyle->exts_fringeShieldHalo;
float fsep = (float)sep;
for (tpnear = TR(tpfar); TOP(tpnear) > limit; tpnear = LB(tpnear))
{
int overlap = MIN(TOP(tpnear), start) - MAX(BOTTOM(tpnear), limit);
if (overlap > 0)
{
frac = (float)(bp->b_segment.r_ytop - bp->b_segment.r_ybot) /
(float)(start - limit);
/* Use sin() approximation for shielding effect */
fshield = 1.0 - sin(1.571 * fsep / halo);
efss->shieldfrac = fshield * frac + efss->shieldfrac * (1.0 - frac);
}
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extShieldRight --
*
* Searching to the right of the boundary 'bp', we found the tile
* 'tpfar' which may lie on the far side of an edge to which the
* edge bp->b_inside | bp->b_outside shields the fringing capacitance.
*
* Walk along the left-hand side of 'tpfar' searching for such edges,
* and recording the amount of shielding in the passed structure.
*
* Results:
* Returns 0 always.
*
* Side effects:
* Updates efss->shieldfrac
*
* ----------------------------------------------------------------------------
*/
int
extShieldRight(tpfar, efss)
Tile *tpfar;
extFringeShieldStruct *efss;
{
Boundary *bp = efss->bp;
Tile *tpnear;
float fshield; /* fraction shielded for this segment */
float frac; /* ratio of segment to boundary length */
int sep = LEFT(tpfar) - bp->b_segment.r_xtop;
int limit = MIN(bp->b_segment.r_ytop, TOP(tpfar));
int start = MAX(bp->b_segment.r_ybot, BOTTOM(tpfar));
float halo = (float)ExtCurStyle->exts_fringeShieldHalo;
float fsep = (float)sep;
for (tpnear = BL(tpfar); BOTTOM(tpnear) < limit; tpnear = RT(tpnear))
{
int overlap = MIN(TOP(tpnear), limit) - MAX(BOTTOM(tpnear), start);
if (overlap > 0)
{
frac = (float)(bp->b_segment.r_ytop - bp->b_segment.r_ybot) /
(float)(limit - start);
/* Use sin() approximation for shielding effect */
fshield = 1.0 - sin(1.571 * fsep / halo);
efss->shieldfrac = fshield * frac + efss->shieldfrac * (1.0 - frac);
}
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extShieldTop --
*
* Searching to the top of the boundary 'bp', we found the tile
* 'tpfar' which may lie on the far side of an edge to which the
* edge bp->b_inside | bp->b_outside shields the fringing capacitance.
*
* Walk along the bottom side of 'tpfar' searching for such edges,
* and recording the amount of shielding in the passed structure.
*
* Results:
* Returns 0 always.
*
* Side effects:
* Updates efss->shieldfrac
*
* ----------------------------------------------------------------------------
*/
int
extShieldTop(tpfar, efss)
Tile *tpfar;
extFringeShieldStruct *efss;
{
Boundary *bp = efss->bp;
Tile *tpnear;
float fshield; /* fraction shielded for this segment */
float frac; /* ratio of segment to boundary length */
int sep = BOTTOM(tpfar) - bp->b_segment.r_ytop;
int limit = MIN(bp->b_segment.r_xtop, RIGHT(tpfar));
int start = MAX(bp->b_segment.r_xbot, LEFT(tpfar));
float halo = (float)ExtCurStyle->exts_fringeShieldHalo;
float fsep = (float)sep;
for (tpnear = LB(tpfar); LEFT(tpnear) < limit; tpnear = TR(tpnear))
{
int overlap = MIN(RIGHT(tpnear), limit) - MAX(LEFT(tpnear), start);
if (overlap > 0)
{
frac = (float)(bp->b_segment.r_xtop - bp->b_segment.r_xbot) /
(float)(limit - start);
/* Use sin() approximation for shielding effect */
fshield = 1.0 - sin(1.571 * fsep / halo);
efss->shieldfrac = fshield * frac + efss->shieldfrac * (1.0 - frac);
}
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extShieldBottom --
*
* Searching to the bottom of the boundary 'bp', we found the tile
* 'tpfar' which may lie on the far side of an edge to which the
* edge bp->b_inside | bp->b_outside shields the fringing capacitance.
*
* Walk along the top side of 'tpfar' searching for such
* and recording the amount of shielding in the passed structure.
*
* Results:
* Returns 0 always.
*
* Side effects:
* Updates efss->shieldfrac
*
* ----------------------------------------------------------------------------
*/
int
extShieldBottom(tpfar, efss)
Tile *tpfar;
extFringeShieldStruct *efss;
{
Boundary *bp = efss->bp;
Tile *tpnear;
float fshield; /* fraction shielded for this segment */
float frac; /* ratio of segment to boundary length */
int sep = bp->b_segment.r_ybot - TOP(tpfar);
int limit = MAX(bp->b_segment.r_xbot, LEFT(tpfar));
int start = MIN(bp->b_segment.r_xtop, RIGHT(tpfar));
float halo = (float)ExtCurStyle->exts_fringeShieldHalo;
float fsep = (float)sep;
for (tpnear = RT(tpfar); RIGHT(tpnear) > limit; tpnear = BL(tpnear))
{
int overlap = MIN(RIGHT(tpnear), start) - MAX(LEFT(tpnear), limit);
if (overlap > 0)
{
frac = (float)(bp->b_segment.r_xtop - bp->b_segment.r_xbot) /
(float)(start - limit);
/* Use sin() approximation for shielding effect */
fshield = 1.0 - sin(1.571 * fsep / halo);
efss->shieldfrac = fshield * frac + efss->shieldfrac * (1.0 - frac);
}
}
return (0);
}

View File

@ -74,7 +74,8 @@ typedef enum
AREAC, CONTACT, CSCALE,
DEFAULTAREACAP, DEFAULTOVERLAP, DEFAULTPERIMETER, DEFAULTSIDEOVERLAP,
DEFAULTSIDEWALL,
DEVICE, FET, FETRESIST, HEIGHT, ANTENNA, MODEL, TIEDOWN, LAMBDA, OVERC,
DEVICE, FET, FETRESIST, FRINGESHIELDHALO,
HEIGHT, ANTENNA, MODEL, TIEDOWN, LAMBDA, OVERC,
PERIMC, PLANEORDER, NOPLANEORDER, RESIST, RSCALE, SIDEHALO, SIDEOVERLAP,
SIDEWALL, STEP, STYLE, SUBSTRATE, UNITS, VARIANT
} Key;
@ -122,6 +123,9 @@ static keydesc keyTable[] = {
"fetresist", FETRESIST, 4, 4,
"type region ohms-per-square",
"fringeshieldhalo", FRINGESHIELDHALO, 2, 2,
"distance",
"height", HEIGHT, 4, 4,
"type height-above-subtrate thickness",
@ -155,7 +159,7 @@ static keydesc keyTable[] = {
"resistance-scalefactor",
"sidehalo", SIDEHALO, 2, 2,
"halo",
"distance",
"sideoverlap", SIDEOVERLAP, 5, 6,
"intypes outtypes ovtypes capacitance [shieldtypes]",
@ -811,6 +815,7 @@ extTechStyleInit(style)
}
style->exts_sideCoupleHalo = 0;
style->exts_fringeShieldHalo = 0;
style->exts_stepSize = 100;
style->exts_unitsPerLambda = 100.0;
style->exts_resistScale = 1000;
@ -2974,6 +2979,13 @@ ExtTechLine(sectionName, argc, argv)
dhalo *= (double)1000.0;
ExtCurStyle->exts_sideCoupleHalo = (int)dhalo;
break;
case FRINGESHIELDHALO:
/* Allow floating-point and increase by factor of 1000 */
/* to accommodate "units microns". */
sscanf(argv[1], "%lg", &dhalo);
dhalo *= (double)1000.0;
ExtCurStyle->exts_fringeShieldHalo = (int)dhalo;
break;
case PERIMC:
DBTechNoisyNameMask(argv[2], &types2);
TTMaskSetMask(allExtractTypes, &types2);
@ -3451,10 +3463,12 @@ zinit:
style->exts_height[r] /= dscale;
}
/* side halo and step size are also in microns */
/* side halo, fringe shield halo, and step size are also in microns */
style->exts_sideCoupleHalo = (int)(((float)style->exts_sideCoupleHalo
/ dscale) + 0.5);
style->exts_fringeShieldHalo = (int)(((float)style->exts_fringeShieldHalo
/ dscale) + 0.5);
style->exts_stepSize = (int)(((float)style->exts_stepSize
/ dscale) + 0.5);
}
@ -3471,6 +3485,7 @@ zinit:
/* needed, so normalize it back to lambda units. */
style->exts_sideCoupleHalo /= 1000;
style->exts_fringeShieldHalo /= 1000;
}
/*
@ -3499,6 +3514,7 @@ ExtTechScale(scalen, scaled)
style->exts_unitsPerLambda = style->exts_unitsPerLambda * (float)scalen
/ (float)scaled;
DBScaleValue(&style->exts_sideCoupleHalo, scaled, scalen);
DBScaleValue(&style->exts_fringeShieldHalo, scaled, scalen);
DBScaleValue(&style->exts_stepSize, scaled, scalen);
for (i = 0; i < DBNumTypes; i++)

View File

@ -782,6 +782,16 @@ typedef struct extstyle
*/
int exts_sideCoupleHalo;
/*
* Search out a distance exts_fringeShieldHalo from each edge
* for types on the same plane that partially shield fringe
* capacitance. The shielding is modeled as an ellipse equation
* and the shield halo should be approximately 10x the distance
* where half the fringe capacitance is shielded. If not specified,
* then it is set to be equal to exts_sideCoupleHalo.
*/
int exts_fringeShieldHalo;
/*
* Sidewall-overlap coupling capacitance.
* This is between an edge on one plane and a type on another plane