From edb05fb3d149b8f65001dfdeef9112ad86171242 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 17 Mar 2023 13:51:33 -0400 Subject: [PATCH] More corrections to the method of calculating fringe capacitance inside a halo area. The previous implementation used a linear accounting of error to determine the amount of shielding, but since the shielding is nonlinear, this is a poor approximation and regularly overestimates the shielding and leads to negative capacitances. The corrected method makes many more calls to the atan() function and the performance impact for extraction will need to be evaluated. --- VERSION | 2 +- extract/ExtCouple.c | 455 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 385 insertions(+), 72 deletions(-) diff --git a/VERSION b/VERSION index 895fc909..6036b47e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.381 +8.3.382 diff --git a/extract/ExtCouple.c b/extract/ExtCouple.c index dd676425..c4c433c1 100644 --- a/extract/ExtCouple.c +++ b/extract/ExtCouple.c @@ -49,7 +49,7 @@ int extBasicOverlap(), extBasicCouple(); int extAddOverlap(), extAddCouple(); int extSideLeft(), extSideRight(), extSideBottom(), extSideTop(); int extWalkLeft(), extWalkRight(), extWalkBottom(), extWalkTop(); -int extSideOverlap(), extFindOverlap(); +int extSideOverlap(), extSideOverlapHalo(), extFindOverlap(); void extSideCommon(); /* Structure to pass on to the coupling and sidewall capacitance */ @@ -396,6 +396,18 @@ struct overlap TileTypeBitMask o_tmask; }; +struct sideoverlap +{ + Rect so_clip; + double so_coupfrac; + double so_subfrac; + int so_length; + extSidewallStruct *so_esws; + PlaneMask so_pmask; + TileTypeBitMask so_tmask; + TileType so_ctype; +}; + int extAddOverlap(tbelow, ecpls) Tile *tbelow; @@ -595,6 +607,134 @@ extSubtractOverlap2(tile, ov) return (0); } +/* Side overlap shielding. The fraction of the side overlap (fringe) + * capacitance over this area is added to ov->o_frac, so that it can + * be subtracted from the total. + */ + +int +extSubtractSideOverlap(tile, sov) + Tile *tile; + struct sideoverlap *sov; +{ + Rect r; + int area, dnear, dfar, length; + double mult, snear, sfar; + TileType ta, tb; + Boundary *bp = sov->so_esws->bp; + + TITORECT(tile, &r); + GEOCLIP(&r, &sov->so_clip); + area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot); + if (area <= 0) return 0; + + ta = TiGetType(bp->b_inside); + tb = sov->so_ctype; + + if (bp->b_segment.r_xtop == bp->b_segment.r_xbot) + length = r.r_ytop - r.r_ybot; + else + length = r.r_xtop - r.r_xbot; + + switch (bp->b_direction) + { + case BD_LEFT: /* Tile tp is to the left of the boundary */ + dnear = bp->b_segment.r_xbot - r.r_xtop; + dfar = bp->b_segment.r_xbot - r.r_xbot; + break; + case BD_RIGHT: /* Tile tp is to the right of the boundary */ + dnear = r.r_xbot - bp->b_segment.r_xtop; + dfar = r.r_xtop - bp->b_segment.r_xtop; + break; + case BD_BOTTOM: /* Tile tp is below the boundary */ + dnear = bp->b_segment.r_ybot - r.r_ytop; + dfar = bp->b_segment.r_ybot - r.r_ybot; + break; + case BD_TOP: /* Tile tp is above the boundary */ + dnear = r.r_ybot - bp->b_segment.r_ytop; + dfar = r.r_ytop - bp->b_segment.r_ytop; + break; + } + + if (dnear < 0) dnear = 0; /* Don't count underlap */ + mult = ExtCurStyle->exts_overlapMult[ta][0]; + snear = 0.6366 * atan(mult * dnear); + sfar = 0.6366 * atan(mult * dfar); + + /* "sfar - snear" is the fractional portion of the fringe cap */ + /* seen by the substrate in the direction perpendicular to the edge */ + /* generating the fringe cap. This is multiplied by the fraction */ + /* of the total edge length to get the total fraction of the entire */ + /* fringe capacitance being shielded. */ + + sov->so_subfrac += (sfar - snear) * ((double)length / (double)sov->so_length); + + /* Do the same calculation but the the overlap multiplier for the */ + /* coupling layer, since the fringe capacitance has a different */ + /* halo than for the substrate. */ + + mult = ExtCurStyle->exts_overlapMult[ta][tb]; + snear = 0.6366 * atan(mult * dnear); + sfar = 0.6366 * atan(mult * dfar); + sov->so_coupfrac += (sfar - snear) * ((double)length / (double)sov->so_length); + + return (0); +} + +/* Recursive shielding side overlap check. If the tile shields */ +/* then the area of overlap is subtracted from ov->o_area. If */ +/* not, then this routine is called recursively on the next */ +/* shielding plane. */ + +int +extSubtractSideOverlap2(tile, sov) + Tile *tile; + struct sideoverlap *sov; +{ + struct sideoverlap sovnew; + int area, pNum; + Rect r; + + TITORECT(tile, &r); + GEOCLIP(&r, &sov->so_clip); + area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot); + if (area <= 0) + return (0); + + /* This tile shields everything below */ + if (TTMaskHasType(&sov->so_tmask, TiGetType(tile))) + { + extSubtractSideOverlap(tile, sov); + return (0); + } + + /* Tile doesn't shield, so search next plane */ + sovnew = *sov; + sovnew.so_clip = r; + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + { + if (!PlaneMaskHasPlane(sovnew.so_pmask, pNum)) continue; + sovnew.so_pmask &= ~(PlaneNumToMaskBit(pNum)); + if (sovnew.so_pmask == 0) + { + (void) DBSrPaintArea((Tile *) NULL, + extOverlapDef->cd_planes[pNum], &sovnew.so_clip, &sovnew.so_tmask, + extSubtractSideOverlap, (ClientData) &sovnew); + } + else + { + (void) DBSrPaintArea((Tile *) NULL, + extOverlapDef->cd_planes[pNum], &sovnew.so_clip, &DBAllTypeBits, + extSubtractSideOverlap2, (ClientData) &sovnew); + } + break; + } + sov->so_subfrac = sovnew.so_subfrac; + sov->so_coupfrac = sovnew.so_coupfrac; + + return (0); +} + /* * ---------------------------------------------------------------------------- * @@ -866,7 +1006,8 @@ extFindOverlap(tp, area, esws) esws->plane_checked = pNum; (void) DBSrPaintArea((Tile *) NULL, esws->def->cd_planes[pNum], area, &ExtCurStyle->exts_sideOverlapOtherTypes[tin][tout], - extSideOverlap, (ClientData)esws); + (esws->fringe_halo) ? extSideOverlapHalo : extSideOverlap, + (ClientData)esws); } esws->area = rsave; return 0; @@ -875,11 +1016,247 @@ extFindOverlap(tp, area, esws) /* * ---------------------------------------------------------------------------- * - * extSideOverlap -- + * extSideOverlapHalo -- * * The boundary 'bp' has been found to overlap the tile 'tp', which it * has coupling capacitance to. * + * Every tile that couples to an edge is also shielding the substrate + * from that edge. To maintain the proper accounting of the amount of + * substrate shielded, calculate only for the area of the substrate that + * couples to the *unshielded* portion of the tile. The part of the + * substrate that is under a shielded portion of the tile will be handled + * later when calculating coupling to that shielding tile. + * + * + * Results: + * Returns 0 to keep DBSrPaintArea() going. + * + * Side effects: + * Update the coupling capacitance between node(bp->t_inside) and + * node(tp) if the two nodes are different. Does so by updating + * the value stored in the HashEntry keyed by the two nodes. + * + * ---------------------------------------------------------------------------- + */ + +int +extSideOverlapHalo(tp, esws) + Tile *tp; /* Overlapped tile */ + extSidewallStruct *esws; /* Overlapping edge and plane information */ +{ + Boundary *bp = esws->bp; /* Overlapping edge */ + NodeRegion *rtp = (NodeRegion *) extGetRegion(tp); + NodeRegion *rbp = (NodeRegion *) extGetRegion(bp->b_inside); + TileType ta, tb; + Rect tpr; + struct sideoverlap sov; + HashEntry *he; + EdgeCap *e; + int length; + double cfrac, sfrac, afrac, mult, efflength; + CapValue cap, subcap; + CoupleKey ck; + int dfar, dnear; + double sfar, snear, subfrac; + + /* Nothing to do for space tiles, so just return. */ + /* (TO DO: Make sure TT_SPACE is removed from all exts_sideOverlapOtherTypes */ + tb = TiGetType(tp); + if (tb == TT_SPACE) return (0); + + if (bp->b_segment.r_xtop == bp->b_segment.r_xbot) + { + length = MIN(bp->b_segment.r_ytop, TOP(tp)) + - MAX(bp->b_segment.r_ybot, BOTTOM(tp)); + } + else + { + length = MIN(bp->b_segment.r_xtop, RIGHT(tp)) + - MAX(bp->b_segment.r_xbot, LEFT(tp)); + } + + /* Get the area of the coupling tile, and clip to the fringe area */ + /* of the tile edge generating the fringe capacitance. */ + TITORECT(tp, &sov.so_clip); + GEOCLIP(&sov.so_clip, esws->area); + + /* ta is the tile type of the edge 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); + + /* Find the fraction of the fringe cap seen by tile tp (depends */ + /* on the tile width and distance from the boundary) */ + switch (bp->b_direction) + { + case BD_LEFT: /* Tile tp is to the left of the boundary */ + dfar = bp->b_segment.r_ll.p_x - sov.so_clip.r_xbot; + dnear = bp->b_segment.r_ll.p_x - sov.so_clip.r_xtop; + break; + case BD_RIGHT: /* Tile tp is to the right of the boundary */ + dfar = sov.so_clip.r_xtop - bp->b_segment.r_ur.p_x; + dnear = sov.so_clip.r_xbot - bp->b_segment.r_ur.p_x; + break; + case BD_BOTTOM: /* Tile tp is below the boundary */ + dfar = bp->b_segment.r_ll.p_y - sov.so_clip.r_ybot; + dnear = bp->b_segment.r_ll.p_y - sov.so_clip.r_ytop; + break; + case BD_TOP: /* Tile tp is above the boundary */ + dfar = sov.so_clip.r_ytop - bp->b_segment.r_ur.p_y; + dnear = sov.so_clip.r_ybot - bp->b_segment.r_ur.p_y; + break; + } + if (dnear < 0) dnear = 0; /* Don't count underlap */ + mult = ExtCurStyle->exts_overlapMult[ta][tb]; + sfar = 0.6366 * atan(mult * dfar); + snear = 0.6366 * atan(mult * dnear); + + /* "cfrac" is the fractional portion of the fringe cap seen */ + /* by tile tp along its length. This is independent of the */ + /* portion of the boundary length that tile tp occupies. */ + + cfrac = sfar - snear; + + /* The fringe portion extracted from the substrate will be */ + /* different than the portion added to the coupling layer. */ + + mult = ExtCurStyle->exts_overlapMult[ta][0]; + sfar = 0.6366 * atan(mult * dfar); + snear = 0.6366 * atan(mult * dnear); + sfrac = sfar - snear; + + /* Apply each rule, incorporating shielding into the edge length. */ + cap = subcap = (CapValue) 0; + subfrac = 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, TiGetType(tp))) + { + /* We have a possible capacitor, but are the tiles shielded from + * each other part of the way? + */ + int pNum; + sov.so_pmask = ExtCurStyle->exts_sideOverlapShieldPlanes[ta][tb]; + sov.so_esws = esws; + sov.so_coupfrac = (double)0.0; + sov.so_subfrac = (double)0.0; + sov.so_length = length; + sov.so_ctype = tb; + + if (sov.so_pmask) + { + sov.so_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(sov.so_pmask, pNum)) continue; + sov.so_pmask &= ~(PlaneNumToMaskBit(pNum)); + if (sov.so_pmask == 0) + { + (void) DBSrPaintArea((Tile *) NULL, + extOverlapDef->cd_planes[pNum], &sov.so_clip, + &sov.so_tmask, extSubtractSideOverlap, (ClientData) &sov); + } + else + { + (void) DBSrPaintArea((Tile *) NULL, + extOverlapDef->cd_planes[pNum], &sov.so_clip, + &DBAllTypeBits, + extSubtractSideOverlap2, (ClientData) &sov); + } + break; + } + } + if (rtp != rbp) + { + efflength = (cfrac * (double)length) * (1.0 - sov.so_coupfrac); + cap += e->ec_cap * efflength; + + subfrac += sov.so_subfrac; /* Just add the shielded fraction */ + } + } + } + + /* Add in the new capacitance. */ + + if (tb != TT_SPACE) + { + int oa = ExtCurStyle->exts_planeOrder[esws->plane_of_boundary]; + int ob = ExtCurStyle->exts_planeOrder[esws->plane_checked]; + if (oa > ob) + { + /* If the overlapped tile is between the substrate and the boundary + * tile, then we subtract the fringe substrate capacitance + * from rbp's region due to the area of the sideoverlap, since + * we now know it is shielded from the substrate. + */ + TileType outtype = TiGetType(bp->b_outside); + + /* Decompose contacts into their residues */ + if (DBIsContact(ta)) + ta = DBPlaneToResidue(ta, esws->plane_of_boundary); + if (DBIsContact(outtype)) + outtype = DBPlaneToResidue(outtype, esws->plane_of_boundary); + + efflength = (sfrac * (double)length) * (1.0 - subfrac); + subcap = ExtCurStyle->exts_perimCap[ta][0] * efflength; + rbp->nreg_cap -= subcap; + /* Ignore residual error at ~zero zeptoFarads. Probably */ + /* there should be better handling of round-off here. */ + if ((rbp->nreg_cap > -0.001) && (rbp->nreg_cap < 0.001)) + rbp->nreg_cap = 0; + if (CAP_DEBUG) + extNregAdjustCap(rbp, -subcap, "obsolete_perimcap"); + } + else if (CAP_DEBUG) + extNregAdjustCap(rbp, 0.0, "obsolete_perimcap (skipped, wrong direction)"); + + /* If the nodes are electrically connected, then we don't add */ + /* any side overlap capacitance to the node. */ + 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; + } + he = HashFind(extCoupleHashPtr, (char *) &ck); + if (CAP_DEBUG) extAdjustCouple(he, cap, "sideoverlap"); + extSetCapValue(he, cap + extGetCapValue(he)); + } + return (0); +} + +/* + * ---------------------------------------------------------------------------- + * + * extSideOverlap -- + * + * The boundary 'bp' has been found to overlap the tile 'tp', which it + * has coupling capacitance to. This is legacy behavior when no fringe + * halo is considered, but the fringe is modeled as being directed + * downward from an edge onto any layer directly below the edge, and + * occupying no area. This approximation is generally only reasonable for + * processes down to 0.5um or so. + * * Results: * Returns 0 to keep DBSrPaintArea() going. * @@ -905,7 +1282,7 @@ extSideOverlap(tp, esws) HashEntry *he; EdgeCap *e; int length, areaAccountedFor, areaTotal; - double cfrac, sfrac, afrac, mult; + double afrac; CapValue cap; CoupleKey ck; @@ -938,57 +1315,6 @@ extSideOverlap(tp, esws) if (DBIsContact(tb)) tb = DBPlaneToResidue(tb, esws->plane_checked); - /* Find the fraction of the fringe cap seen by tile tp (depends */ - /* on the tile width and distance from the boundary) */ - if (esws->fringe_halo) - { - int dfar, dnear; - double sfar, snear; - - switch (bp->b_direction) - { - case BD_LEFT: /* Tile tp is to the left of the boundary */ - dfar = bp->b_segment.r_ll.p_x - ov.o_clip.r_xbot; - dnear = bp->b_segment.r_ll.p_x - ov.o_clip.r_xtop; - break; - case BD_RIGHT: /* Tile tp is to the right of the boundary */ - dfar = ov.o_clip.r_xtop - bp->b_segment.r_ur.p_x; - dnear = ov.o_clip.r_xbot - bp->b_segment.r_ur.p_x; - break; - case BD_BOTTOM: /* Tile tp is below the boundary */ - dfar = bp->b_segment.r_ll.p_y - ov.o_clip.r_ybot; - dnear = bp->b_segment.r_ll.p_y - ov.o_clip.r_ytop; - break; - case BD_TOP: /* Tile tp is above the boundary */ - dfar = ov.o_clip.r_ytop - bp->b_segment.r_ur.p_y; - dnear = ov.o_clip.r_ybot - bp->b_segment.r_ur.p_y; - break; - } - if (dnear < 0) dnear = 0; /* Don't count underlap */ - mult = ExtCurStyle->exts_overlapMult[ta][tb]; - sfar = 0.6366 * atan(mult * dfar); - snear = 0.6366 * atan(mult * dnear); - - /* "cfrac" is the fractional portion of the fringe cap seen by */ - /* tile tp along its length. This is independent of the */ - /* portion of the boundary length that tile tp occupies. */ - - cfrac = sfar - snear; - - /* The fringe portion extracted from the substrate will be */ - /* different than the portion added to the coupling layer. */ - - mult = ExtCurStyle->exts_overlapMult[ta][0]; - sfar = 0.6366 * atan(mult * dfar); - snear = 0.6366 * atan(mult * dnear); - sfrac = sfar - snear; - } - else - { - cfrac = 1.0; /* For simplified perimeter cap calculation */ - sfrac = 1.0; - } - /* Apply each rule, incorporating shielding into the edge length. */ cap = (CapValue) 0; for (e = esws->extOverlapList; e; e = e->ec_next) @@ -1032,17 +1358,8 @@ extSideOverlap(tp, esws) } } if (rtp != rbp) - { - if (!esws->fringe_halo) - { - cap += e->ec_cap * ov.o_area; - } - else /* (perimeter cap distributed over halo) */ - { - afrac = (double)ov.o_area / (double)areaTotal; - cap += e->ec_cap * length * afrac * cfrac; - } - } + cap += e->ec_cap * ov.o_area; + areaAccountedFor += ov.o_area; } } @@ -1070,12 +1387,8 @@ extSideOverlap(tp, esws) outtype = DBPlaneToResidue(outtype, esws->plane_of_boundary); afrac = (double)areaAccountedFor / (double)areaTotal; - if (!esws->fringe_halo) - subcap = (ExtCurStyle->exts_perimCap[ta][outtype] * + subcap = (ExtCurStyle->exts_perimCap[ta][outtype] * MIN(areaAccountedFor, length)); - else /* Fringe capacitance distributed over halo */ - subcap = (ExtCurStyle->exts_perimCap[ta][outtype] * - sfrac * length * MIN(afrac, 1.0)); rbp->nreg_cap -= subcap; /* Ignore residual error at ~zero zeptoFarads. Probably */ /* there should be better handling of round-off here. */