mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-05 08:51:53 +02:00
after much discussion about the implementation. Since it is not exactly clear what the field lines do at corners, the implementation depends largely on an unknown and presumably global constant multiplier; this has provisionally been set to 1 but needs to be determined empirically with a field equation solver. At least one rational approximation suggests a value of pi/2 instead of 1. The corner capacitance can be considered a refinement of existing parasitic capacitance extraction, and since it takes a non-trivial additional amount of computation, it is left as an option to "extract" that can be turned on when a more accurate result is preferred at the expense of a longer extraction time.
3104 lines
91 KiB
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);
|
|
}
|
|
|