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:
parent
083c0c10e9
commit
d98645afc1
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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++)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue