Corrected the antenna checking routines, which were incorrect with

respect to calculations around diode-connected diffusion regions.
The diffusion area calculation needed to be fixed to avoid double-
counting contacts, and the value for the ratioDiffA coefficient
needed to be scaled, since it is multiplied by the diffusion area
and therefore has dimensioned units of (1/area^2) and should be
treated like all other dimensioned units in magic.
This commit is contained in:
Tim Edwards 2022-11-06 11:50:05 -05:00
parent 3534b79994
commit a9aafebfc4
3 changed files with 205 additions and 68 deletions

View File

@ -1 +1 @@
8.3.335
8.3.336

View File

@ -36,6 +36,8 @@
#include "extract/extractInt.h"
#include "select/select.h"
#include "utils/malloc.h"
#include "cif/cif.h" /* For CIFGetContactSize() */
#include "cif/CIFint.h" /* For CIFCurStyle */
/* C99 compat */
#include "extract/extract.h"
@ -91,11 +93,13 @@ typedef struct _aas {
dlong *accum; /* Pointer to array of accumulated areas per type */
int pNum; /* Plane of check */
Rect r; /* Holds any one visited rectangle */
Rect via; /* Holds any one visitid via rectangle */
CellDef *def; /* CellDef for adding feedback */
} AntennaAccumStruct;
typedef struct _gdas {
dlong accum; /* Accumulated area of all gates/diff */
int pNum; /* Plane of check */
Rect r; /* Holds any one visited rectangle */
CellDef *def; /* CellDef for adding feedback */
} GateDiffAccumStruct;
@ -363,7 +367,7 @@ antennacheckVisit(dev, hc, scale, trans, editUse)
TileType t, conType;
int pos, pNum, pNum2, pmax, p, i, j, total;
dlong gatearea, diffarea;
double anttotal;
double anttotal, conttotal;
float saveRatio, ratioTotal;
dlong *antennaarea;
Rect r, gaterect;
@ -526,13 +530,17 @@ antennacheckVisit(dev, hc, scale, trans, editUse)
/* Search planes of tie types and accumulate all tiedown areas */
gdas.accum = (dlong)0;
for (p = 0; p < DBNumPlanes; p++)
{
gdas.pNum = p;
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p],
&TiPlaneRect, &ExtCurStyle->exts_antennaTieTypes,
areaAccumFunc, (ClientData)&gdas);
}
diffarea = gdas.accum;
/* Search plane of gate type and accumulate all gate area */
gdas.accum = (dlong)0;
gdas.pNum = pNum;
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum],
&TiPlaneRect, &gatemask, areaAccumFunc, (ClientData)&gdas);
gatearea = gdas.accum;
@ -552,16 +560,25 @@ antennacheckVisit(dev, hc, scale, trans, editUse)
}
antennaError = FALSE;
if (diffarea == 0)
{
anttotal = 0.0;
conttotal = 0.0;
saveRatio = 0.0;
for (i = 0; i < DBNumTypes; i++)
for (i = 0; i < DBNumUserLayers; i++)
{
if (ExtCurStyle->exts_antennaRatio[i].ratioGate > 0)
{
anttotal += (double)antennaarea[i] /
(double)ExtCurStyle->exts_antennaRatio[i].ratioGate;
/* Partial model computes vias separately */
if ((ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL)
&& !DBIsContact(i))
anttotal += (double)antennaarea[i] /
(double)ExtCurStyle->exts_antennaRatio[i].ratioGate;
else if ((ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL)
&& (DBPlane(i) == pNum2))
conttotal += (double)antennaarea[i] /
(double)ExtCurStyle->exts_antennaRatio[i].ratioGate;
}
if (ExtCurStyle->exts_antennaRatio[i].ratioGate > saveRatio)
saveRatio = ExtCurStyle->exts_antennaRatio[i].ratioGate;
@ -572,7 +589,10 @@ antennacheckVisit(dev, hc, scale, trans, editUse)
antennaError = TRUE;
if (efAntennaDebug == TRUE)
{
TxError("Cell: %s\n", hc->hc_use->use_id);
if (hc->hc_use->use_id)
TxError("Cell: %s\n", hc->hc_use->use_id);
else
TxError("Cell: %s\n", hc->hc_use->use_def->def_name);
TxError("Antenna violation detected at plane %s\n",
DBPlaneLongNameTbl[pNum2]);
TxError("Effective antenna ratio %g > limit %g\n",
@ -586,19 +606,53 @@ antennacheckVisit(dev, hc, scale, trans, editUse)
aas.r.r_xtop, aas.r.r_ytop);
}
}
if (conttotal > (double)gatearea)
{
antennaError = TRUE;
if (efAntennaDebug == TRUE)
{
if (hc->hc_use->use_id)
TxError("Cell: %s\n", hc->hc_use->use_id);
else
TxError("Cell: %s\n", hc->hc_use->use_def->def_name);
TxError("Antenna violation detected at plane %s contact\n",
DBPlaneLongNameTbl[pNum2]);
TxError("Effective antenna ratio %g > limit %g\n",
saveRatio * (float)conttotal / (float)gatearea,
saveRatio);
TxError("Gate rect (%d %d) to (%d %d)\n",
gdas.r.r_xbot, gdas.r.r_ybot,
gdas.r.r_xtop, gdas.r.r_ytop);
TxError("Antenna rect (%d %d) to (%d %d)\n",
aas.r.r_xbot, aas.r.r_ybot,
aas.r.r_xtop, aas.r.r_ytop);
}
}
}
else
{
anttotal = 0.0;
conttotal = 0.0;
saveRatio = 0.0;
for (i = 0; i < DBNumTypes; i++)
for (i = 0; i < DBNumUserLayers; i++)
if (ExtCurStyle->exts_antennaRatio[i].ratioDiffB != INFINITY)
{
ratioTotal = ExtCurStyle->exts_antennaRatio[i].ratioDiffB +
diffarea * ExtCurStyle->exts_antennaRatio[i].ratioDiffA;
/* Compute effective gate ratio increased by diffusion area */
ratioTotal = ExtCurStyle->exts_antennaRatio[i].ratioGate +
ExtCurStyle->exts_antennaRatio[i].ratioDiffB +
ExtCurStyle->exts_antennaRatio[i].ratioDiffA *
(double)diffarea;
if (ratioTotal > 0)
anttotal += (double)antennaarea[i] / (double)ratioTotal;
{
/* Partial model computes vias separately */
if ((ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL)
&& !DBIsContact(i))
anttotal += (double)antennaarea[i] / ratioTotal;
else if ((ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL)
&& (DBPlane(i) == pNum2))
conttotal += (double)antennaarea[i] / ratioTotal;
}
if (ratioTotal > saveRatio)
saveRatio = ratioTotal;
}
@ -608,7 +662,10 @@ antennacheckVisit(dev, hc, scale, trans, editUse)
antennaError = TRUE;
if (efAntennaDebug == TRUE)
{
TxError("Cell: %s\n", hc->hc_use->use_id);
if (hc->hc_use->use_id)
TxError("Cell: %s\n", hc->hc_use->use_id);
else
TxError("Cell: %s\n", hc->hc_use->use_def->def_name);
TxError("Antenna violation detected at plane %s\n",
DBPlaneLongNameTbl[pNum2]);
TxError("Effective antenna ratio %g > limit %g\n",
@ -622,6 +679,28 @@ antennacheckVisit(dev, hc, scale, trans, editUse)
aas.r.r_xtop, aas.r.r_ytop);
}
}
if (conttotal > (double)gatearea)
{
antennaError = TRUE;
if (efAntennaDebug == TRUE)
{
if (hc->hc_use->use_id)
TxError("Cell: %s\n", hc->hc_use->use_id);
else
TxError("Cell: %s\n", hc->hc_use->use_def->def_name);
TxError("Antenna violation detected at plane %s contact\n",
DBPlaneLongNameTbl[pNum2]);
TxError("Effective antenna ratio %g > limit %g\n",
saveRatio * (float)conttotal / (float)gatearea,
saveRatio);
TxError("Gate rect (%d %d) to (%d %d)\n",
gdas.r.r_xbot, gdas.r.r_ybot,
gdas.r.r_xtop, gdas.r.r_ytop);
TxError("Antenna rect (%d %d) to (%d %d)\n",
aas.r.r_xbot, aas.r.r_ybot,
aas.r.r_xtop, aas.r.r_ytop);
}
}
}
if (antennaError)
@ -697,6 +776,16 @@ areaAccumFunc(tile, gdas)
int type;
dlong area;
/* Avoid double-counting the area of contacts */
if (IsSplit(tile))
type = SplitSide(tile) ? SplitRightType(tile) : SplitLeftType(tile);
else
type = TiGetType(tile);
if (DBIsContact(type))
if (DBPlane(type) != gdas->pNum)
return 0;
TiToRect(tile, rect);
area = (dlong)(rect->r_xtop - rect->r_xbot) * (dlong)(rect->r_ytop - rect->r_ybot);
gdas->accum += area;
@ -722,64 +811,18 @@ antennaAccumFunc(tile, aaptr)
AntennaAccumStruct *aaptr;
{
Rect *rect = &(aaptr->r);
Rect *cont = &(aaptr->via);
dlong area;
int type;
dlong *typeareas = aaptr->accum;
int plane = aaptr->pNum;
float thick;
float thick, fcutsize;
int cutsize, cutsep, cutborder, nx, ny, w, h;
type = TiGetType(tile);
TiToRect(tile, rect);
if (ExtCurStyle->exts_antennaRatio[type].areaType & ANTENNAMODEL_SIDEWALL)
{
/* Accumulate perimeter of tile where tile abuts space */
Tile *tp;
int perimeter = 0, pmax, pmin;
/* Top */
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
{
if (TiGetBottomType(tp) == TT_SPACE)
{
pmin = MAX(LEFT(tile), LEFT(tp));
pmax = MIN(RIGHT(tile), RIGHT(tp));
perimeter += (pmax - pmin);
}
}
/* Bottom */
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
{
if (TiGetTopType(tp) == TT_SPACE)
{
pmin = MAX(LEFT(tile), LEFT(tp));
pmax = MIN(RIGHT(tile), RIGHT(tp));
perimeter += (pmax - pmin);
}
}
/* Left */
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
{
if (TiGetRightType(tp) == TT_SPACE)
{
pmin = MAX(BOTTOM(tile), BOTTOM(tp));
pmax = MIN(TOP(tile), TOP(tp));
perimeter += (pmax - pmin);
}
}
/* Right */
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
{
if (TiGetLeftType(tp) == TT_SPACE)
{
pmin = MAX(BOTTOM(tile), BOTTOM(tp));
pmax = MIN(TOP(tile), TOP(tp));
perimeter += (pmax - pmin);
}
}
if (DBIsContact(type))
{
int cperim;
@ -787,7 +830,22 @@ antennaAccumFunc(tile, aaptr)
TileTypeBitMask sMask;
float thick;
cperim = ((rect->r_xtop - rect->r_xbot) + (rect->r_ytop - rect->r_ybot)) << 1;
TiToRect(tile, cont);
/* Simple cut area calculation. Note that this is not the same as */
/* the GDS output routine for contact cuts, and can be wrong for */
/* partially overlapping contacts where the tiles get subdivided. */
CIFGetContactSize(type, &cutsize, &cutsep, &cutborder);
w = cont->r_xtop - cont->r_xbot;
h = cont->r_ytop - cont->r_ybot;
nx = (w - 2 * cutborder) / (cutsize + cutsep);
ny = (h - 2 * cutborder) / (cutsize + cutsep);
if (nx == 0) nx = 1;
if (ny == 0) ny = 1;
cperim = nx * ny * (cutsize << 2) / CIFCurStyle->cs_scaleFactor;
/* For contacts, add the area of the perimeter to the */
/* residue (metal) type on the plane being searched. */
@ -801,7 +859,7 @@ antennaAccumFunc(tile, aaptr)
if (DBTypeOnPlane(ttype, plane))
{
thick = ExtCurStyle->exts_thick[ttype];
typeareas[ttype] += (dlong)((float)perimeter * thick);
typeareas[ttype] += (dlong)((float)cperim * thick);
}
/* NOTE: The "partial" model ignores the contribution of vias. */
@ -815,19 +873,67 @@ antennaAccumFunc(tile, aaptr)
if (DBTypeOnPlane(ttype, plane))
{
thick = ExtCurStyle->exts_thick[ttype];
typeareas[ttype] += (dlong)((float)perimeter * thick);
typeareas[ttype] += (dlong)((float)cperim * thick);
break;
}
}
else
{
thick = ExtCurStyle->exts_thick[type];
typeareas[type] += (dlong)((float)perimeter * thick);
typeareas[type] += (dlong)((float)cperim * thick);
}
}
}
else
{
Tile *tp;
int perimeter = 0, pmax, pmin;
TiToRect(tile, rect);
/* Accumulate perimeter of tile where tile abuts space */
/* Top */
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
{
if (TiGetBottomType(tp) == TT_SPACE)
{
pmin = MAX(LEFT(tile), LEFT(tp));
pmax = MIN(RIGHT(tile), RIGHT(tp));
perimeter += (pmax - pmin);
}
}
/* Bottom */
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
{
if (TiGetTopType(tp) == TT_SPACE)
{
pmin = MAX(LEFT(tile), LEFT(tp));
pmax = MIN(RIGHT(tile), RIGHT(tp));
perimeter += (pmax - pmin);
}
}
/* Left */
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
{
if (TiGetRightType(tp) == TT_SPACE)
{
pmin = MAX(BOTTOM(tile), BOTTOM(tp));
pmax = MIN(TOP(tile), TOP(tp));
perimeter += (pmax - pmin);
}
}
/* Right */
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
{
if (TiGetLeftType(tp) == TT_SPACE)
{
pmin = MAX(BOTTOM(tile), BOTTOM(tp));
pmax = MIN(TOP(tile), TOP(tp));
perimeter += (pmax - pmin);
}
}
/* Area is perimeter times layer thickness */
thick = ExtCurStyle->exts_thick[type];
typeareas[type] += (dlong)((float)perimeter * thick);
@ -835,10 +941,6 @@ antennaAccumFunc(tile, aaptr)
}
else if (ExtCurStyle->exts_antennaRatio[type].areaType & ANTENNAMODEL_SURFACE)
{
/* Simple tile area calculation */
area = (dlong)(rect->r_xtop - rect->r_xbot)
* (dlong)(rect->r_ytop - rect->r_ybot);
/* If type is a contact, then add area to both residues as well */
/* as the contact type. */
@ -850,6 +952,24 @@ antennaAccumFunc(tile, aaptr)
TileType ttype;
TileTypeBitMask sMask;
TiToRect(tile, cont);
/* Simple cut area calculation. Note that this is not the same as */
/* the GDS output routine for contact cuts, and can be wrong for */
/* partially overlapping contacts where the tiles get subdivided. */
CIFGetContactSize(type, &cutsize, &cutsep, &cutborder);
w = cont->r_xtop - cont->r_xbot;
h = cont->r_ytop - cont->r_ybot;
nx = (w - 2 * cutborder) / (cutsize + cutsep);
ny = (h - 2 * cutborder) / (cutsize + cutsep);
if (nx == 0) nx = 1;
if (ny == 0) ny = 1;
fcutsize = (float)cutsize / (float)CIFCurStyle->cs_scaleFactor;
area = (dlong)(nx * ny) * (dlong)(fcutsize * fcutsize);
DBFullResidueMask(type, &sMask);
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
if (TTMaskHasType(&sMask, ttype))
@ -871,7 +991,13 @@ antennaAccumFunc(tile, aaptr)
typeareas[type] += area;
}
else
{
TiToRect(tile, rect);
area = (dlong)(rect->r_xtop - rect->r_xbot)
* (dlong)(rect->r_ytop - rect->r_ybot);
typeareas[type] += area;
}
}
return 0;
}

View File

@ -2727,6 +2727,10 @@ ExtTechLine(sectionName, argc, argv)
else
antennaratio = 0;
/* NOTE: antennaratio is multiplied by diffusion area and so has
* units of (1/area^2) and so it should be scaled with other
* dimension-scaled units.
*/
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
if (TTMaskHasType(&types1, t))
ExtCurStyle->exts_antennaRatio[t].ratioDiffA = antennaratio;
@ -3445,6 +3449,7 @@ zinit:
/* internal units is done separately). */
float dscale = CIFGetOutputScale(1000);
float dsq = dscale * dscale;
CapValue scalefac = (CapValue)dscale;
CapValue sqfac = scalefac * scalefac;
@ -3498,6 +3503,9 @@ zinit:
/* Layer thickness and height are in microns, but are floating-point */
style->exts_thick[r] /= dscale;
style->exts_height[r] /= dscale;
/* Only this antenna coefficient has dimensioned units */
style->exts_antennaRatio[r].ratioDiffA *= dsq;
}
/* side halo, fringe shield halo, and step size are also in microns */
@ -3574,6 +3582,9 @@ ExtTechScale(scalen, scaled)
style->exts_thick[i] *= scaled;
style->exts_thick[i] /= scalen;
style->exts_antennaRatio[i].ratioDiffA *= sqn;
style->exts_antennaRatio[i].ratioDiffA /= sqd;
for (j = 0; j < DBNumTypes; j++)
{
style->exts_perimCap[i][j] *= scalen;