From 1a3caee3761d3ad4d4d4a7e931137b21a608a92d Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 27 Jan 2023 11:47:37 -0500 Subject: [PATCH] (1) Added a check for unclosed boundaries when reading GDS. This is diagnostic only and does not change the read-in behavior. (2) ext2spice: Corrected an error that had been introduced into version 8.3.171 that accidentally marks all devices as visited which causes all source/drain areas and perimeters to be output as zero. (3) extract: Sweeping changes to handling of fringe capacitance. Removed the (recently added) "fringeshieldhalo" parameter from the tech file. Reworked the fringe capacitance models based on results from the "capiche" project (github/RTimothyEdwards/capiche). Fringe shielding is now done by clipping fringe at the boundary of a shielding shape, rather than trying to calculate the amount of shielding (as the "capiche" project proved this to be equivalent). Values for partial fringing are modeled by atan(x), which like the sidewall (1/x) curve, extends to infinity and values are limited by the halo but do not otherwise depend on the halo. Because of this, the halo can be made variable and controlled by the user for deciding on the tradeoff between accuracy and run time. A new command option "extract halo" was added to allow this control over the halo distance. --- VERSION | 2 +- calma/CalmaRdpt.c | 2 +- cif/CIFrdpoly.c | 7 +- cif/CIFrdpt.c | 6 +- commands/CmdCD.c | 2 +- commands/CmdE.c | 50 ++- ext2spice/ext2spice.c | 4 +- extract/ExtCouple.c | 708 +++++++++++++++--------------------------- extract/ExtTech.c | 36 ++- extract/extractInt.h | 23 +- 10 files changed, 341 insertions(+), 499 deletions(-) diff --git a/VERSION b/VERSION index a8daa452..922558bc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.363 +8.3.364 diff --git a/calma/CalmaRdpt.c b/calma/CalmaRdpt.c index b24d18de..6a462ed7 100644 --- a/calma/CalmaRdpt.c +++ b/calma/CalmaRdpt.c @@ -283,7 +283,7 @@ calmaElementBoundary() /* Convert the polygon to rectangles. */ - rp = CIFPolyToRects(pathheadp, plane, CIFPaintTable, (PaintUndoInfo *)NULL); + rp = CIFPolyToRects(pathheadp, plane, CIFPaintTable, (PaintUndoInfo *)NULL, TRUE); CIFFreePath(pathheadp); /* If the input layer is designated for ports by a "label" */ diff --git a/cif/CIFrdpoly.c b/cif/CIFrdpoly.c index 20377b47..3202e68f 100644 --- a/cif/CIFrdpoly.c +++ b/cif/CIFrdpoly.c @@ -29,6 +29,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "database/database.h" #include "cif/CIFint.h" #include "cif/CIFread.h" +#include "calma/calma.h" #include "utils/malloc.h" #define HEDGE 0 /* Horizontal edge */ @@ -222,11 +223,12 @@ cifCross(edge, dir, ybot, ytop) */ LinkedRect * -CIFPolyToRects(path, plane, resultTbl, ui) +CIFPolyToRects(path, plane, resultTbl, ui, isCalma) CIFPath *path; /* Path describing a polygon. */ Plane *plane; /* Plane to draw on */ PaintResultType *resultTbl; PaintUndoInfo *ui; + bool isCalma; /* TRUE for Calma, FALSE for CIF */ { int npts = 0, n, *dir, curr, wrapno; int xbot, xtop, ybot, ytop; @@ -240,6 +242,9 @@ CIFPolyToRects(path, plane, resultTbl, ui) if ((tail->cifp_x != path->cifp_x) || (tail->cifp_y != path->cifp_y)) { + if (isCalma) + CalmaReadError("Boundary is not closed.\n" ); + p = (CIFPath *) mallocMagic ((unsigned) sizeof (CIFPath)); p->cifp_x = path->cifp_x; p->cifp_y = path->cifp_y; diff --git a/cif/CIFrdpt.c b/cif/CIFrdpt.c index e39b49f1..d05bedf1 100644 --- a/cif/CIFrdpt.c +++ b/cif/CIFrdpt.c @@ -481,7 +481,7 @@ CIFPaintWirePath(pathheadp, width, endcap, plane, ptable, ui) /* Slow draw for non-Manhattan paths: */ /* Break the area up into triangles and rectangles */ - rectp = CIFPolyToRects(polypath, plane, ptable, ui); + rectp = CIFPolyToRects(polypath, plane, ptable, ui, FALSE); CIFFreePath(polypath); for (; rectp != NULL ; rectp = rectp->r_next) @@ -583,7 +583,7 @@ PaintPolygon(pointlist, number, plane, ptable, ui, keep) cifpath = newpath; } - rectlist = CIFPolyToRects(cifpath, plane, ptable, ui); + rectlist = CIFPolyToRects(cifpath, plane, ptable, ui, FALSE); CIFFreePath(cifpath); for (rectp = rectlist; rectp != NULL ; rectp = rectp->r_next) @@ -807,7 +807,7 @@ CIFParsePoly() /* Convert the polygon to rectangles. */ rectp = CIFPolyToRects(pathheadp, cifReadPlane, CIFPaintTable, - (PaintUndoInfo *)NULL); + (PaintUndoInfo *)NULL, FALSE); CIFFreePath(pathheadp); if (rectp == NULL) { diff --git a/commands/CmdCD.c b/commands/CmdCD.c index 830bb9c9..822e8de8 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -2907,7 +2907,7 @@ CmdCorner(w, cmd) ui.pu_pNum = pNum; rectp = CIFPolyToRects(cmdPathList.pathlist->pathhead, plane, - resultTbl, &ui); + resultTbl, &ui, FALSE); for (; rectp != NULL; rectp = rectp->r_next) { DBPaintPlane(plane, &rectp->r_r, resultTbl, &ui); diff --git a/commands/CmdE.c b/commands/CmdE.c index 32e13ff7..6f9f7912 100644 --- a/commands/CmdE.c +++ b/commands/CmdE.c @@ -42,6 +42,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "drc/drc.h" #include "textio/txcommands.h" #include "extract/extract.h" +#include "extract/extractInt.h" #include "select/select.h" /* C99 compat */ @@ -860,14 +861,15 @@ cmdExpandFunc(use, windowMask) #define EXTALL 0 #define EXTCELL 1 #define EXTDO 2 -#define EXTHELP 3 -#define EXTLENGTH 4 -#define EXTNO 5 -#define EXTPARENTS 6 -#define EXTSHOWPARENTS 7 -#define EXTSTYLE 8 -#define EXTUNIQUE 9 -#define EXTWARN 10 +#define EXTHALO 3 +#define EXTHELP 4 +#define EXTLENGTH 5 +#define EXTNO 6 +#define EXTPARENTS 7 +#define EXTSHOWPARENTS 8 +#define EXTSTYLE 9 +#define EXTUNIQUE 10 +#define EXTWARN 11 #define WARNALL 0 #define WARNDUP 1 @@ -900,6 +902,7 @@ CmdExtract(w, cmd) { char **msg, *namep, *arg; int option, warn, len, n, all; + int dist; bool no; CellUse *selectedUse; CellDef *selectedDef; @@ -953,6 +956,7 @@ CmdExtract(w, cmd) "all extract root cell and all its children", "cell name extract selected cell into file \"name\"", "do [option] enable extractor option", + "halo [value] print or set the sidewall halo distance", "help print this help information", "length [option] control pathlength extraction information", "no [option] disable extractor option", @@ -1060,6 +1064,36 @@ CmdExtract(w, cmd) ExtractOneCell(selectedUse->cu_def, namep, FALSE); return; + case EXTHALO: + if (ExtCurStyle == NULL) + { + TxError("No extraction style set.\n"); + return; + } + else if (argc == 2) + { +#ifdef MAGIC_WRAPPER + Tcl_Obj *tobj; + tobj = Tcl_NewIntObj(ExtCurStyle->exts_sideCoupleHalo); + Tcl_SetObjResult(magicinterp, tobj); +#else + TxPrintf("Side overlap halo is %d\n", ExtCurStyle->exts_sideCoupleHalo); +#endif + return; + } + else if (argc != 3) goto wrongNumArgs; + + /* argv[2] is a halo distance */ + dist = cmdParseCoord(w, argv[2], TRUE, TRUE); + if (dist <= 0) + { + TxError("Bad halo distance. Halo must be strictly positive."); + return; + } + else + ExtCurStyle->exts_sideCoupleHalo = dist; + break; + case EXTPARENTS: selectedUse = CmdGetSelectedCell((Transform *) NULL); if (selectedUse == NULL) diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 143d1e86..6d2e6033 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -1093,7 +1093,7 @@ runexttospice: TTMaskZero(&initMask); if (!esDistrJunct) - TTMaskCom(&initMask); + TTMaskSetType(&initMask, efNumResistClasses); if (esMergeDevsA || esMergeDevsC) { @@ -1271,7 +1271,7 @@ main(argc, argv) TTMaskZero(&initMask); if (!esDistrJunct) - TTMaskCom(&initMask); + TTMaskSetType(&initMask, efNumResistClasses); if ( esMergeDevsA || esMergeDevsC ) { EFVisitDevs(devMergeVisit, (ClientData) NULL); diff --git a/extract/ExtCouple.c b/extract/ExtCouple.c index c17d068c..3f6b1745 100644 --- a/extract/ExtCouple.c +++ b/extract/ExtCouple.c @@ -22,7 +22,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #endif /* not lint */ #include -#include /* For sin() */ +#include /* For atan() */ #include "utils/magic.h" #include "utils/geometry.h" @@ -41,10 +41,6 @@ HashTable *extCoupleHashPtr; /* Clipping area for coupling searches */ Rect *extCoupleSearchArea; -/* Current list of sidewall capacitance rules */ -EdgeCap *extCoupleList; -EdgeCap *extOverlapList; - /* Def being processed */ CellDef *extOverlapDef; @@ -52,9 +48,8 @@ CellDef *extOverlapDef; int extBasicOverlap(), extBasicCouple(); int extAddOverlap(), extAddCouple(); int extSideLeft(), extSideRight(), extSideBottom(), extSideTop(); -int extShieldLeft(), extShieldRight(), extShieldBottom(), extShieldTop(); int extWalkLeft(), extWalkRight(), extWalkBottom(), extWalkTop(); -int extSideOverlap(); +int extSideOverlap(), extFindOverlap(); void extSideCommon(); /* Structure to pass on to the coupling and sidewall capacitance */ @@ -80,10 +75,13 @@ typedef struct _ecpls { typedef struct _esws { Boundary *bp; - int plane_of_boundary; - int plane_checked; - int fringe_halo; - float shieldfrac; + int plane_of_boundary; + int plane_checked; + bool fringe_halo; + Rect *area; + EdgeCap *extCoupleList; /* List of sidewall capacitance rules */ + EdgeCap *extOverlapList; /* List of overlap capacitance rules */ + CellDef *def; } extSidewallStruct; /* --------------------- Debugging stuff ---------------------- */ @@ -142,15 +140,6 @@ void extAdjustCouple(he, c, str) * hash table. (We may want to deduct the perimeter capacitance * to substrate?). * - * and a mitigating effect: - * - * Sidewall - * shield. When another shape on the same plane is in the proximity of - * a sidewall edge, then the other shape partially shields the - * fringe (sidewall overlap) capacitance. The amount of shielding - * is modeled by an ellipse between the fringe effect distance - * exts_fringeShieldHalo (no shielding) and zero (full shielding). - * * Requires that ExtFindRegions has been run on 'def' to label all its * tiles with NodeRegions. Also requires that the HashTable 'table' * has been initialized by the caller. @@ -670,8 +659,6 @@ extBasicCouple(tile, ecs) * ---------------------------------------------------------------------------- */ -Rect extSideOverlapSearchArea; - int extAddCouple(bp, ecs) Boundary *bp; /* Boundary being considered */ @@ -682,7 +669,6 @@ extAddCouple(bp, ecs) PlaneMask pMask; Boundary bpCopy; Rect r, ovr; - CellDef *def = ecs->def; extSidewallStruct esws; int distFringe; @@ -692,11 +678,13 @@ extAddCouple(bp, ecs) if (DBIsContact(tout)) tout = DBPlaneToResidue(tout, ecs->plane); - extCoupleList = ExtCurStyle->exts_sideCoupleCap[tin][tout]; - extOverlapList = ExtCurStyle->exts_sideOverlapCap[tin][tout]; - if (extCoupleList == NULL && extOverlapList == NULL) + esws.extCoupleList = ExtCurStyle->exts_sideCoupleCap[tin][tout]; + esws.extOverlapList = ExtCurStyle->exts_sideOverlapCap[tin][tout]; + if ((esws.extCoupleList == NULL) && (esws.extOverlapList == NULL)) return (0); + esws.def = ecs->def; + /* * Clip the edge of interest to the area where we're searching * for coupling capacitance, if such an area has been specified. @@ -719,138 +707,169 @@ extAddCouple(bp, ecs) /* fringe cap is (unrealistically) assumed to couple only */ /* to shapes that are directly below the edge. */ + esws.fringe_halo = (ExtOptions & EXT_DOFRINGEHALO) ? + ((ExtCurStyle->exts_sideCoupleHalo == 0) ? FALSE : TRUE) + : FALSE; + distFringe = (ExtOptions & EXT_DOFRINGEHALO) ? - ExtCurStyle->exts_fringeShieldHalo : 1; + ExtCurStyle->exts_sideCoupleHalo : 1; if (distFringe == 0) distFringe = 1; + esws.bp = bp; + esws.plane_of_boundary = ecs->plane; + esws.area = &ovr; + switch (bp->b_direction) { case BD_LEFT: /* Along left */ r.r_xbot -= ExtCurStyle->exts_sideCoupleHalo; ovr.r_xbot -= distFringe; - if (extCoupleList) - extWalkLeft(&r, + extWalkLeft(&r, &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout], - extSideLeft, bp, (ClientData)NULL); + extSideLeft, bp, (ClientData)&esws); break; case BD_RIGHT: /* Along right */ r.r_xtop += ExtCurStyle->exts_sideCoupleHalo; ovr.r_xtop += distFringe; - if (extCoupleList) - extWalkRight(&r, + extWalkRight(&r, &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout], - extSideRight, bp, (ClientData)NULL); + extSideRight, bp, (ClientData)&esws); break; case BD_TOP: /* Along top */ r.r_ytop += ExtCurStyle->exts_sideCoupleHalo; ovr.r_ytop += distFringe; - if (extCoupleList) - extWalkTop(&r, + extWalkTop(&r, &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout], - extSideTop, bp, (ClientData)NULL); + extSideTop, bp, (ClientData)&esws); break; case BD_BOTTOM: /* Along bottom */ r.r_ybot -= ExtCurStyle->exts_sideCoupleHalo; ovr.r_ybot -= distFringe; - if (extCoupleList) - extWalkBottom(&r, + extWalkBottom(&r, &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout], - extSideBottom, bp, (ClientData)NULL); + extSideBottom, bp, (ClientData)&esws); + break; + } + return (0); +} + +/* + * ---------------------------------------------------------------------------- + * + * extRemoveSubcap -- + * + * A nearby shape blocks parasitic fringe capacitance from a layer boundary + * to substrate, and so all parasitic fringe capacitance from the layer's + * region to substrate that is blocked must be removed from the total + * substrate capacitance for that region. + * + * ---------------------------------------------------------------------------- + */ + +void +extRemoveSubcap(bp, clip, esws) + Boundary *bp; /* Boundary with fringe capacitance */ + Rect *clip; /* Area not being blocked */ + extSidewallStruct *esws; /* Overlapping edge and plane information */ +{ + int dnear, length; + double snear, cfrac; + NodeRegion *rbp; + TileType ta, tb; + float mult; + CapValue subcap; + + if (!esws->fringe_halo) return; + + ta = TiGetType(bp->b_inside); + tb = TiGetType(bp->b_outside); + rbp = (NodeRegion *)extGetRegion(bp->b_inside); + + if (bp->b_segment.r_xtop == bp->b_segment.r_xbot) + length = bp->b_segment.r_ytop - bp->b_segment.r_ybot; + else + length = bp->b_segment.r_xtop - bp->b_segment.r_xbot; + + switch (bp->b_direction) + { + case BD_LEFT: /* Tile tp is to the left of the boundary */ + dnear = bp->b_segment.r_xbot - clip->r_xbot; + break; + case BD_RIGHT: /* Tile tp is to the right of the boundary */ + dnear = clip->r_xtop - bp->b_segment.r_xtop; + break; + case BD_BOTTOM: /* Tile tp is below the boundary */ + dnear = bp->b_segment.r_ybot - clip->r_ybot; + break; + case BD_TOP: /* Tile tp is above the boundary */ + dnear = clip->r_ytop - bp->b_segment.r_ytop; break; } - /* Additional calculations for the significant shielding effect of */ - /* nearby shapes on fringe capacitance. */ + if (dnear < 0) dnear = 0; /* Don't count underlap */ + mult = ExtCurStyle->exts_overlapMult[ta][0]; + snear = 0.6366 * atan(mult * dnear); - if (extCoupleList && extOverlapList && (ExtCurStyle->exts_fringeShieldHalo > 0) - && (ExtOptions & EXT_DOCOUPLING)) - { - float shieldFrac; - NodeRegion *rbp; + /* "snear" is the fractional portion of the fringe cap seen by */ + /* the substrate, so (1.0 - snear) is the part that is blocked. */ - shieldFrac = 0.0; + subcap = ExtCurStyle->exts_perimCap[ta][tb] * (1.0 - snear) * length; + rbp->nreg_cap -= subcap; +} - /* Resize r for fringe shield calculation */ - /* and find fringe shielding amount */ +/* + * ---------------------------------------------------------------------------- + * + * extFindOverlap -- + * + * Callback function for extWalkTop/Bottom/Right/Left to find the + * side overlap (fringe) capacitance from a material edge (held in + * esws->bp) and all layers in planes below to which its fringe + * capacitance may couple. The area to search will have been reduced + * by any nearby layers on the same plane that shield the fringe + * capacitance. + * + * Results: + * Returns 0 to keep extWalk*() going. + * + * Side effects: + * See side effects of the called function extSideOverlap() + * + * ---------------------------------------------------------------------------- + */ - switch (bp->b_direction) + +int +extFindOverlap(tp, area, esws) + Tile *tp; /* Overlapped tile */ + Rect *area; /* Area to check for coupling */ + extSidewallStruct *esws; /* Overlapping edge and plane information */ +{ + PlaneMask pMask; + int pNum; + Rect *rsave; + Boundary *bp = esws->bp; + TileType tin = TiGetType(bp->b_inside); + TileType tout = TiGetType(bp->b_outside); + + pMask = ExtCurStyle->exts_sideOverlapOtherPlanes[tin][tout]; + extOverlapDef = esws->def; + + /* Replace esws->area with area */ + rsave = esws->area; + esws->area = area; + + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + if (PlaneMaskHasPlane(pMask, pNum)) { - case BD_LEFT: /* Along left */ - r.r_xbot += ExtCurStyle->exts_sideCoupleHalo ; - r.r_xbot -= ExtCurStyle->exts_fringeShieldHalo ; - extWalkLeft(&r, - &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout], - extShieldLeft, bp, (ClientData) &shieldFrac); - break; - case BD_RIGHT: /* Along right */ - r.r_xtop -= ExtCurStyle->exts_sideCoupleHalo ; - r.r_xtop += ExtCurStyle->exts_fringeShieldHalo ; - extWalkRight(&r, - &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout], - extShieldRight, bp, (ClientData) &shieldFrac); - break; - case BD_TOP: /* Along top */ - r.r_ytop -= ExtCurStyle->exts_sideCoupleHalo ; - r.r_ytop += ExtCurStyle->exts_fringeShieldHalo ; - extWalkTop(&r, - &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout], - extShieldTop, bp, (ClientData) &shieldFrac); - break; - case BD_BOTTOM: /* Along bottom */ - r.r_ybot += ExtCurStyle->exts_sideCoupleHalo ; - r.r_ybot -= ExtCurStyle->exts_fringeShieldHalo ; - extWalkBottom(&r, - &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout], - extShieldBottom, bp, (ClientData) &shieldFrac); - break; + esws->plane_checked = pNum; + (void) DBSrPaintArea((Tile *) NULL, esws->def->cd_planes[pNum], + area, &ExtCurStyle->exts_sideOverlapOtherTypes[tin][tout], + extSideOverlap, (ClientData)esws); } - - esws.shieldfrac = shieldFrac; - - /* Remove the part of the capacitance to substrate that came from - * the sidewall overlap and that was shielded by the nearby shape. - */ - if (esws.shieldfrac > 0.0) - { - int length; - CapValue subcap; - - if (bp->b_segment.r_xtop == bp->b_segment.r_xbot) - length = bp->b_segment.r_ytop - bp->b_segment.r_ybot; - else - length = bp->b_segment.r_xtop - bp->b_segment.r_xbot; - - subcap = ExtCurStyle->exts_perimCap[tin][tout] * length * esws.shieldfrac; - - rbp = (NodeRegion *) extGetRegion(bp->b_inside); - rbp->nreg_cap -= subcap; - } - } - else - esws.shieldfrac = 0.0; - - if (extOverlapList) - { - pMask = ExtCurStyle->exts_sideOverlapOtherPlanes[tin][tout]; - extSideOverlapSearchArea = ovr; - extOverlapDef = def; - - esws.bp = bp; - esws.plane_of_boundary = ecs->plane; - esws.fringe_halo = distFringe; - - for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) - if (PlaneMaskHasPlane(pMask, pNum)) - { - esws.plane_checked = pNum; - (void) DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum], - &ovr, &ExtCurStyle->exts_sideOverlapOtherTypes[tin][tout], - extSideOverlap, (ClientData) &esws); - } - } - - return (0); + esws->area = rsave; + return 0; } /* @@ -886,7 +905,7 @@ extSideOverlap(tp, esws) HashEntry *he; EdgeCap *e; int length, areaAccountedFor, areaTotal; - double cfrac, afrac; + double cfrac, sfrac, afrac, mult; CapValue cap; CoupleKey ck; @@ -907,12 +926,10 @@ extSideOverlap(tp, esws) } TITORECT(tp, &ov.o_clip); - GEOCLIP(&ov.o_clip, &extSideOverlapSearchArea); - areaTotal = length * esws->fringe_halo; + GEOCLIP(&ov.o_clip, esws->area); + areaTotal = GEO_WIDTH(&ov.o_clip) * GEO_HEIGHT(&ov.o_clip); areaAccountedFor = 0; - ASSERT(areaTotal == GEO_WIDTH(&ov.o_clip) * GEO_HEIGHT(&ov.o_clip), - "extSideOverlap"); ta = TiGetType(bp->b_inside); /* Revert any contacts to their residues */ @@ -923,50 +940,58 @@ extSideOverlap(tp, esws) /* 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 > 1) + if (esws->fringe_halo) { int dfar, dnear; - double ffar, fnear; 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 - LEFT(tp); - dnear = bp->b_segment.r_ll.p_x - RIGHT(tp); + 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 = RIGHT(tp) - bp->b_segment.r_ur.p_x; - dnear = LEFT(tp) - bp->b_segment.r_ur.p_x; + 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 - BOTTOM(tp); - dnear = bp->b_segment.r_ll.p_y - TOP(tp); + 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 = TOP(tp) - bp->b_segment.r_ur.p_y; - dnear = BOTTOM(tp) - bp->b_segment.r_ur.p_y; + 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; /* Do not count underlap */ - if (dfar > esws->fringe_halo) dfar = esws->fringe_halo; - ffar = (double)dfar / (double)esws->fringe_halo; - fnear = (double)dnear / (double)esws->fringe_halo; - sfar = sin(1.5708 * ffar); - snear = sin(1.5708 * fnear); + 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 = extOverlapList; e; e = e->ec_next) + 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; @@ -1008,14 +1033,14 @@ extSideOverlap(tp, esws) } if (rtp != rbp) { - if (esws->fringe_halo == 1) + if (!esws->fringe_halo) { - cap += e->ec_cap * ov.o_area * (1.0 - esws->shieldfrac); + 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 * (1.0 - esws->shieldfrac); + cap += e->ec_cap * length * afrac * cfrac; } } areaAccountedFor += ov.o_area; @@ -1045,14 +1070,12 @@ extSideOverlap(tp, esws) outtype = DBPlaneToResidue(outtype, esws->plane_of_boundary); afrac = (double)areaAccountedFor / (double)areaTotal; - if (esws->fringe_halo == 1) + if (!esws->fringe_halo) subcap = (ExtCurStyle->exts_perimCap[ta][outtype] * - (1.0 - esws->shieldfrac) * MIN(areaAccountedFor, length)); else /* Fringe capacitance distributed over halo */ subcap = (ExtCurStyle->exts_perimCap[ta][outtype] * - (1.0 - esws->shieldfrac) * cfrac * length * - MIN(afrac, 1.0)); + 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. */ @@ -1148,8 +1171,15 @@ extWalkTop(area, mask, func, bp, clientData) if (lookRight) bloc.b_segment.r_xtop = RIGHT(tp); + /* Call sidewall coupling calculation function */ if (func(tp, &bloc, clientData) != 0) return 1; + /* Clip coupling area and call fringe coupling calculation function */ + aloc = *area; + aloc.r_ytop = BOTTOM(tp); + if (extFindOverlap(bp->b_outside, &aloc, clientData) != 0) return 1; + extRemoveSubcap(bp, &aloc, clientData); + /* Recurse on tile left side */ if (lookLeft) { @@ -1176,13 +1206,18 @@ extWalkTop(area, mask, func, bp, clientData) /* coupling to tiles behind it, so return. */ return 0; } + /* Continue to walk left until out of bounds */ tp = BL(tp); } /* Continue to walk up from right edge */ tile = RT(tile); } - return 0; + + /* Any length which does not couple to anything in the */ + /* same plane is still checked for coupling to anything */ + /* below it. */ + return extFindOverlap(bp->b_outside, area, clientData); } /* @@ -1246,8 +1281,15 @@ extWalkBottom(area, mask, func, bp, clientData) if (lookRight) bloc.b_segment.r_xtop = RIGHT(tp); + /* Call sidewall coupling calculation function */ if (func(tp, &bloc, clientData) != 0) return 1; + /* Clip coupling area and call fringe coupling calculation function */ + aloc = *area; + aloc.r_ybot = TOP(tp); + if (extFindOverlap(bp->b_outside, &aloc, clientData) != 0) return 1; + extRemoveSubcap(bp, &aloc, clientData); + /* Recurse on tile left side */ if (lookLeft) { @@ -1274,13 +1316,18 @@ extWalkBottom(area, mask, func, bp, clientData) /* coupling to tiles behind it, so return. */ return 0; } + /* Continue to walk right until out of bounds */ tp = TR(tp); } /* Continue to walk down from left edge */ tile = LB(tile); } - return 0; + + /* Any length which does not couple to anything in the */ + /* same plane is still checked for coupling to anything */ + /* below it. */ + return extFindOverlap(bp->b_outside, area, clientData); } /* @@ -1344,8 +1391,15 @@ extWalkRight(area, mask, func, bp, clientData) if (lookUp) bloc.b_segment.r_ytop = TOP(tp); + /* Call sidewall coupling calculation function */ if (func(tp, &bloc, clientData) != 0) return 1; + /* Clip coupling area and call fringe coupling calculation function */ + aloc = *area; + aloc.r_xtop = LEFT(tp); + if (extFindOverlap(bp->b_outside, &aloc, clientData) != 0) return 1; + extRemoveSubcap(bp, &aloc, clientData); + /* Recurse on tile bottom side */ if (lookDown) { @@ -1372,13 +1426,18 @@ extWalkRight(area, mask, func, bp, clientData) /* coupling to tiles behind it, so return. */ return 0; } + /* Continue to walk down until out of bounds */ tp = LB(tp); } /* Continue to walk right from top edge */ tile = TR(tile); } - return 0; + + /* Any length which does not couple to anything in the */ + /* same plane is still checked for coupling to anything */ + /* below it. */ + return extFindOverlap(bp->b_outside, area, clientData); } /* @@ -1442,8 +1501,15 @@ extWalkLeft(area, mask, func, bp, clientData) if (lookUp) bloc.b_segment.r_ytop = TOP(tp); + /* Call sidewall coupling calculation function */ if (func(tp, &bloc, clientData) != 0) return 1; + /* Clip coupling area and call fringe coupling calculation function */ + aloc = *area; + aloc.r_xbot = RIGHT(tp); + if (extFindOverlap(bp->b_outside, &aloc, clientData) != 0) return 1; + extRemoveSubcap(bp, &aloc, clientData); + /* Recurse on tile bottom side */ if (lookDown) { @@ -1470,13 +1536,18 @@ extWalkLeft(area, mask, func, bp, clientData) /* coupling to tiles behind it, so return. */ return 0; } + /* Continue to walk up until out of bounds */ tp = RT(tp); } /* Continue to walk left from top edge */ tile = BL(tile); } - return 0; + + /* Any length which does not couple to anything in the */ + /* same plane is still checked for coupling to anything */ + /* below it. */ + return extFindOverlap(bp->b_outside, area, clientData); } /* @@ -1507,10 +1578,10 @@ extWalkLeft(area, mask, func, bp, clientData) */ int -extSideLeft(tpfar, bp, clientData) +extSideLeft(tpfar, bp, esws) Tile *tpfar; Boundary *bp; - ClientData clientData; /* Unused */ + extSidewallStruct *esws; { NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar); @@ -1526,7 +1597,8 @@ extSideLeft(tpfar, bp, clientData) { int overlap = MIN(TOP(tpnear), start) - MAX(BOTTOM(tpnear), limit); if (overlap > 0) - extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep); + extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep, + esws->extCoupleList); } } @@ -1556,10 +1628,10 @@ extSideLeft(tpfar, bp, clientData) */ int -extSideRight(tpfar, bp, clientData) +extSideRight(tpfar, bp, esws) Tile *tpfar; Boundary *bp; - ClientData clientData; /* Unused */ + extSidewallStruct *esws; { NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar); @@ -1575,7 +1647,8 @@ extSideRight(tpfar, bp, clientData) { int overlap = MIN(TOP(tpnear), limit) - MAX(BOTTOM(tpnear), start); if (overlap > 0) - extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep); + extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep, + esws->extCoupleList); } } @@ -1605,10 +1678,10 @@ extSideRight(tpfar, bp, clientData) */ int -extSideTop(tpfar, bp, clientData) +extSideTop(tpfar, bp, esws) Tile *tpfar; Boundary *bp; - ClientData clientData; /* Unused */ + extSidewallStruct *esws; { NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar); @@ -1624,7 +1697,8 @@ extSideTop(tpfar, bp, clientData) { int overlap = MIN(RIGHT(tpnear), limit) - MAX(LEFT(tpnear), start); if (overlap > 0) - extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep); + extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep, + esws->extCoupleList); } } @@ -1654,10 +1728,10 @@ extSideTop(tpfar, bp, clientData) */ int -extSideBottom(tpfar, bp, clientData) +extSideBottom(tpfar, bp, esws) Tile *tpfar; Boundary *bp; - ClientData clientData; /* Unused */ + extSidewallStruct *esws; { NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar); @@ -1673,7 +1747,8 @@ extSideBottom(tpfar, bp, clientData) { int overlap = MIN(RIGHT(tpnear), start) - MAX(LEFT(tpnear), limit); if (overlap > 0) - extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep); + extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep, + esws->extCoupleList); } } @@ -1704,12 +1779,13 @@ extSideBottom(tpfar, bp, clientData) */ void -extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep) +extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep, extCoupleList) NodeRegion *rinside, *rfar; /* Both must be valid */ Tile *tpnear, *tpfar; /* Tiles on near and far side of edge */ int overlap, sep; /* Overlap of this edge with original one, * and distance between the two. */ + EdgeCap *extCoupleList; /* List of sidewall capacitance rules */ { TileType near = TiGetType(tpnear), far = TiGetType(tpfar); HashEntry *he; @@ -1733,295 +1809,3 @@ extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep) extSetCapValue(he, cap); } -/* - * ---------------------------------------------------------------------------- - * - * extShieldLeft -- - * - * Searching to the left of the boundary 'bp', we found the tile - * 'tpfar' which may lie on the far side of an edge to which the - * edge bp->b_inside | bp->b_outside shields the fringing capacitance. - * - * Walk along the right-hand side of 'tpfar' searching for such edges, - * and recording the amount of shielding in the passed structure. - * - * Results: - * Returns 0 always. - * - * Side effects: - * Updates data pointed to by shieldFrac - * - * ---------------------------------------------------------------------------- - */ - -int -extShieldLeft(tpfar, bp, shieldFrac) - Tile *tpfar; - Boundary *bp; - float *shieldFrac; -{ - NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); - Tile *tpnear; - float fshield; /* fraction shielded for this segment */ - float frac; /* ratio of segment to boundary length */ - - int sep = bp->b_segment.r_xbot - RIGHT(tpfar); - int limit = MAX(bp->b_segment.r_ybot, BOTTOM(tpfar)); - int start = MIN(bp->b_segment.r_ytop, TOP(tpfar)); - float halo = (float)ExtCurStyle->exts_fringeShieldHalo; - float fsep = (float)sep; - - for (tpnear = TR(tpfar); TOP(tpnear) > limit; tpnear = LB(tpnear)) - { - int overlap = MIN(TOP(tpnear), start) - MAX(BOTTOM(tpnear), limit); - if (overlap > 0) - { - Tile *tptest = tpnear; - Point p; - NodeRegion *rnear; - - /* Walk back from edge to original boundary, checking */ - /* that no shapes are shielding the shield. . . */ - - p.p_y = (start + limit) / 2; - p.p_x = RIGHT(tpnear) + 1; - while (p.p_x < bp->b_segment.r_xbot) - { - GOTOPOINT(tptest, &p); - rnear = (NodeRegion *)extGetRegion(tptest); - if ((rnear != (NodeRegion *)extUnInit) && (rnear != rinside)) - break; - p.p_x = RIGHT(tptest) + 1; - } - if (p.p_x > bp->b_segment.r_xbot) - { - frac = (float)(start - limit) / - (float)(bp->b_segment.r_ytop - bp->b_segment.r_ybot); - /* Use sin() approximation for shielding effect */ - fshield = 1.0 - sin(1.571 * fsep / halo); - *shieldFrac = fshield * frac + (*shieldFrac) * (1.0 - frac); - } - } - } - return (0); -} - -/* - * ---------------------------------------------------------------------------- - * - * extShieldRight -- - * - * Searching to the right of the boundary 'bp', we found the tile - * 'tpfar' which may lie on the far side of an edge to which the - * edge bp->b_inside | bp->b_outside shields the fringing capacitance. - * - * Walk along the left-hand side of 'tpfar' searching for such edges, - * and recording the amount of shielding in the passed structure. - * - * Results: - * Returns 0 always. - * - * Side effects: - * Updates data pointed to by shieldFrac - * - * ---------------------------------------------------------------------------- - */ - -int -extShieldRight(tpfar, bp, shieldFrac) - Tile *tpfar; - Boundary *bp; - float *shieldFrac; -{ - NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); - Tile *tpnear; - float fshield; /* fraction shielded for this segment */ - float frac; /* ratio of segment to boundary length */ - - int sep = LEFT(tpfar) - bp->b_segment.r_xtop; - int limit = MIN(bp->b_segment.r_ytop, TOP(tpfar)); - int start = MAX(bp->b_segment.r_ybot, BOTTOM(tpfar)); - float halo = (float)ExtCurStyle->exts_fringeShieldHalo; - float fsep = (float)sep; - - for (tpnear = BL(tpfar); BOTTOM(tpnear) < limit; tpnear = RT(tpnear)) - { - int overlap = MIN(TOP(tpnear), limit) - MAX(BOTTOM(tpnear), start); - if (overlap > 0) - { - Tile *tptest = tpnear; - Point p; - NodeRegion *rnear; - - /* Walk back from edge to original boundary, checking */ - /* that no shapes are shielding the shield. . . */ - - p.p_y = (start + limit) / 2; - p.p_x = LEFT(tpnear) - 1; - while (p.p_x > bp->b_segment.r_xtop) - { - GOTOPOINT(tptest, &p); - rnear = (NodeRegion *)extGetRegion(tptest); - if ((rnear != (NodeRegion *)extUnInit) && (rnear != rinside)) - break; - p.p_x = LEFT(tptest) - 1; - } - if (p.p_x < bp->b_segment.r_xtop) - { - frac = (float)(limit - start) / - (float)(bp->b_segment.r_ytop - bp->b_segment.r_ybot); - /* Use sin() approximation for shielding effect */ - fshield = 1.0 - sin(1.571 * fsep / halo); - *shieldFrac = fshield * frac + (*shieldFrac) * (1.0 - frac); - } - } - } - return (0); -} - -/* - * ---------------------------------------------------------------------------- - * - * extShieldTop -- - * - * Searching to the top of the boundary 'bp', we found the tile - * 'tpfar' which may lie on the far side of an edge to which the - * edge bp->b_inside | bp->b_outside shields the fringing capacitance. - * - * Walk along the bottom side of 'tpfar' searching for such edges, - * and recording the amount of shielding in the passed structure. - * - * Results: - * Returns 0 always. - * - * Side effects: - * Updates data pointed to by shieldFrac - * - * ---------------------------------------------------------------------------- - */ - -int -extShieldTop(tpfar, bp, shieldFrac) - Tile *tpfar; - Boundary *bp; - float *shieldFrac; -{ - NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); - Tile *tpnear; - float fshield; /* fraction shielded for this segment */ - float frac; /* ratio of segment to boundary length */ - - int sep = BOTTOM(tpfar) - bp->b_segment.r_ytop; - int limit = MIN(bp->b_segment.r_xtop, RIGHT(tpfar)); - int start = MAX(bp->b_segment.r_xbot, LEFT(tpfar)); - float halo = (float)ExtCurStyle->exts_fringeShieldHalo; - float fsep = (float)sep; - - for (tpnear = LB(tpfar); LEFT(tpnear) < limit; tpnear = TR(tpnear)) - { - int overlap = MIN(RIGHT(tpnear), limit) - MAX(LEFT(tpnear), start); - if (overlap > 0) - { - Tile *tptest = tpnear; - Point p; - NodeRegion *rnear; - - /* Walk back from edge to original boundary, checking */ - /* that no shapes are shielding the shield. . . */ - - p.p_x = (start + limit) / 2; - p.p_y = BOTTOM(tpnear) - 1; - while (p.p_y > bp->b_segment.r_ytop) - { - GOTOPOINT(tptest, &p); - rnear = (NodeRegion *)extGetRegion(tptest); - if ((rnear != (NodeRegion *)extUnInit) && (rnear != rinside)) - break; - p.p_y = BOTTOM(tptest) - 1; - } - if (p.p_y < bp->b_segment.r_ytop) - { - frac = (float)(limit - start) / - (float)(bp->b_segment.r_xtop - bp->b_segment.r_xbot); - /* Use sin() approximation for shielding effect */ - fshield = 1.0 - sin(1.571 * fsep / halo); - *shieldFrac = fshield * frac + (*shieldFrac) * (1.0 - frac); - } - } - } - return (0); -} - -/* - * ---------------------------------------------------------------------------- - * - * extShieldBottom -- - * - * Searching to the bottom of the boundary 'bp', we found the tile - * 'tpfar' which may lie on the far side of an edge to which the - * edge bp->b_inside | bp->b_outside shields the fringing capacitance. - * - * Walk along the top side of 'tpfar' searching for such - * and recording the amount of shielding in the passed structure. - * - * Results: - * Returns 0 always. - * - * Side effects: - * Updates data pointed to by shieldFrac - * - * ---------------------------------------------------------------------------- - */ - -int -extShieldBottom(tpfar, bp, shieldFrac) - Tile *tpfar; - Boundary *bp; - float *shieldFrac; -{ - NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); - Tile *tpnear; - float fshield; /* fraction shielded for this segment */ - float frac; /* ratio of segment to boundary length */ - - int sep = bp->b_segment.r_ybot - TOP(tpfar); - int limit = MAX(bp->b_segment.r_xbot, LEFT(tpfar)); - int start = MIN(bp->b_segment.r_xtop, RIGHT(tpfar)); - float halo = (float)ExtCurStyle->exts_fringeShieldHalo; - float fsep = (float)sep; - - for (tpnear = RT(tpfar); RIGHT(tpnear) > limit; tpnear = BL(tpnear)) - { - int overlap = MIN(RIGHT(tpnear), start) - MAX(LEFT(tpnear), limit); - if (overlap > 0) - { - Tile *tptest = tpnear; - Point p; - NodeRegion *rnear; - - /* Walk back from edge to original boundary, checking */ - /* that no shapes are shielding the shield. . . */ - - p.p_x = (start + limit) / 2; - p.p_y = TOP(tpnear) + 1; - while (p.p_y < bp->b_segment.r_ybot) - { - GOTOPOINT(tptest, &p); - rnear = (NodeRegion *)extGetRegion(tptest); - if ((rnear != (NodeRegion *)extUnInit) && (rnear != rinside)) - break; - p.p_y = TOP(tptest) + 1; - } - if (p.p_y > bp->b_segment.r_ybot) - { - frac = (float)(start - limit) / - (float)(bp->b_segment.r_xtop - bp->b_segment.r_xbot); - /* Use sin() approximation for shielding effect */ - fshield = 1.0 - sin(1.571 * fsep / halo); - *shieldFrac = fshield * frac + (*shieldFrac) * (1.0 - frac); - } - } - } - return (0); -} - diff --git a/extract/ExtTech.c b/extract/ExtTech.c index 4578ee74..1f32fb3f 100644 --- a/extract/ExtTech.c +++ b/extract/ExtTech.c @@ -62,6 +62,12 @@ void extTechFinalStyle(); void ExtLoadStyle(); void ExtTechScale(int, int); +/* This is a placeholder value; it may be approximately + * constant across processes, or it may need to be set + * per process. + */ +#define FRINGE_MULT 0.02 + /* * Table used for parsing the extract section of a .tech file * Each line in the extract section is of a type determined by @@ -767,6 +773,7 @@ extTechStyleInit(style) style->exts_sideOverlapCap[r][s] = (EdgeCap *) NULL; style->exts_perimCap[r][s] = (CapValue) 0; style->exts_overlapCap[r][s] = (CapValue) 0; + style->exts_overlapMult[r][s] = (float) 0; TTMaskZero(&style->exts_overlapShieldTypes[r][s]); style->exts_overlapShieldPlanes[r][s] = 0; @@ -815,7 +822,6 @@ extTechStyleInit(style) } style->exts_sideCoupleHalo = 0; - style->exts_fringeShieldHalo = 0; style->exts_stepSize = 100; style->exts_unitsPerLambda = 100.0; style->exts_resistScale = 1000; @@ -1064,6 +1070,7 @@ ExtTechSimpleAreaCap(argc, argv) TileType s, t; TileTypeBitMask types, subtypes, shields; CapValue capVal; + float multVal; int plane1, plane2, plane3, pnum1, pnum2, pnum3; PlaneMask pshield; @@ -1096,7 +1103,11 @@ ExtTechSimpleAreaCap(argc, argv) /* Part 1: Area cap */ for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) if (TTMaskHasType(&types, t)) + { ExtCurStyle->exts_areaCap[t] = capVal; + ExtCurStyle->exts_overlapMult[t][0] = (float) capVal * FRINGE_MULT; + ExtCurStyle->exts_overlapMult[0][t] = (float) capVal * FRINGE_MULT; + } if ((plane2 == -1) && (ExtCurStyle->exts_globSubstratePlane == -1)) return; else if (plane1 == plane2) return; /* shouldn't happen */ @@ -1182,6 +1193,8 @@ ExtTechSimpleAreaCap(argc, argv) continue; /* redundant overlap */ ExtCurStyle->exts_overlapCap[s][t] = capVal; + ExtCurStyle->exts_overlapMult[s][t] = (float)capVal * FRINGE_MULT; + ExtCurStyle->exts_overlapMult[t][s] = (float)capVal * FRINGE_MULT; ExtCurStyle->exts_overlapPlanes |= PlaneNumToMaskBit(plane1); if (plane2 != -1) ExtCurStyle->exts_overlapOtherPlanes[s] |= PlaneNumToMaskBit(plane2); @@ -1561,6 +1574,8 @@ ExtTechSimpleOverlapCap(argv) continue; /* redundant overlap */ ExtCurStyle->exts_overlapCap[s][t] = capVal; + ExtCurStyle->exts_overlapMult[s][t] = (float)capVal * FRINGE_MULT; + ExtCurStyle->exts_overlapMult[t][s] = (float)capVal * FRINGE_MULT; ExtCurStyle->exts_overlapPlanes |= PlaneNumToMaskBit(plane1); ExtCurStyle->exts_overlapOtherPlanes[s] |= PlaneNumToMaskBit(plane2); TTMaskSetType(&ExtCurStyle->exts_overlapTypes[plane1], s); @@ -2109,7 +2124,11 @@ ExtTechLine(sectionName, argc, argv) capVal = aToCap(argv[2]); for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) if (TTMaskHasType(&types1, t)) + { ExtCurStyle->exts_areaCap[t] = capVal; + ExtCurStyle->exts_overlapMult[t][0] = (float) capVal * FRINGE_MULT; + ExtCurStyle->exts_overlapMult[0][t] = (float) capVal * FRINGE_MULT; + } break; case CONTACT: /* Contact size, border, spacing deprecated (now taken from */ @@ -2825,6 +2844,8 @@ ExtTechLine(sectionName, argc, argv) continue; } ExtCurStyle->exts_overlapCap[s][t] = capVal; + ExtCurStyle->exts_overlapMult[s][t] = (float)capVal * FRINGE_MULT; + ExtCurStyle->exts_overlapMult[t][s] = (float)capVal * FRINGE_MULT; ExtCurStyle->exts_overlapPlanes |= PlaneNumToMaskBit(p1); ExtCurStyle->exts_overlapOtherPlanes[s] |= PlaneNumToMaskBit(p2); @@ -3012,11 +3033,7 @@ ExtTechLine(sectionName, argc, argv) ExtCurStyle->exts_sideCoupleHalo = (int)dhalo; break; case FRINGESHIELDHALO: - /* Allow floating-point and increase by factor of 1000 */ - /* to accommodate "units microns". */ - sscanf(argv[1], "%lg", &dhalo); - dhalo *= (double)1000.0; - ExtCurStyle->exts_fringeShieldHalo = (int)dhalo; + /* This is deprecated. . . Ignore */ break; case PERIMC: DBTechNoisyNameMask(argv[2], &types2); @@ -3471,6 +3488,7 @@ zinit: style->exts_perimCap[r][s] *= scalefac; style->exts_overlapCap[r][s] *= sqfac; + style->exts_overlapMult[r][s] *= scalefac; for (ec = style->exts_sideOverlapCap[r][s]; ec != NULL; ec = ec->ec_next) ec->ec_cap *= scalefac; @@ -3512,8 +3530,6 @@ zinit: style->exts_sideCoupleHalo = (int)(((float)style->exts_sideCoupleHalo / dscale) + 0.5); - style->exts_fringeShieldHalo = (int)(((float)style->exts_fringeShieldHalo - / dscale) + 0.5); style->exts_stepSize = (int)(((float)style->exts_stepSize / dscale) + 0.5); } @@ -3530,7 +3546,6 @@ zinit: /* needed, so normalize it back to lambda units. */ style->exts_sideCoupleHalo /= 1000; - style->exts_fringeShieldHalo /= 1000; } /* @@ -3559,7 +3574,6 @@ ExtTechScale(scalen, scaled) style->exts_unitsPerLambda = style->exts_unitsPerLambda * (float)scalen / (float)scaled; DBScaleValue(&style->exts_sideCoupleHalo, scaled, scalen); - DBScaleValue(&style->exts_fringeShieldHalo, scaled, scalen); DBScaleValue(&style->exts_stepSize, scaled, scalen); for (i = 0; i < DBNumTypes; i++) @@ -3591,6 +3605,8 @@ ExtTechScale(scalen, scaled) style->exts_perimCap[i][j] /= scaled; style->exts_overlapCap[i][j] *= sqn; style->exts_overlapCap[i][j] /= sqd; /* Typo fixed in 7.2.57 */ + style->exts_overlapMult[i][j] *= scalen; + style->exts_overlapMult[i][j] /= scaled; // Do not scale sidewall cap, for while the value is // per distance, the distance is referred to a separation diff --git a/extract/extractInt.h b/extract/extractInt.h index 32f0839b..b5f54f1b 100644 --- a/extract/extractInt.h +++ b/extract/extractInt.h @@ -726,6 +726,15 @@ typedef struct extstyle */ CapValue exts_overlapCap[NT][NT]; + /* + * exts_overlapMult is needed for modeling fringe shielding and + * partial fringing, whose models have multiplier coefficients + * that are proportional to area capacitance referred to some + * constant length (so that it scales with the internal grid, + * not with the internal grid squared). + */ + float exts_overlapMult[NT][NT]; + /* Specifies an ordering of the planes, so we can determine which * tile is above another one. This is used only when determining * if we should subtract capacitance to substrate for overlap and @@ -780,19 +789,13 @@ typedef struct extstyle * This value determines how much extra gets yanked when * computing hierarchical adjustments, so should be kept * small to insure reasonable performance. + * + * To be done: Set this as a per-plane value with a + * corresponding method in the tech file to declare the value + * for each plane separately. */ int exts_sideCoupleHalo; - /* - * Search out a distance exts_fringeShieldHalo from each edge - * for types on the same plane that partially shield fringe - * capacitance. The shielding is modeled as an ellipse equation - * and the shield halo should be approximately 10x the distance - * where half the fringe capacitance is shielded. If not specified, - * then it is set to be equal to exts_sideCoupleHalo. - */ - int exts_fringeShieldHalo; - /* * Sidewall-overlap coupling capacitance. * This is between an edge on one plane and a type on another plane