magic/extract/ExtCouple.c

3104 lines
91 KiB
C

/*
* ExtCouple.c --
*
* Circuit extraction.
* Extraction of coupling capacitance.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/extract/ExtCouple.c,v 1.2 2010/06/24 12:37:17 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <math.h> /* For atan() */
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "textio/textio.h"
/* --------------------- Data local to this file ---------------------- */
/* Pointer to hash table currently being updated with coupling capacitance */
HashTable *extCoupleHashPtr;
/* Clipping area for coupling searches */
Rect *extCoupleSearchArea;
/* Def being processed */
CellDef *extOverlapDef;
/* Forward procedure declarations */
int extBasicOverlap(), extBasicCouple();
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 */
/* routines to include the current cell definition and the current */
/* plane being searched. */
typedef struct _ecs {
CellDef *def;
int plane;
} extCapStruct;
/* Structure to pass on two planes to check for coupling and the tile */
/* which is doing the coupling. */
typedef struct _ecpls {
Tile *tile;
TileType dinfo;
int plane_of_tile;
int plane_checked;
} extCoupleStruct;
/* Structure to pass on two planes to check for coupling and the */
/* boundary which initiated the check. */
typedef struct _esws {
Boundary *bp;
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;
/* 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
void extNregAdjustCap(nr, c, str)
NodeRegion *nr;
CapValue c;
char *str;
{
char *name;
name = extNodeName((LabRegion *) nr);
fprintf(stderr, "CapDebug: %s += %f (%s)\n", name, c, str);
}
void extAdjustCouple(he, c, str)
HashEntry *he;
CapValue c;
char *str;
{
char *name1;
char *name2;
CoupleKey *ck;
ck = (CoupleKey *) he->h_key.h_words;
name1 = extNodeName((LabRegion *) ck->ck_1);
name2 = extNodeName((LabRegion *) ck->ck_2);
fprintf(stderr, "CapDebug: %s-%s += %f (%s)\n", name1, name2, c, str);
}
/*
* ----------------------------------------------------------------------------
*
* extFindCoupling --
*
* Find the coupling capacitances in the cell def. Such capacitances
* arise from three causes:
*
* Overlap. When two tiles on different planes overlap, they
* may have a coupling capacitance proportional to
* their areas. If this is so, we subtract the substrate
* capacitance of the overlapped type, and add the overlap
* capacitance to the coupling hash table.
*
* Sidewall. When tiles on the same plane are adjacent, they may
* have a coupling capacitance proportional to the
* length of their edges, divided by the distance between
* them. In this case, we just add the sidewall coupling
* capacitance to the hash table.
*
* Sidewall
* overlap. When the edge of a tile on one plane overlaps a tile
* on a different plane, the two tiles may have a coupling
* capacitance proportional to the length of the overlapping
* edge. In this case we add the coupling capacitance to the
* hash table. (We may want to deduct the perimeter capacitance
* to substrate?).
*
* 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.
*
* If 'clipArea' is non-NULL, search for overlap capacitance only inside
* the area *clipArea. Search for sidewall capacitance only from tiles
* inside *clipArea, although this capacitance may be to tiles outside
* *clipArea.
*
* Results:
* None.
*
* Side effects:
* When done, the HashTable 'table' will have been filled
* in with an entry for each pair of nodes having coupling
* capacitance. Each entry will have a two-word key organized
* as an CoupleKey struct, with ck_1 and ck_2 pointing to the
* coupled nodes. The value of the hash entry will be the
* coupling capacitance between that pair of nodes.
*
* ----------------------------------------------------------------------------
*/
void
extFindCoupling(def, table, clipArea)
CellDef *def;
HashTable *table;
Rect *clipArea;
{
const Rect *searchArea;
int pNum;
extCapStruct ecs;
ecs.def = def;
extCoupleHashPtr = table;
extCoupleSearchArea = clipArea;
searchArea = clipArea ? clipArea : &TiPlaneRect;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
ecs.plane = pNum;
if (PlaneMaskHasPlane(ExtCurStyle->exts_overlapPlanes, pNum))
(void) DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
searchArea, &ExtCurStyle->exts_overlapTypes[pNum],
extBasicOverlap, (ClientData) &ecs);
if (PlaneMaskHasPlane(ExtCurStyle->exts_sidePlanes, pNum))
(void) DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
searchArea, &ExtCurStyle->exts_sideTypes[pNum],
extBasicCouple, (ClientData) &ecs);
}
}
/*
* ----------------------------------------------------------------------------
*
* extRelocateSubstrateCoupling ---
*
* Move coupling capacitance to the substrate node from the coupling
* cap table onto the source node's cap-to-substrate record.
*
* ----------------------------------------------------------------------------
*/
void
extRelocateSubstrateCoupling(table, subsnode)
HashTable *table; /* Coupling capacitance hash table */
NodeRegion *subsnode; /* Node record for substrate */
{
HashEntry *he;
CoupleKey *ck;
HashSearch hs;
CapValue cap;
NodeRegion *rtp;
NodeRegion *rbp;
HashStartSearch(&hs);
while ((he = HashNext(table, &hs)))
{
cap = extGetCapValue(he);
if (cap == 0) continue;
ck = (CoupleKey *) he->h_key.h_words;
rtp = (NodeRegion *) ck->ck_1;
rbp = (NodeRegion *) ck->ck_2;
if (rtp == subsnode)
{
rbp->nreg_cap += cap;
extSetCapValue(he, (CapValue)0);
}
else if (rbp == subsnode)
{
rtp->nreg_cap += cap;
extSetCapValue(he, (CapValue)0);
}
}
}
/*
* ----------------------------------------------------------------------------
*
* extOutputCoupling --
*
* Output the coupling capacitance table built up by extFindCoupling().
* Each entry in the hash table is a capacitance between the pair of
* nodes identified by he->h_key, an CoupleKey struct.
*
* ExtFindRegions and ExtLabelRegions should have been called prior
* to this procedure.
*
* Results:
* None.
*
* Side effects:
* See the comments above.
*
* ----------------------------------------------------------------------------
*/
void
extOutputCoupling(table, outFile)
HashTable *table; /* Coupling capacitance hash table */
FILE *outFile; /* Output file */
{
HashEntry *he;
CoupleKey *ck;
HashSearch hs;
char *text;
CapValue cap; /* value of capacitance. */
HashStartSearch(&hs);
while ((he = HashNext(table, &hs)))
{
cap = extGetCapValue(he) / ExtCurStyle->exts_capScale;
if (cap == 0)
continue;
ck = (CoupleKey *) he->h_key.h_words;
text = extNodeName((LabRegion *) ck->ck_1);
fprintf(outFile, "cap \"%s\" ", text);
text = extNodeName((LabRegion *) ck->ck_2);
fprintf(outFile, "\"%s\" %lg\n", text, cap);
}
}
/*
* ----------------------------------------------------------------------------
*
* extBasicOverlap --
*
* Filter function for overlap capacitance.
* Called for each tile that might have coupling capacitance
* to another node because it overlaps a tile or tiles in that
* node. Causes an area search over the area of 'tile' in all
* planes to which 'tile' has overlap capacitance, for any tiles
* to which 'tile' has overlap capacitance.
*
* Results:
* Returns 0 to keep DBSrPaintArea() going.
*
* Side effects:
* See extAddOverlap().
*
* ----------------------------------------------------------------------------
*/
int
extBasicOverlap(tile, dinfo, ecs)
Tile *tile;
TileType dinfo;
extCapStruct *ecs;
{
int thisType;
int pNum;
PlaneMask pMask;
TileTypeBitMask *tMask;
Rect r;
CellDef *def = ecs->def;
int thisPlane = ecs->plane;
extCoupleStruct ecpls;
if (IsSplit(tile))
thisType = ((dinfo & TT_SIDE)) ? SplitRightType(tile) :
SplitLeftType(tile);
else
thisType = TiGetTypeExact(tile);
if (DBIsContact(thisType))
thisType = DBPlaneToResidue(thisType, thisPlane);
pMask = ExtCurStyle->exts_overlapOtherPlanes[thisType];
tMask = &ExtCurStyle->exts_overlapOtherTypes[thisType];
TITORECT(tile, &r);
extOverlapDef = def;
if (extCoupleSearchArea)
{
GEOCLIP(&r, extCoupleSearchArea);
}
ecpls.tile = tile;
ecpls.dinfo = dinfo;
ecpls.plane_of_tile = thisPlane;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
/* Skip if nothing interesting on the other plane */
if (pNum == thisPlane || !PlaneMaskHasPlane(pMask, pNum))
continue;
ecpls.plane_checked = pNum;
(void) DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum], &r, tMask,
extAddOverlap, (ClientData) &ecpls);
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extAddOverlap --
*
* We are called for each tile that is overlapped by the tile passed to
* extBasicOverlap() above (our argument 'tabove'). The intent is that
* 'tbelow' actually shields 'tabove' from the substrate, so we should
* replace node(tabove)'s capacitance to substrate with a capacitance
* to node(tbelow) whose size is proportional to the area of the overlap.
*
* We check to insure that tabove is not shielded from tbelow by any
* intervening material; if it is, we deduct the capacitance between
* node(tabove) and node(tbelow) for the area of the overlap.
*
* Results:
* Returns 0 to keep DBSrPaintArea() going.
*
* Side effects:
* Updates the HashEntry with key node(tbelow), node(tabove)
* by adding the capacitance of the overlap if node(tbelow)
* and node(tabove) are different, and if they are not totally
* shielded by intervening material. Also subtracts the capacitance
* to substrate from node(tabove) for the area of the overlap.
* If node(tbelow) and node(tabove) are the same, we do nothing.
*
* ----------------------------------------------------------------------------
*/
struct overlap
{
Rect o_clip;
int o_area;
PlaneMask o_pmask;
TileTypeBitMask o_tmask;
};
struct sideoverlap
{
Rect so_clip;
double so_coupfrac;
double so_subfrac;
int so_length;
extSidewallStruct *so_esws;
PlaneMask so_pmask;
TileTypeBitMask so_tmask;
TileType so_ctype;
};
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;
TileType dinfo; /* unused, but needs to be handled */
extCoupleStruct *ecpls;
{
int extSubtractOverlap(), extSubtractOverlap2();
NodeRegion *rabove, *rbelow;
HashEntry *he;
struct overlap ov;
TileType ta, tb;
CoupleKey ck;
int pNum;
CapValue c;
Tile *tabove = ecpls->tile;
/* Check if both tiles are connected. If they are, we don't need */
/* to check for shielding material, and we don't want to add any */
/* coupling capacitance between them. However, we *do* want to */
/* subtract off any substrate (area) capacitance previously added */
/* (Correction made 4/29/04 by Tim from a tip by Jeff Sondeen). */
rabove = (NodeRegion *) ExtGetRegion(tabove, ecpls->dinfo);
rbelow = (NodeRegion *) ExtGetRegion(tbelow, dinfo);
/* Quick check on validity of tile's ti_client record */
if (rbelow == (NodeRegion *)CLIENTDEFAULT) return 0;
if (rabove == (NodeRegion *)CLIENTDEFAULT) return 0;
/* Compute the area of overlap */
ov.o_clip.r_xbot = MAX(LEFT(tbelow), LEFT(tabove));
ov.o_clip.r_xtop = MIN(RIGHT(tbelow), RIGHT(tabove));
ov.o_clip.r_ybot = MAX(BOTTOM(tbelow), BOTTOM(tabove));
ov.o_clip.r_ytop = MIN(TOP(tbelow), TOP(tabove));
if (extCoupleSearchArea)
{
GEOCLIP(&ov.o_clip, extCoupleSearchArea);
}
ov.o_area = (ov.o_clip.r_ytop - ov.o_clip.r_ybot)
* (ov.o_clip.r_xtop - ov.o_clip.r_xbot);
if (IsSplit(tabove))
ta = (ecpls->dinfo & TT_SIDE) ? TiGetRightType(tabove) : TiGetLeftType(tabove);
else
ta = TiGetTypeExact(tabove);
if (IsSplit(tbelow))
tb = (dinfo & TT_SIDE) ? TiGetRightType(tbelow) : TiGetLeftType(tbelow);
else
tb = TiGetTypeExact(tbelow);
/* Revert any contacts to their residues */
if (DBIsContact(ta))
ta = DBPlaneToResidue(ta, ecpls->plane_of_tile);
if (DBIsContact(tb))
tb = DBPlaneToResidue(tb, ecpls->plane_checked);
/*
* Find whether rabove and rbelow are shielded by intervening material.
* Deduct the area shielded from the area of the overlap, so we adjust
* the overlap capacitance correspondingly.
*/
if ((ov.o_pmask = ExtCurStyle->exts_overlapShieldPlanes[ta][tb]))
{
ov.o_tmask = ExtCurStyle->exts_overlapShieldTypes[ta][tb];
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (!PlaneMaskHasPlane(ov.o_pmask, pNum)) continue;
ov.o_pmask &= ~(PlaneNumToMaskBit(pNum));
if (ov.o_pmask == 0)
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &ov.o_clip, &ov.o_tmask,
extSubtractOverlap, (ClientData) &ov);
}
else
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &ov.o_clip, &DBAllTypeBits,
extSubtractOverlap2, (ClientData) &ov);
}
break;
}
}
/* If any capacitance remains, add this record to the table */
if (ov.o_area > 0)
{
int oa = ExtCurStyle->exts_planeOrder[ecpls->plane_of_tile];
int ob = ExtCurStyle->exts_planeOrder[ecpls->plane_checked];
if (oa > ob)
{
Tile *tp;
TileType t, tres;
TileTypeBitMask *mask;
int len;
CapValue cp;
/*
* Subtract the substrate capacitance from tabove's region due to
* the area of the overlap, minus any shielded area. The shielded
* areas get handled later, when processing coupling between tabove
* and the shielding tile. (Tabove was the overlapping tile, so it
* is shielded from the substrate by tbelow if the Tabove plane is
* above the Tbelow plane).
*/
rabove->nreg_cap -= ExtCurStyle->exts_areaCap[ta] * ov.o_area;
if (CAP_DEBUG)
extNregAdjustCap(rabove,
-(ExtCurStyle->exts_areaCap[ta] * ov.o_area),
"obsolete_overlap");
} else if (CAP_DEBUG)
extNregAdjustCap(rabove, 0.0,
"obsolete_overlap (skipped, wrong direction)");
/* If the regions are the same, skip this part */
if (rabove == rbelow) return (0);
/* Find the coupling hash record */
if (rabove < rbelow) ck.ck_1 = rabove, ck.ck_2 = rbelow;
else ck.ck_1 = rbelow, ck.ck_2 = rabove;
he = HashFind(extCoupleHashPtr, (char *) &ck);
/* Add the overlap capacitance to the table */
c = extGetCapValue(he);
c += ExtCurStyle->exts_overlapCap[ta][tb] * ov.o_area;
if (CAP_DEBUG)
extAdjustCouple(he, ExtCurStyle->exts_overlapCap[ta][tb] *
ov.o_area, "overlap");
extSetCapValue(he, c);
}
return (0);
}
/* Simple overlap. The area of overlap is subtracted from ov->o_area */
int
extSubtractOverlap(tile, dinfo, ov)
Tile *tile;
TileType dinfo; /* (unused) */
struct overlap *ov;
{
Rect r;
int area;
TITORECT(tile, &r);
GEOCLIP(&r, &ov->o_clip);
area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot);
if (IsSplit(tile)) area /= 2;
if (area > 0)
ov->o_area -= area;
return (0);
}
/* Recursive shielding overlap check. If the tile shields, */
/* then the area of overlap is subtracted from ov->o_area. If */
/* not, then this routine is called recursively on the next */
/* shielding plane. */
int
extSubtractOverlap2(tile, dinfo, ov)
Tile *tile;
TileType dinfo; /* (unused) */
struct overlap *ov;
{
TileType ttype;
struct overlap ovnew;
int area, pNum;
Rect r;
TITORECT(tile, &r);
GEOCLIP(&r, &ov->o_clip);
area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot);
if (area <= 0)
return (0);
if (IsSplit(tile))
{
area /= 2;
ttype = (dinfo & TT_SIDE) ? TiGetRightType(tile) : TiGetLeftType(tile);
}
else
ttype = TiGetTypeExact(tile);
/* This tile shields everything below */
if (TTMaskHasType(&ov->o_tmask, ttype))
{
ov->o_area -= area;
return (0);
}
/* Tile doesn't shield, so search next plane */
ovnew = *ov;
ovnew.o_clip = r;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (!PlaneMaskHasPlane(ovnew.o_pmask, pNum)) continue;
ovnew.o_pmask &= ~(PlaneNumToMaskBit(pNum));
if (ovnew.o_pmask == 0)
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &ovnew.o_clip, &ovnew.o_tmask,
extSubtractOverlap, (ClientData) &ovnew);
}
else
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &ovnew.o_clip, &DBAllTypeBits,
extSubtractOverlap2, (ClientData) &ovnew);
}
break;
}
ov->o_area = ovnew.o_area;
return (0);
}
/* Side overlap shielding. The fraction of the side overlap (fringe)
* capacitance over this area is added to ov->o_frac, so that it can
* be subtracted from the total.
*/
int
extSubtractSideOverlap(tile, dinfo, sov)
Tile *tile;
TileType dinfo; /* (unused) */
struct sideoverlap *sov;
{
Rect r;
int area, dnear, dfar, length;
double mult, snear, sfar;
TileType ta, tb;
Boundary *bp = sov->so_esws->bp;
TITORECT(tile, &r);
GEOCLIP(&r, &sov->so_clip);
area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot);
if (area <= 0) return 0;
ta = TiGetType(bp->b_inside);
tb = sov->so_ctype;
if (bp->b_segment.r_xtop == bp->b_segment.r_xbot)
length = r.r_ytop - r.r_ybot;
else
length = r.r_xtop - r.r_xbot;
switch (bp->b_direction)
{
case BD_LEFT: /* Tile tp is to the left of the boundary */
dnear = bp->b_segment.r_xbot - r.r_xtop;
dfar = bp->b_segment.r_xbot - r.r_xbot;
break;
case BD_RIGHT: /* Tile tp is to the right of the boundary */
dnear = r.r_xbot - bp->b_segment.r_xtop;
dfar = r.r_xtop - bp->b_segment.r_xtop;
break;
case BD_BOTTOM: /* Tile tp is below the boundary */
dnear = bp->b_segment.r_ybot - r.r_ytop;
dfar = bp->b_segment.r_ybot - r.r_ybot;
break;
case BD_TOP: /* Tile tp is above the boundary */
dnear = r.r_ybot - bp->b_segment.r_ytop;
dfar = r.r_ytop - bp->b_segment.r_ytop;
break;
}
if (dnear < 0) dnear = 0; /* Don't count underlap */
mult = ExtCurStyle->exts_overlapMult[ta][0];
snear = 0.6366 * atan(mult * dnear);
sfar = 0.6366 * atan(mult * dfar);
/* "sfar - snear" is the fractional portion of the fringe cap */
/* seen by the substrate in the direction perpendicular to the edge */
/* generating the fringe cap. This is multiplied by the fraction */
/* of the total edge length to get the total fraction of the entire */
/* fringe capacitance being shielded. */
sov->so_subfrac += (sfar - snear) * ((double)length / (double)sov->so_length);
/* Do the same calculation but the the overlap multiplier for the */
/* coupling layer, since the fringe capacitance has a different */
/* halo than for the substrate. */
if (ExtCurStyle->exts_overlapMult[ta][tb] != mult)
{
mult = ExtCurStyle->exts_overlapMult[ta][tb];
snear = 0.6366 * atan(mult * dnear);
sfar = 0.6366 * atan(mult * dfar);
}
sov->so_coupfrac += (sfar - snear) * ((double)length / (double)sov->so_length);
return (0);
}
/* Recursive shielding side overlap check. If the tile shields */
/* then the area of overlap is subtracted from ov->o_area. If */
/* not, then this routine is called recursively on the next */
/* shielding plane. */
int
extSubtractSideOverlap2(tile, dinfo, sov)
Tile *tile;
TileType dinfo;
struct sideoverlap *sov;
{
TileType ttype;
struct sideoverlap sovnew;
int area, pNum;
Rect r;
if (IsSplit(tile))
ttype = (dinfo & TT_SIDE) ? TiGetRightType(tile) : TiGetLeftType(tile);
else
ttype = TiGetTypeExact(tile);
TITORECT(tile, &r);
GEOCLIP(&r, &sov->so_clip);
area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot);
if (area <= 0) return (0);
if (IsSplit(tile)) area /= 2;
/* This tile shields everything below */
if (TTMaskHasType(&sov->so_tmask, ttype))
{
extSubtractSideOverlap(tile, dinfo, sov);
return (0);
}
/* Tile doesn't shield, so search next plane */
sovnew = *sov;
sovnew.so_clip = r;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (!PlaneMaskHasPlane(sovnew.so_pmask, pNum)) continue;
sovnew.so_pmask &= ~(PlaneNumToMaskBit(pNum));
if (sovnew.so_pmask == 0)
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &sovnew.so_clip, &sovnew.so_tmask,
extSubtractSideOverlap, (ClientData) &sovnew);
}
else
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &sovnew.so_clip, &DBAllTypeBits,
extSubtractSideOverlap2, (ClientData) &sovnew);
}
break;
}
sov->so_subfrac = sovnew.so_subfrac;
sov->so_coupfrac = sovnew.so_coupfrac;
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extBasicCouple --
*
* Filter function for sidewall coupling capacitance.
* Called for each tile that might have coupling capacitance
* to another node because it is near tiles on the same plane,
* or because its edge overlaps tiles on a different plane.
*
* Causes an area search over a halo surrounding each edge of
* 'tile' for edges to which each edge has coupling capacitance
* on this plane, and a search for tiles on different planes that
* this edge overlaps.
*
* Results:
* Returns 0 to keep DBSrPaintArea() going.
*
* Side effects:
* See extAddCouple().
*
* ----------------------------------------------------------------------------
*/
int
extBasicCouple(tile, dinfo, ecs)
Tile *tile;
TileType dinfo;
extCapStruct *ecs;
{
TileType ttype;
if (IsSplit(tile))
ttype = (dinfo & TT_SIDE) ? TiGetRightType(tile) : TiGetLeftType(tile);
else
ttype = TiGetTypeExact(tile);
(void) extEnumTilePerim(tile, dinfo, &ExtCurStyle->exts_sideEdges[ttype],
ecs->plane, extAddCouple, (ClientData) ecs);
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extGetBoundaryTypes ---
*
* Return the tile types of the boundary inside and outside type in the
* argument pointers. The routine takes care of deciding if either side
* of the boundary is a split tile, and choosing the correct type based
* on the direction of the boundary.
*
* Result:
* None.
*
* Side effects:
* The tile types are passed by pointer reference in the arguments.
*
* ----------------------------------------------------------------------------
*/
void
extGetBoundaryTypes(Boundary *bp,
TileType *tin,
TileType *tout)
{
TileType loctin, loctout;
if (IsSplit(bp->b_inside))
{
switch (bp->b_direction)
{
case BD_LEFT:
loctin = TiGetLeftType(bp->b_inside);
break;
case BD_RIGHT:
loctin = TiGetRightType(bp->b_inside);
break;
case BD_TOP:
loctin = TiGetTopType(bp->b_inside);
break;
case BD_BOTTOM:
loctin = TiGetBottomType(bp->b_inside);
break;
}
}
else
loctin = TiGetTypeExact(bp->b_inside);
if (IsSplit(bp->b_outside))
{
switch (bp->b_direction)
{
case BD_LEFT:
loctout = TiGetRightType(bp->b_outside);
break;
case BD_RIGHT:
loctout = TiGetLeftType(bp->b_outside);
break;
case BD_TOP:
loctout = TiGetBottomType(bp->b_outside);
break;
case BD_BOTTOM:
loctout = TiGetTopType(bp->b_outside);
break;
}
}
else
loctout = TiGetTypeExact(bp->b_outside);
*tin = loctin;
*tout = loctout;
}
/*
* ----------------------------------------------------------------------------
*
* extGetBoundaryTypes2 ---
*
* Similar to extGetBoundaryTypes(), but where the tiles for which we
* want to get the tile type are not necessarily the ones in the boundary
* record; the boundary just provides the direction that determines which
* side the tile type is on, in the case of a split tile.
*
* Result:
* None.
*
* Side effects:
* The tile types are passed by pointer reference in the arguments.
*
* ----------------------------------------------------------------------------
*/
void
extGetBoundaryTypes2(int bdir,
Tile *tbin,
Tile *tbout,
TileType *tin,
TileType *tout)
{
TileType loctin, loctout;
if (IsSplit(tbin))
{
switch (bdir)
{
case BD_LEFT:
loctin = TiGetLeftType(tbin);
break;
case BD_RIGHT:
loctin = TiGetRightType(tbin);
break;
case BD_TOP:
loctin = TiGetTopType(tbin);
break;
case BD_BOTTOM:
loctin = TiGetBottomType(tbin);
break;
}
}
else
loctin = TiGetTypeExact(tbin);
if (IsSplit(tbout))
{
switch (bdir)
{
case BD_LEFT:
loctout = TiGetRightType(tbout);
break;
case BD_RIGHT:
loctout = TiGetLeftType(tbout);
break;
case BD_TOP:
loctout = TiGetBottomType(tbout);
break;
case BD_BOTTOM:
loctout = TiGetTopType(tbout);
break;
}
}
else
loctout = TiGetTypeExact(tbout);
*tin = loctin;
*tout = loctout;
}
/*
* ----------------------------------------------------------------------------
*
* extGetBoundaryRegions ---
*
* Given a boundary direction and two tiles, one on the boundary inside
* and one on the boundary outside, find the two node regions associated
* with the facing sides of the two tiles.
*
* Results:
* None.
*
* Side effects:
* The tile types are passed by pointer reference in the arguments.
*
* ----------------------------------------------------------------------------
*/
void
extGetBoundaryRegions(int bdir,
Tile *tbin,
Tile *tbout,
NodeRegion **rinptr,
NodeRegion **routptr)
{
NodeRegion *locrin, *locrout;
if (IsSplit(tbin))
{
switch (bdir)
{
case BD_LEFT:
locrin = (NodeRegion *)ExtGetRegion(tbin, (TileType)0);
break;
case BD_RIGHT:
locrin = (NodeRegion *)ExtGetRegion(tbin, (TileType)TT_SIDE);
break;
case BD_TOP:
locrin = (NodeRegion *)ExtGetRegion(tbin,
TiGetTypeExact(tbin) & TT_DIRECTION ?
(TileType)TT_SIDE : (TileType)0);
break;
case BD_BOTTOM:
locrin = (NodeRegion *)ExtGetRegion(tbin,
TiGetTypeExact(tbin) & TT_DIRECTION ?
(TileType)0 : (TileType)TT_SIDE);
break;
}
}
else
locrin = (NodeRegion *)ExtGetRegion(tbin, (TileType)0);
if (IsSplit(tbout))
{
switch (bdir)
{
case BD_LEFT:
locrout = (NodeRegion *)ExtGetRegion(tbout, (TileType)TT_SIDE);
break;
case BD_RIGHT:
locrout = (NodeRegion *)ExtGetRegion(tbout, (TileType)0);
break;
case BD_TOP:
locrout = (NodeRegion *)ExtGetRegion(tbout,
TiGetTypeExact(tbin) & TT_DIRECTION ?
(TileType)0 : (TileType)TT_SIDE);
break;
case BD_BOTTOM:
locrout = (NodeRegion *)ExtGetRegion(tbout,
TiGetTypeExact(tbin) & TT_DIRECTION ?
(TileType)TT_SIDE : (TileType)0);
break;
}
}
else
locrout = (NodeRegion *)ExtGetRegion(tbout, (TileType)0);
*rinptr = locrin;
*routptr = locrout;
}
/*
* ----------------------------------------------------------------------------
*
* extAddCouple --
*
* Called for each segment along the boundary of the tile bp->b_inside
* that might have coupling capacitance with its neighbors.
* Causes an area search over a halo surrounding the boundary bp->b_segment
* on the side outside bp->b_inside for edges to which this one has coupling
* capacitance on this plane, and for tiles overlapping this edge on different
* planes.
*
* Results:
* Returns 0 to keep DBSrPaintArea() going.
*
* Side effects:
* For each edge (tnear, tfar) we find that has coupling capacitance
* to us, update the HashEntry with key node(bp->b_inside), node(tfar)
* by adding the sidewall capacitance if node(bp->b_inside) and node(tfar)
* are different. If node(bp->b_inside) and node(tfar) are the same, we
* do nothing.
*
* For each tile tp we find on a different plane that overlaps this
* edge, update the HashEntry with key node(bp->b_inside), node(tp)
* by adding the sidewall overlap capacitance. If node(bp->b_inside)
* and node(tp) are the same, do nothing.
*
* ----------------------------------------------------------------------------
*/
int
extAddCouple(bp, ecs)
Boundary *bp; /* Boundary being considered */
extCapStruct *ecs;
{
TileType tin, tout;
int pNum;
PlaneMask pMask;
Boundary bpCopy;
Rect r, ovr;
extSidewallStruct esws;
int distFringe;
/* Non-Manhattan boundaries are not handled. This is
* future work to be done.
*/
switch (bp->b_direction)
{
case BD_NW:
case BD_NE:
case BD_SW:
case BD_SE:
return 0;
}
/* Get the types on the inside and outside of the boundary */
extGetBoundaryTypes(bp, &tin, &tout);
/* Check here for a zero exts_sideCoupleOtherEdges mask.
* that handles cases such as FET types not being declared in
* defaultperimeter, as the edge between poly and FET will be
* seen as a boundary. The lack of any area coupling should
* then prevent it from being checked for fringe cap.
*/
if (TTMaskIsZero(&ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout]))
return 0;
/* Revert any edge contacts to their residues */
if (DBIsContact(tin))
tin = DBPlaneToResidue(tin, ecs->plane);
if (DBIsContact(tout))
tout = DBPlaneToResidue(tout, ecs->plane);
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.
*/
if (extCoupleSearchArea)
{
bpCopy = *bp;
bp = &bpCopy;
if (!GEO_OVERLAP(&bp->b_segment, extCoupleSearchArea))
return 0;
GEOCLIP(&bp->b_segment, extCoupleSearchArea);
}
r = ovr = bp->b_segment;
/* If considering fringe capacitance to be distributed over */
/* a halo surrounding the edge of a shape, then set the */
/* fringe distance to the halo value. Otherwise, the */
/* 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_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;
extWalkLeft(&r,
&ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout],
extSideLeft, bp, &esws);
break;
case BD_RIGHT: /* Along right */
r.r_xtop += ExtCurStyle->exts_sideCoupleHalo;
ovr.r_xtop += distFringe;
extWalkRight(&r,
&ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout],
extSideRight, bp, &esws);
break;
case BD_TOP: /* Along top */
r.r_ytop += ExtCurStyle->exts_sideCoupleHalo;
ovr.r_ytop += distFringe;
extWalkTop(&r,
&ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout],
extSideTop, bp, &esws);
break;
case BD_BOTTOM: /* Along bottom */
r.r_ybot -= ExtCurStyle->exts_sideCoupleHalo;
ovr.r_ybot -= distFringe;
extWalkBottom(&r,
&ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout],
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;
}
/*
* ----------------------------------------------------------------------------
*
* 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;
/* Get the types on the inside and outside of the boundary */
extGetBoundaryTypes(bp, &ta, &tb);
rbp = (NodeRegion *)ExtGetRegion(bp->b_inside, (TileType)0);
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;
}
if (dnear < 0) dnear = 0; /* Don't count underlap */
mult = ExtCurStyle->exts_overlapMult[ta][0];
snear = 0.6366 * atan((double)mult * dnear);
/* "snear" is the fractional portion of the fringe cap seen by */
/* the substrate, so (1.0 - snear) is the part that is blocked. */
subcap = ExtCurStyle->exts_perimCap[ta][tb] * (1.0 - snear) * length;
rbp->nreg_cap -= subcap;
}
/*
* ----------------------------------------------------------------------------
*
* 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()
*
* ----------------------------------------------------------------------------
*/
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);
/* Get residues
* (Note: Isn't it better to include contacts in the tables?)
*/
if (DBIsContact(tin))
tin = DBPlaneToResidue(tin, esws->plane_of_boundary);
if (DBIsContact(tout))
tout = DBPlaneToResidue(tout, esws->plane_of_boundary);
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))
{
esws->plane_checked = pNum;
(void) DBSrPaintArea((Tile *) NULL, esws->def->cd_planes[pNum],
area, &ExtCurStyle->exts_sideOverlapOtherTypes[tin][tout],
(esws->fringe_halo) ? extSideOverlapHalo : extSideOverlap,
(ClientData)esws);
}
esws->area = rsave;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* extSideOverlapHalo --
*
* The boundary 'bp' has been found to overlap the tile 'tp', which it
* has coupling capacitance to.
*
* Every tile that couples to an edge is also shielding the substrate
* from that edge. To maintain the proper accounting of the amount of
* substrate shielded, calculate only for the area of the substrate that
* couples to the *unshielded* portion of the tile. The part of the
* substrate that is under a shielded portion of the tile will be handled
* later when calculating coupling to that shielding tile.
*
*
* Results:
* Returns 0 to keep DBSrPaintArea() going.
*
* Side effects:
* Update the coupling capacitance between node(bp->t_inside) and
* node(tp) if the two nodes are different. Does so by updating
* the value stored in the HashEntry keyed by the two nodes.
*
* ----------------------------------------------------------------------------
*/
int
extSideOverlapHalo(tp, dinfo, esws)
Tile *tp; /* Overlapped tile */
TileType dinfo; /* Split tile information */
extSidewallStruct *esws; /* Overlapping edge and plane information */
{
Boundary *bp = esws->bp; /* Overlapping edge */
NodeRegion *rtp = (NodeRegion *) ExtGetRegion(tp, dinfo);
NodeRegion *rbp = (NodeRegion *) ExtGetRegion(bp->b_inside, (TileType)0);
TileType ta, tb;
Rect tpr;
struct sideoverlap sov;
HashEntry *he;
EdgeCap *e;
int length;
double cfrac, sfrac, afrac, mult, efflength;
CapValue cap, subcap;
CoupleKey ck;
int dfar, dnear;
double sfar, snear, subfrac;
/* Nothing to do for space tiles, so just return. */
/* (TO DO: Make sure TT_SPACE is removed from all exts_sideOverlapOtherTypes */
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, and clip to the fringe area */
/* of the tile edge generating the fringe capacitance. */
TITORECT(tp, &sov.so_clip);
GEOCLIP(&sov.so_clip, esws->area);
/* Calculate the length of the clipped area */
if (bp->b_segment.r_xtop == bp->b_segment.r_xbot)
length = sov.so_clip.r_ytop - sov.so_clip.r_ybot;
else
length = sov.so_clip.r_xtop - sov.so_clip.r_xbot;
/* ta is the tile type of the edge generating the fringe cap. */
ta = TiGetType(bp->b_inside);
/* Revert any contacts to their residues */
if (DBIsContact(ta))
ta = DBPlaneToResidue(ta, esws->plane_of_boundary);
if (DBIsContact(tb))
tb = DBPlaneToResidue(tb, esws->plane_checked);
/* Find the fraction of the fringe cap seen by tile tp (depends */
/* on the tile width and distance from the boundary) */
switch (bp->b_direction)
{
case BD_LEFT: /* Tile tp is to the left of the boundary */
dfar = bp->b_segment.r_ll.p_x - sov.so_clip.r_xbot;
dnear = bp->b_segment.r_ll.p_x - sov.so_clip.r_xtop;
break;
case BD_RIGHT: /* Tile tp is to the right of the boundary */
dfar = sov.so_clip.r_xtop - bp->b_segment.r_ur.p_x;
dnear = sov.so_clip.r_xbot - bp->b_segment.r_ur.p_x;
break;
case BD_BOTTOM: /* Tile tp is below the boundary */
dfar = bp->b_segment.r_ll.p_y - sov.so_clip.r_ybot;
dnear = bp->b_segment.r_ll.p_y - sov.so_clip.r_ytop;
break;
case BD_TOP: /* Tile tp is above the boundary */
dfar = sov.so_clip.r_ytop - bp->b_segment.r_ur.p_y;
dnear = sov.so_clip.r_ybot - bp->b_segment.r_ur.p_y;
break;
}
if (dnear < 0) dnear = 0; /* Don't count underlap */
mult = ExtCurStyle->exts_overlapMult[ta][tb];
sfar = 0.6366 * atan(mult * dfar);
snear = 0.6366 * atan(mult * dnear);
/* "cfrac" is the fractional portion of the fringe cap seen */
/* by tile tp along its length. This is independent of the */
/* portion of the boundary length that tile tp occupies. */
cfrac = sfar - snear;
/* The fringe portion extracted from the substrate will be */
/* different than the portion added to the coupling layer. */
if (ExtCurStyle->exts_overlapMult[ta][0] != mult)
{
mult = ExtCurStyle->exts_overlapMult[ta][0];
sfar = 0.6366 * atan(mult * dfar);
snear = 0.6366 * atan(mult * dnear);
}
sfrac = sfar - snear;
/* Apply each rule, incorporating shielding into the edge length. */
cap = subcap = (CapValue) 0;
subfrac = 0.0;
for (e = esws->extOverlapList; e; e = e->ec_next)
{
/* Only apply rules for the plane in which they are declared */
if (!PlaneMaskHasPlane(e->ec_pmask, esws->plane_checked)) continue;
/* Does this rule "e" include the tile we found? */
if (TTMaskHasType(&e->ec_near, tb))
{
/* We have a possible capacitor, but are the tiles shielded from
* each other part of the way?
*/
int pNum;
sov.so_pmask = ExtCurStyle->exts_sideOverlapShieldPlanes[ta][tb];
sov.so_esws = esws;
sov.so_coupfrac = (double)0.0;
sov.so_subfrac = (double)0.0;
sov.so_length = length;
sov.so_ctype = tb;
if (sov.so_pmask)
{
sov.so_tmask = e->ec_far; /* Actually shieldtypes. */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
/* Each call to DBSrPaintArea has an opportunity to
* subtract a partial capacitance from the total.
*/
if (!PlaneMaskHasPlane(sov.so_pmask, pNum)) continue;
sov.so_pmask &= ~(PlaneNumToMaskBit(pNum));
if (sov.so_pmask == 0)
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &sov.so_clip,
&sov.so_tmask, extSubtractSideOverlap, (ClientData) &sov);
}
else
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &sov.so_clip,
&DBAllTypeBits,
extSubtractSideOverlap2, (ClientData) &sov);
}
break;
}
}
if (rtp != rbp)
{
efflength = (cfrac - sov.so_coupfrac) * (double)length;
cap += e->ec_cap * efflength;
subfrac += sov.so_subfrac; /* Just add the shielded fraction */
}
}
}
/* Add in the new capacitance. */
if (tb != TT_SPACE)
{
int oa = ExtCurStyle->exts_planeOrder[esws->plane_of_boundary];
int ob = ExtCurStyle->exts_planeOrder[esws->plane_checked];
if (oa > ob)
{
/* If the overlapped tile is between the substrate and the boundary
* tile, then we subtract the fringe substrate capacitance
* from rbp's region due to the area of the sideoverlap, since
* we now know it is shielded from the substrate.
*/
TileType outtype = TiGetType(bp->b_outside);
/* Decompose contacts into their residues */
if (DBIsContact(ta))
ta = DBPlaneToResidue(ta, esws->plane_of_boundary);
if (DBIsContact(outtype))
outtype = DBPlaneToResidue(outtype, esws->plane_of_boundary);
efflength = (sfrac - subfrac) * (double)length;
subcap = ExtCurStyle->exts_perimCap[ta][0] * efflength;
rbp->nreg_cap -= subcap;
/* Ignore residual error at ~zero zeptoFarads. Probably */
/* there should be better handling of round-off here. */
if ((rbp->nreg_cap > -0.001) && (rbp->nreg_cap < 0.001))
rbp->nreg_cap = 0;
if (CAP_DEBUG)
extNregAdjustCap(rbp, -subcap, "obsolete_perimcap");
}
else if (CAP_DEBUG)
extNregAdjustCap(rbp, 0.0, "obsolete_perimcap (skipped, wrong direction)");
/* If the nodes are electrically connected, then we don't add */
/* any side overlap capacitance to the node. */
if (rtp == rbp) return 0;
if (rtp == (NodeRegion *)CLIENTDEFAULT) return 0;
if (rbp == (NodeRegion *)CLIENTDEFAULT) return 0;
if (rtp < rbp)
{
ck.ck_1 = rtp;
ck.ck_2 = rbp;
}
else
{
ck.ck_1 = rbp;
ck.ck_2 = rtp;
}
he = HashFind(extCoupleHashPtr, (char *) &ck);
if (CAP_DEBUG) extAdjustCouple(he, cap, "sideoverlap");
extSetCapValue(he, cap + extGetCapValue(he));
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extSideOverlap --
*
* The boundary 'bp' has been found to overlap the tile 'tp', which it
* has coupling capacitance to. This is legacy behavior when no fringe
* halo is considered, but the fringe is modeled as being directed
* downward from an edge onto any layer directly below the edge, and
* occupying no area. This approximation is generally only reasonable for
* processes down to 0.5um or so.
*
* Results:
* Returns 0 to keep DBSrPaintArea() going.
*
* Side effects:
* Update the coupling capacitance between node(bp->t_inside) and
* node(tp) if the two nodes are different. Does so by updating
* the value stored in the HashEntry keyed by the two nodes.
*
* ----------------------------------------------------------------------------
*/
int
extSideOverlap(tp, dinfo, esws)
Tile *tp; /* Overlapped tile */
TileType dinfo; /* Split tile information */
extSidewallStruct *esws; /* Overlapping edge and plane information */
{
Boundary *bp = esws->bp; /* Overlapping edge */
NodeRegion *rtp = (NodeRegion *) ExtGetRegion(tp, dinfo);
NodeRegion *rbp = (NodeRegion *) ExtGetRegion(bp->b_inside, (TileType)0);
TileType ta, tb;
Rect tpr;
struct overlap ov;
HashEntry *he;
EdgeCap *e;
int length, areaAccountedFor, areaTotal;
double afrac;
CapValue cap;
CoupleKey ck;
/* Nothing to do for space tiles, so just return. */
/* (TO DO: Make sure TT_SPACE is removed from all exts_sideOverlapOtherTypes */
if (IsSplit(tp))
tb = (dinfo & TT_SIDE) ? TiGetRightType(tp) : TiGetLeftType(tp);
else
tb = TiGetTypeExact(tp);
if (tb == TT_SPACE) return (0);
if (bp->b_segment.r_xtop == bp->b_segment.r_xbot)
{
length = MIN(bp->b_segment.r_ytop, TOP(tp))
- MAX(bp->b_segment.r_ybot, BOTTOM(tp));
}
else
{
length = MIN(bp->b_segment.r_xtop, RIGHT(tp))
- MAX(bp->b_segment.r_xbot, LEFT(tp));
}
TITORECT(tp, &ov.o_clip);
GEOCLIP(&ov.o_clip, esws->area);
areaTotal = GEO_WIDTH(&ov.o_clip) * GEO_HEIGHT(&ov.o_clip);
areaAccountedFor = 0;
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 edge length. */
cap = (CapValue) 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))
{
/* We have a possible capacitor, but are the tiles shielded from
* each other part of the way?
*/
int pNum;
ov.o_area = areaTotal;
ov.o_pmask = ExtCurStyle->exts_sideOverlapShieldPlanes[ta][tb];
if (ov.o_pmask)
{
ov.o_tmask = e->ec_far; /* Actually shieldtypes. */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
/* Each call to DBSrPaintArea has an opportunity to
* subtract from the area (really length 'cause width=1).
*/
if (!PlaneMaskHasPlane(ov.o_pmask, pNum)) continue;
ov.o_pmask &= ~(PlaneNumToMaskBit(pNum));
if (ov.o_pmask == 0)
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &ov.o_clip,
&ov.o_tmask, extSubtractOverlap, (ClientData) &ov);
}
else
{
(void) DBSrPaintArea((Tile *) NULL,
extOverlapDef->cd_planes[pNum], &ov.o_clip,
&DBAllTypeBits,
extSubtractOverlap2, (ClientData) &ov);
}
break;
}
}
if (rtp != rbp)
cap += e->ec_cap * ov.o_area;
areaAccountedFor += ov.o_area;
}
}
/* Add in the new capacitance. */
if (tb != TT_SPACE)
{
int oa = ExtCurStyle->exts_planeOrder[esws->plane_of_boundary];
int ob = ExtCurStyle->exts_planeOrder[esws->plane_checked];
if (oa > ob)
{
/* If the overlapped tile is between the substrate and the boundary
* tile, then we subtract the fringe substrate capacitance
* from rbp's region due to the area of the sideoverlap, since
* we now know it is shielded from the substrate.
*/
CapValue subcap;
TileType outtype = TiGetType(bp->b_outside);
/* Decompose contacts into their residues */
if (DBIsContact(ta))
ta = DBPlaneToResidue(ta, esws->plane_of_boundary);
if (DBIsContact(outtype))
outtype = DBPlaneToResidue(outtype, esws->plane_of_boundary);
afrac = (double)areaAccountedFor / (double)areaTotal;
subcap = (ExtCurStyle->exts_perimCap[ta][outtype] *
MIN(areaAccountedFor, length));
rbp->nreg_cap -= subcap;
/* Ignore residual error at ~zero zeptoFarads. Probably */
/* there should be better handling of round-off here. */
if ((rbp->nreg_cap > -0.001) && (rbp->nreg_cap < 0.001))
rbp->nreg_cap = 0;
if (CAP_DEBUG)
extNregAdjustCap(rbp, -subcap, "obsolete_perimcap");
}
else if (CAP_DEBUG)
extNregAdjustCap(rbp, 0.0, "obsolete_perimcap (skipped, wrong direction)");
/* If the nodes are electrically connected, then we don't add */
/* any side overlap capacitance to the node. */
if (rtp == rbp) return 0;
if (rtp == (NodeRegion *)CLIENTDEFAULT) return 0;
if (rbp == (NodeRegion *)CLIENTDEFAULT) return 0;
if (rtp < rbp)
{
ck.ck_1 = rtp;
ck.ck_2 = rbp;
}
else
{
ck.ck_1 = rbp;
ck.ck_2 = rtp;
}
he = HashFind(extCoupleHashPtr, (char *) &ck);
if (CAP_DEBUG) extAdjustCouple(he, cap, "sideoverlap");
extSetCapValue(he, cap + extGetCapValue(he));
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* 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);
}
}
}
/*
* ----------------------------------------------------------------------------
*
* extWalkTop ---
*
* Search in the area 'area' above the boundary 'bp' for coupling tiles of
* types in 'mask', starting from the right corner above the boundary and
* sweeping left. If a coupling tile is found, process it, clipping the
* boundary to the width of the tile if needed. Then recursively call
* extWalkTop on the areas to the left and right sides of the tile with
* boundaries reduced to the width of those areas. This way the edge
* boundary is subdivided into lengths occupied by the nearest neighbor.
*
* Return value:
* Return 1 if func() returned 1, otherwise return 0.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
extWalkTop(area, mask, func, bp, esws)
Rect *area;
TileTypeBitMask *mask;
int (*func)();
Boundary *bp;
extSidewallStruct *esws;
{
Tile *tile, *tp;
TileType ttype;
Boundary bloc;
Rect aloc;
tile = RT(bp->b_outside); /* Tile above tile on top of the boundary */
while (BOTTOM(tile) < area->r_ytop)
{
while (LEFT(tile) >= area->r_xtop) tile = BL(tile); /* Walk back to area */
tp = tile;
while (RIGHT(tp) > area->r_xbot)
{
ttype = TiGetBottomType(tp);
if (TTMaskHasType(mask, ttype))
{
bool lookLeft, lookRight;
bloc = *bp; /* Copy boundary to bc, then adjust boundary */
lookLeft = (LEFT(tp) > bp->b_segment.r_xbot) ? TRUE : FALSE;
lookRight = (RIGHT(tp) < bp->b_segment.r_xtop) ? TRUE : FALSE;
if (lookLeft)
bloc.b_segment.r_xbot = LEFT(tp);
if (lookRight)
bloc.b_segment.r_xtop = RIGHT(tp);
/* Call sidewall coupling calculation function */
if (func(tp, &bloc, esws) != 0) return 1;
/* Clip coupling area and call fringe coupling calculation function */
aloc = *area;
aloc.r_ytop = BOTTOM(tp);
aloc.r_xbot = bloc.b_segment.r_xbot;
aloc.r_xtop = bloc.b_segment.r_xtop;
if (extFindOverlap(bp->b_outside, &aloc, esws) != 0) return 1;
extRemoveSubcap(&bloc, &aloc, esws);
/* Recurse on tile left side */
if (lookLeft)
{
aloc = *area;
aloc.r_xtop = bloc.b_segment.r_xbot;
bloc.b_segment.r_xbot = bp->b_segment.r_xbot;
bloc.b_segment.r_xtop = aloc.r_xtop;
if (extWalkTop(&aloc, mask, func, &bloc, esws) != 0)
return 1;
}
/* Recurse on tile right side */
if (lookRight)
{
aloc = *area;
aloc.r_xbot = RIGHT(tp);
bloc.b_segment.r_xtop = bp->b_segment.r_xtop;
bloc.b_segment.r_xbot = aloc.r_xbot;
if (extWalkTop(&aloc, mask, func, &bloc, esws) != 0)
return 1;
}
/* Once a coupling tile is found, it blocks any */
/* 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);
}
/* 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, esws);
}
/*
* ----------------------------------------------------------------------------
*
* extWalkBottom ---
*
* Search in the area 'area' below the boundary 'bp' for coupling tiles of
* types in 'mask', starting from the left corner below the boundary and
* sweeping right. If a coupling tile is found, process it, clipping the
* boundary to the width of the tile if needed. Then recursively call
* extWalkBottom on the areas to the left and right sides of the tile with
* boundaries reduced to the width of those areas. This way the edge
* boundary is subdivided into lengths occupied by the nearest neighbor.
*
* Return value:
* Return 1 if func() returned 1, otherwise return 0.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
extWalkBottom(area, mask, func, bp, esws)
Rect *area;
TileTypeBitMask *mask;
int (*func)();
Boundary *bp;
extSidewallStruct *esws;
{
Tile *tile, *tp;
TileType ttype;
Boundary bloc;
Rect aloc;
tile = LB(bp->b_outside); /* Tile below tile on bottom of the boundary */
while (TOP(tile) > area->r_ybot)
{
while (RIGHT(tile) <= area->r_xbot) tile = TR(tile); /* Walk back to area */
tp = tile;
while (LEFT(tp) < area->r_xtop)
{
ttype = TiGetTopType(tp);
if (TTMaskHasType(mask, ttype))
{
bool lookLeft, lookRight;
bloc = *bp; /* Copy boundary to bc, then adjust boundary */
lookLeft = (LEFT(tp) > bp->b_segment.r_xbot) ? TRUE : FALSE;
lookRight = (RIGHT(tp) < bp->b_segment.r_xtop) ? TRUE : FALSE;
if (lookLeft)
bloc.b_segment.r_xbot = LEFT(tp);
if (lookRight)
bloc.b_segment.r_xtop = RIGHT(tp);
/* Call sidewall coupling calculation function */
if (func(tp, &bloc, esws) != 0) return 1;
/* Clip coupling area and call fringe coupling calculation function */
aloc = *area;
aloc.r_ybot = TOP(tp);
aloc.r_xbot = bloc.b_segment.r_xbot;
aloc.r_xtop = bloc.b_segment.r_xtop;
if (extFindOverlap(bp->b_outside, &aloc, esws) != 0) return 1;
extRemoveSubcap(&bloc, &aloc, esws);
/* Recurse on tile left side */
if (lookLeft)
{
aloc = *area;
aloc.r_xtop = bloc.b_segment.r_xbot;
bloc.b_segment.r_xbot = bp->b_segment.r_xbot;
bloc.b_segment.r_xtop = aloc.r_xtop;
if (extWalkBottom(&aloc, mask, func, &bloc, esws) != 0)
return 1;
}
/* Recurse on tile right side */
if (lookRight)
{
aloc = *area;
aloc.r_xbot = RIGHT(tp);
bloc.b_segment.r_xtop = bp->b_segment.r_xtop;
bloc.b_segment.r_xbot = aloc.r_xbot;
if (extWalkBottom(&aloc, mask, func, &bloc, esws) != 0)
return 1;
}
/* Once a coupling tile is found, it blocks any */
/* 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);
}
/* 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, esws);
}
/*
* ----------------------------------------------------------------------------
*
* extWalkRight ---
*
* Search in the area 'area' to the right of the boundary 'bp' for coupling
* tiles of types in 'mask', starting from the top corner to the right of the
* boundary and sweeping downward. If a coupling tile is found, process it,
* clipping the boundary to the height of the tile if needed. Then recursively
* call extWalkRight on the areas above and below the tile with boundaries
* reduced to the height of those areas. This way the edge boundary is
* subdivided into lengths occupied by the nearest neighbor.
*
* Return value:
* Return 1 if func() returned 1, otherwise return 0.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
extWalkRight(area, mask, func, bp, esws)
Rect *area;
TileTypeBitMask *mask;
int (*func)();
Boundary *bp;
extSidewallStruct *esws;
{
Tile *tile, *tp;
TileType ttype;
Boundary bloc;
Rect aloc;
tile = TR(bp->b_outside); /* Tile to the right of tile to right of the boundary */
while (LEFT(tile) < area->r_xtop)
{
while (BOTTOM(tile) >= area->r_ytop) tile = LB(tile); /* Walk back to area */
tp = tile;
while (TOP(tp) > area->r_ybot)
{
ttype = TiGetLeftType(tp);
if (TTMaskHasType(mask, ttype))
{
bool lookDown, lookUp;
bloc = *bp; /* Copy boundary to bc, then adjust boundary */
lookDown = (BOTTOM(tp) > bp->b_segment.r_ybot) ? TRUE : FALSE;
lookUp = (TOP(tp) < bp->b_segment.r_ytop) ? TRUE : FALSE;
if (lookDown)
bloc.b_segment.r_ybot = BOTTOM(tp);
if (lookUp)
bloc.b_segment.r_ytop = TOP(tp);
/* Call sidewall coupling calculation function */
if (func(tp, &bloc, esws) != 0) return 1;
/* Clip coupling area and call fringe coupling calculation function */
aloc = *area;
aloc.r_xtop = LEFT(tp);
aloc.r_ybot = bloc.b_segment.r_ybot;
aloc.r_ytop = bloc.b_segment.r_ytop;
if (extFindOverlap(bp->b_outside, &aloc, esws) != 0) return 1;
extRemoveSubcap(&bloc, &aloc, esws);
/* Recurse on tile bottom side */
if (lookDown)
{
aloc = *area;
aloc.r_ytop = bloc.b_segment.r_ybot;
bloc.b_segment.r_ybot = bp->b_segment.r_ybot;
bloc.b_segment.r_ytop = aloc.r_ytop;
if (extWalkRight(&aloc, mask, func, &bloc, esws) != 0)
return 1;
}
/* Recurse on tile top side */
if (lookUp)
{
aloc = *area;
aloc.r_ybot = TOP(tp);
bloc.b_segment.r_ytop = bp->b_segment.r_ytop;
bloc.b_segment.r_ybot = aloc.r_ybot;
if (extWalkRight(&aloc, mask, func, &bloc, esws) != 0)
return 1;
}
/* Once a coupling tile is found, it blocks any */
/* 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);
}
/* 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, esws);
}
/*
* ----------------------------------------------------------------------------
*
* extWalkLeft ---
*
* Search in the area 'area' to the left of the boundary 'bp' for coupling
* tiles of types in 'mask', starting from the bottom corner to the left of the
* boundary and sweeping upward. If a coupling tile is found, process it,
* clipping the boundary to the height of the tile if needed. Then recursively
* call extWalkLeft on the areas above and below the tile with boundaries
* reduced to the height of those areas. This way the edge boundary is
* subdivided into lengths occupied by the nearest neighbor.
*
* Return value:
* Return 1 if func() returned 1, otherwise return 0.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
extWalkLeft(area, mask, func, bp, esws)
Rect *area;
TileTypeBitMask *mask;
int (*func)();
Boundary *bp;
extSidewallStruct *esws;
{
Tile *tile, *tp;
TileType ttype;
Boundary bloc;
Rect aloc;
tile = BL(bp->b_outside); /* Tile to the left of tile to left of the boundary */
while (RIGHT(tile) > area->r_xbot)
{
while (TOP(tile) <= area->r_ybot) tile = RT(tile); /* Walk back to area */
tp = tile;
while (BOTTOM(tp) < area->r_ytop)
{
ttype = TiGetRightType(tp);
if (TTMaskHasType(mask, ttype))
{
bool lookDown, lookUp;
bloc = *bp; /* Copy boundary to bc, then adjust boundary */
lookDown = (BOTTOM(tp) > bp->b_segment.r_ybot) ? TRUE : FALSE;
lookUp = (TOP(tp) < bp->b_segment.r_ytop) ? TRUE : FALSE;
if (lookDown)
bloc.b_segment.r_ybot = BOTTOM(tp);
if (lookUp)
bloc.b_segment.r_ytop = TOP(tp);
/* Call sidewall coupling calculation function */
if (func(tp, &bloc, esws) != 0) return 1;
/* Clip coupling area and call fringe coupling calculation function */
aloc = *area;
aloc.r_xbot = RIGHT(tp);
aloc.r_ybot = bloc.b_segment.r_ybot;
aloc.r_ytop = bloc.b_segment.r_ytop;
if (extFindOverlap(bp->b_outside, &aloc, esws) != 0) return 1;
extRemoveSubcap(&bloc, &aloc, esws);
/* Recurse on tile bottom side */
if (lookDown)
{
aloc = *area;
aloc.r_ytop = bloc.b_segment.r_ybot;
bloc.b_segment.r_ybot = bp->b_segment.r_ybot;
bloc.b_segment.r_ytop = aloc.r_ytop;
if (extWalkLeft(&aloc, mask, func, &bloc, esws) != 0)
return 1;
}
/* Recurse on tile top side */
if (lookUp)
{
aloc = *area;
aloc.r_ybot = TOP(tp);
bloc.b_segment.r_ytop = bp->b_segment.r_ytop;
bloc.b_segment.r_ybot = aloc.r_ybot;
if (extWalkLeft(&aloc, mask, func, &bloc, esws) != 0)
return 1;
}
/* Once a coupling tile is found, it blocks any */
/* 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);
}
/* 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, esws);
}
/*
* ----------------------------------------------------------------------------
*
* extSideLeft --
*
* 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 has sidewall coupling capacitance.
*
* Walk along the right-hand side of 'tpfar' searching for such
* edges, and recording their capacitance in the hash table
* *extCoupleHashPtr.
*
* Results:
* Returns 0 always.
*
* Side effects:
* If node(tpfar) exists, and node(bp->b_inside) != node(tpfar),
* search along the inside edge of tpfar (the one closest to
* the boundary bp) for edges having capacitance with bp. For
* each such edge found, update the entry in *extCoupleHashPtr
* identified by node(bp->b_inside) and node(tpfar) by adding
* the capacitance due to the adjacency of the pair of edges.
*
* ----------------------------------------------------------------------------
*/
int
extSideLeft(tpfar, bp, esws)
Tile *tpfar;
Boundary *bp;
extSidewallStruct *esws;
{
NodeRegion *rinside, *rfar;
Tile *tpnear;
/* Get the regions associated with bp->b_inside and tpfar */
extGetBoundaryRegions(bp->b_direction, bp->b_inside, tpfar, &rinside, &rfar);
if (rfar != (NodeRegion *)CLIENTDEFAULT && rfar != rinside)
{
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));
for (tpnear = TR(tpfar); TOP(tpnear) > limit; tpnear = LB(tpnear))
{
int overlap = MIN(TOP(tpnear), start) - MAX(BOTTOM(tpnear), limit);
if (overlap > 0)
extSideCommon(rinside, rfar, tpnear, tpfar, bp->b_direction,
overlap, sep, esws->extCoupleList);
}
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extSideRight --
*
* 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 has sidewall coupling capacitance.
*
* Walk along the left-hand side of 'tpfar' searching for such
* edges, and recording their capacitance in the hash table
* *extCoupleHashPtr.
*
* Results:
* Returns 0 always.
*
* Side effects:
* See extSideLeft.
*
* ----------------------------------------------------------------------------
*/
int
extSideRight(tpfar, bp, esws)
Tile *tpfar;
Boundary *bp;
extSidewallStruct *esws;
{
NodeRegion *rinside, *rfar;
Tile *tpnear;
/* Get the regions associated with bp->b_inside and tpfar */
extGetBoundaryRegions(bp->b_direction, bp->b_inside, tpfar, &rinside, &rfar);
if (rfar != (NodeRegion *) CLIENTDEFAULT && rfar != rinside)
{
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));
for (tpnear = BL(tpfar); BOTTOM(tpnear) < limit; tpnear = RT(tpnear))
{
int overlap = MIN(TOP(tpnear), limit) - MAX(BOTTOM(tpnear), start);
if (overlap > 0)
extSideCommon(rinside, rfar, tpnear, tpfar, bp->b_direction,
overlap, sep, esws->extCoupleList);
}
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extSideTop --
*
* 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 has sidewall coupling capacitance.
*
* Walk along the bottom side of 'tpfar' searching for such
* edges, and recording their capacitance in the hash table
* *extCoupleHashPtr.
*
* Results:
* Returns 0 always.
*
* Side effects:
* See extSideLeft.
*
* ----------------------------------------------------------------------------
*/
int
extSideTop(tpfar, bp, esws)
Tile *tpfar;
Boundary *bp;
extSidewallStruct *esws;
{
NodeRegion *rinside, *rfar;
Tile *tpnear;
/* Get the regions associated with bp->b_inside and tpfar */
extGetBoundaryRegions(bp->b_direction, bp->b_inside, tpfar, &rinside, &rfar);
if (rfar != (NodeRegion *) CLIENTDEFAULT && rfar != rinside)
{
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));
for (tpnear = LB(tpfar); LEFT(tpnear) < limit; tpnear = TR(tpnear))
{
int overlap = MIN(RIGHT(tpnear), limit) - MAX(LEFT(tpnear), start);
if (overlap > 0)
extSideCommon(rinside, rfar, tpnear, tpfar, bp->b_direction,
overlap, sep, esws->extCoupleList);
}
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extSideBottom --
*
* 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 has sidewall coupling capacitance.
*
* Walk along the top side of 'tpfar' searching for such
* edges, and recording their capacitance in the hash table
* *extCoupleHashPtr.
*
* Results:
* Returns 0 always.
*
* Side effects:
* See extSideLeft.
*
* ----------------------------------------------------------------------------
*/
int
extSideBottom(tpfar, bp, esws)
Tile *tpfar;
Boundary *bp;
extSidewallStruct *esws;
{
NodeRegion *rinside, *rfar;
Tile *tpnear;
/* Get the regions associated with bp->b_inside and tpfar */
extGetBoundaryRegions(bp->b_direction, bp->b_inside, tpfar, &rinside, &rfar);
if (rfar != (NodeRegion *) CLIENTDEFAULT && rfar != rinside)
{
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));
for (tpnear = RT(tpfar); RIGHT(tpnear) > limit; tpnear = BL(tpnear))
{
int overlap = MIN(RIGHT(tpnear), start) - MAX(LEFT(tpnear), limit);
if (overlap > 0)
extSideCommon(rinside, rfar, tpnear, tpfar, bp->b_direction,
overlap, sep, esws->extCoupleList);
}
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extSideCommon --
*
* Perform the actual update to the hash table entry for
* the regions 'rinside' and 'rfar'. We assume that neither
* 'rinside' nor 'rfar' are CLIENTDEFAULT, and further that they
* are not equal.
*
* Walk along the rules in extCoupleList, applying the appropriate
* amount of capacitance for an edge with tpnear on the close side
* and tpfar on the remote side.
*
* Results:
* Returns 0 always.
*
* Side effects:
* See extSideLeft.
*
* ----------------------------------------------------------------------------
*/
void
extSideCommon(rinside, rfar, tpnear, tpfar, bdir, overlap, sep, extCoupleList)
NodeRegion *rinside, *rfar; /* Both must be valid */
Tile *tpnear, *tpfar; /* Tiles on near and far side of edge */
int bdir; /* Boundary direction */
int overlap, sep; /* Overlap of this edge with original one,
* and distance between the two.
*/
EdgeCap *extCoupleList; /* List of sidewall capacitance rules */
{
TileType near, far;
HashEntry *he;
EdgeCap *e;
CoupleKey ck;
CapValue cap;
/* Get the tile types of tpnear and tpfar */
extGetBoundaryTypes2(bdir, tpnear, tpfar, &near, &far);
if (rinside < rfar) ck.ck_1 = rinside, ck.ck_2 = rfar;
else ck.ck_1 = rfar, ck.ck_2 = rinside;
he = HashFind(extCoupleHashPtr, (char *) &ck);
cap = extGetCapValue(he);
for (e = extCoupleList; e; e = e->ec_next)
if (TTMaskHasType(&e->ec_near, near) && TTMaskHasType(&e->ec_far, far)) {
cap += (e->ec_cap * overlap) / (sep + e->ec_offset);
if (CAP_DEBUG)
extAdjustCouple(he,
(e->ec_cap * overlap) / (sep + e->ec_offset),
"sidewall");
}
extSetCapValue(he, cap);
}