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