diff --git a/VERSION b/VERSION index 5c92172e..c37ace7e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.671 +8.3.672 diff --git a/commands/CmdE.c b/commands/CmdE.c index f3b0a148..ddb1725a 100644 --- a/commands/CmdE.c +++ b/commands/CmdE.c @@ -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; diff --git a/doc/html/extract.html b/doc/html/extract.html index b1926498..aaec972d 100644 --- a/doc/html/extract.html +++ b/doc/html/extract.html @@ -45,6 +45,26 @@ Circuit netlist extractor
coupling
Extract the parasitic coupling capacitance between nodes. +
corners [value] +
(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 value (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 "all".
lumped
Extract lumped resistance values. The values extracted are "lumped" resistance and diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 0764a5f9..2bb9d942 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -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; } diff --git a/extract/ExtCouple.c b/extract/ExtCouple.c index 96b7b1ed..fd0f7223 100644 --- a/extract/ExtCouple.c +++ b/extract/ExtCouple.c @@ -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); + } + } +} + /* * ---------------------------------------------------------------------------- * diff --git a/extract/ExtMain.c b/extract/ExtMain.c index ec1f475d..fef5f82a 100644 --- a/extract/ExtMain.c +++ b/extract/ExtMain.c @@ -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 " and is meant + * to be calibrated against field equation solver results. + */ +double ExtCornerFactor = 1.0; + /* --------------------------- Global data ---------------------------- */ /* Cumulative yank buffer for hierarchical circuit extraction */ diff --git a/extract/extract.h b/extract/extract.h index 6cf1db38..5f25ab67 100644 --- a/extract/extract.h +++ b/extract/extract.h @@ -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