mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-30 18:02:32 +02:00
is specified in the extraction section of the techfile, then magic will compute the effect of a nearby shape partially shielding the sidewall overlap capacitance, which approaches 100% shielding as the shapes converge to zero separation. This method prevents magic from vastly overestimating the fringe capacitance of closely spaced wires, which was magic's worst problem with parasitic accuracy. The "fringeshieldhalo" value is the distance at which the fringe shielding becomes negligible. Typically, it will be about three times the distance at which half the fringe value is shielded. It may be necessary at some point to make both the fringe shielding halo and the sidewall halo values per-type values (or per-plane, at least). For now, it should suffice to bring Magic's parasitic extraction back in line with other tools.
1468 lines
42 KiB
C
1468 lines
42 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 sin() */
|
|
|
|
#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"
|
|
|
|
/* --------------------- Data local to this file ---------------------- */
|
|
|
|
/* Pointer to hash table currently being updated with coupling capacitance */
|
|
HashTable *extCoupleHashPtr;
|
|
|
|
/* Clipping area for coupling searches */
|
|
Rect *extCoupleSearchArea;
|
|
|
|
/* Current list of sidewall capacitance rules */
|
|
EdgeCap *extCoupleList;
|
|
EdgeCap *extOverlapList;
|
|
|
|
/* Def being processed */
|
|
CellDef *extOverlapDef;
|
|
|
|
/* Forward procedure declarations */
|
|
int extBasicOverlap(), extBasicCouple();
|
|
int extAddOverlap(), extAddCouple();
|
|
int extSideLeft(), extSideRight(), extSideBottom(), extSideTop();
|
|
int extSideOverlap();
|
|
void extSideCommon();
|
|
int extShieldLeft(), extShieldRight(), extShieldBottom(), extShieldTop();
|
|
|
|
/* 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;
|
|
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;
|
|
float shieldfrac;
|
|
} extSidewallStruct;
|
|
|
|
/* Structure to pass the value for fringe shielding */
|
|
|
|
typedef struct _efss {
|
|
Boundary *bp;
|
|
float shieldfrac; // Fraction of fringe capacitance shielded
|
|
} extFringeShieldStruct;
|
|
|
|
|
|
/* --------------------- 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?).
|
|
*
|
|
* and a mitigating effect:
|
|
*
|
|
* Sidewall
|
|
* shield. When another shape on the same plane is in the proximity of
|
|
* a sidewall edge, then the other shape partially shields the
|
|
* fringe (sidewall overlap) capacitance. The amount of shielding
|
|
* is modeled by an ellipse between the fringe effect distance
|
|
* exts_fringeShieldHalo (no shielding) and zero (full shielding).
|
|
*
|
|
* Requires that ExtFindRegions has been run on 'def' to label all its
|
|
* tiles with NodeRegions. Also requires that the HashTable 'table'
|
|
* has been initialized by the caller.
|
|
*
|
|
* 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;
|
|
{
|
|
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, ecs)
|
|
Tile *tile;
|
|
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 = (SplitSide(tile)) ? 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.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;
|
|
};
|
|
|
|
int
|
|
extAddOverlap(tbelow, ecpls)
|
|
Tile *tbelow;
|
|
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);
|
|
rbelow = (NodeRegion *) extGetRegion(tbelow);
|
|
|
|
/* 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);
|
|
ta = TiGetType(tabove);
|
|
tb = TiGetType(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);
|
|
}
|
|
|
|
int
|
|
extSubtractOverlap(tile, ov)
|
|
Tile *tile;
|
|
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 (area > 0)
|
|
ov->o_area -= area;
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
extSubtractOverlap2(tile, ov)
|
|
Tile *tile;
|
|
struct overlap *ov;
|
|
{
|
|
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);
|
|
|
|
/* This tile shields everything below */
|
|
if (TTMaskHasType(&ov->o_tmask, TiGetType(tile)))
|
|
{
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* 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, ecs)
|
|
Tile *tile;
|
|
extCapStruct *ecs;
|
|
{
|
|
(void) extEnumTilePerim(tile, ExtCurStyle->exts_sideEdges[TiGetType(tile)],
|
|
ecs->plane, extAddCouple, (ClientData) ecs);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* 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.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Rect extSideOverlapSearchArea;
|
|
|
|
int
|
|
extAddCouple(bp, ecs)
|
|
Boundary *bp; /* Boundary being considered */
|
|
extCapStruct *ecs;
|
|
{
|
|
TileType tin = TiGetType(bp->b_inside), tout = TiGetType(bp->b_outside);
|
|
int pNum;
|
|
PlaneMask pMask;
|
|
int (*proc)();
|
|
Boundary bpCopy;
|
|
Rect r, ovr;
|
|
CellDef *def = ecs->def;
|
|
extSidewallStruct esws;
|
|
|
|
/* Revert any edge contacts to their residues */
|
|
if (DBIsContact(tin))
|
|
tin = DBPlaneToResidue(tin, ecs->plane);
|
|
if (DBIsContact(tout))
|
|
tout = DBPlaneToResidue(tout, ecs->plane);
|
|
|
|
extCoupleList = ExtCurStyle->exts_sideCoupleCap[tin][tout];
|
|
extOverlapList = ExtCurStyle->exts_sideOverlapCap[tin][tout];
|
|
if (extCoupleList == NULL && extOverlapList == NULL)
|
|
return (0);
|
|
|
|
/*
|
|
* 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;
|
|
|
|
GEOCLIP(&bp->b_segment, extCoupleSearchArea);
|
|
|
|
if ((bp->b_segment.r_ytop <= bp->b_segment.r_ybot) &&
|
|
(bp->b_segment.r_xtop <= bp->b_segment.r_xbot))
|
|
return 0;
|
|
}
|
|
r = ovr = bp->b_segment;
|
|
|
|
switch (bp->b_direction)
|
|
{
|
|
case BD_LEFT: /* Along left */
|
|
r.r_xbot -= ExtCurStyle->exts_sideCoupleHalo ;
|
|
ovr.r_xbot -= 1;
|
|
proc = extSideLeft;
|
|
break;
|
|
case BD_RIGHT: /* Along right */
|
|
r.r_xtop += ExtCurStyle->exts_sideCoupleHalo ;
|
|
ovr.r_xtop += 1;
|
|
proc = extSideRight;
|
|
break;
|
|
case BD_TOP: /* Along top */
|
|
r.r_ytop += ExtCurStyle->exts_sideCoupleHalo ;
|
|
ovr.r_ytop += 1;
|
|
proc = extSideTop;
|
|
break;
|
|
case BD_BOTTOM: /* Along bottom */
|
|
r.r_ybot -= ExtCurStyle->exts_sideCoupleHalo ;
|
|
ovr.r_ybot -= 1;
|
|
proc = extSideBottom;
|
|
break;
|
|
}
|
|
|
|
if (extCoupleList)
|
|
(void) DBSrPaintArea((Tile *) NULL, def->cd_planes[ecs->plane],
|
|
&r, &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout],
|
|
proc, (ClientData) bp);
|
|
|
|
if (extCoupleList && extOverlapList && (ExtCurStyle->exts_fringeShieldHalo > 0))
|
|
{
|
|
extFringeShieldStruct efss;
|
|
NodeRegion *rbp;
|
|
|
|
/* Resize r for fringe shield calculation */
|
|
|
|
switch (bp->b_direction)
|
|
{
|
|
case BD_LEFT: /* Along left */
|
|
r.r_xbot += ExtCurStyle->exts_sideCoupleHalo ;
|
|
r.r_xbot -= ExtCurStyle->exts_fringeShieldHalo ;
|
|
proc = extShieldLeft;
|
|
break;
|
|
case BD_RIGHT: /* Along right */
|
|
r.r_xtop -= ExtCurStyle->exts_sideCoupleHalo ;
|
|
r.r_xtop += ExtCurStyle->exts_fringeShieldHalo ;
|
|
proc = extShieldRight;
|
|
break;
|
|
case BD_TOP: /* Along top */
|
|
r.r_ytop -= ExtCurStyle->exts_sideCoupleHalo ;
|
|
r.r_ytop += ExtCurStyle->exts_fringeShieldHalo ;
|
|
proc = extShieldTop;
|
|
break;
|
|
case BD_BOTTOM: /* Along bottom */
|
|
r.r_ybot += ExtCurStyle->exts_sideCoupleHalo ;
|
|
r.r_ybot -= ExtCurStyle->exts_fringeShieldHalo ;
|
|
proc = extShieldBottom;
|
|
break;
|
|
}
|
|
|
|
/* Find fringe shielding amount */
|
|
|
|
efss.bp = bp;
|
|
efss.shieldfrac = 0.0;
|
|
|
|
(void) DBSrPaintArea((Tile *) NULL, def->cd_planes[ecs->plane],
|
|
&r, &ExtCurStyle->exts_sideCoupleOtherEdges[tin][tout],
|
|
proc, (ClientData) &efss);
|
|
|
|
esws.shieldfrac = efss.shieldfrac;
|
|
|
|
/* Remove the part of the capacitance to substrate that came from
|
|
* the sidewall overlap and that was shielded by the nearby shape.
|
|
*/
|
|
if (esws.shieldfrac > 0.0)
|
|
{
|
|
int length;
|
|
CapValue subcap;
|
|
|
|
if (bp->b_segment.r_xtop == bp->b_segment.r_xbot)
|
|
length = bp->b_segment.r_ytop - bp->b_segment.r_ybot;
|
|
else
|
|
length = bp->b_segment.r_xtop - bp->b_segment.r_xbot;
|
|
|
|
subcap = ExtCurStyle->exts_perimCap[tin][tout] * length * esws.shieldfrac;
|
|
|
|
rbp = (NodeRegion *) extGetRegion(bp->b_inside);
|
|
rbp->nreg_cap -= subcap;
|
|
}
|
|
}
|
|
else
|
|
esws.shieldfrac = 0.0;
|
|
|
|
if (extOverlapList)
|
|
{
|
|
pMask = ExtCurStyle->exts_sideOverlapOtherPlanes[tin][tout];
|
|
extSideOverlapSearchArea = ovr;
|
|
extOverlapDef = def;
|
|
|
|
esws.bp = bp;
|
|
esws.plane_of_boundary = ecs->plane;
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(pMask, pNum))
|
|
{
|
|
esws.plane_checked = pNum;
|
|
(void) DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
|
|
&ovr, &ExtCurStyle->exts_sideOverlapOtherTypes[tin][tout],
|
|
extSideOverlap, (ClientData) &esws);
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extSideOverlap --
|
|
*
|
|
* The boundary 'bp' has been found to overlap the tile 'tp', which it
|
|
* has coupling capacitance to.
|
|
*
|
|
* 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, esws)
|
|
Tile *tp; /* Overlapped tile */
|
|
extSidewallStruct *esws; /* Overlapping edge and plane information */
|
|
{
|
|
Boundary *bp = esws->bp; /* Overlapping edge */
|
|
NodeRegion *rtp = (NodeRegion *) extGetRegion(tp);
|
|
NodeRegion *rbp = (NodeRegion *) extGetRegion(bp->b_inside);
|
|
TileType ta, tb;
|
|
Rect tpr;
|
|
struct overlap ov;
|
|
HashEntry *he;
|
|
EdgeCap *e;
|
|
int length, areaAccountedFor;
|
|
CapValue cap;
|
|
CoupleKey ck;
|
|
|
|
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, &extSideOverlapSearchArea);
|
|
ov.o_area = length;
|
|
areaAccountedFor = 0;
|
|
ASSERT(length == GEO_WIDTH(&ov.o_clip) * GEO_HEIGHT(&ov.o_clip),
|
|
"extSideOverlap");
|
|
ta = TiGetType(bp->b_inside);
|
|
tb = TiGetType(tp);
|
|
|
|
/* Avoid doing the code below if we're just going to return without */
|
|
/* changing anything. */
|
|
if ((tb == TT_SPACE) && (rtp == rbp)) return (0);
|
|
|
|
/* 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 = 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, TiGetType(tp)))
|
|
{
|
|
/* We have a possible capacitor, but are the tiles shielded from
|
|
* each other part of the way?
|
|
*/
|
|
int pNum;
|
|
ov.o_area = length;
|
|
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 * (1.0 - esws->shieldfrac);
|
|
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);
|
|
|
|
subcap = (ExtCurStyle->exts_perimCap[ta][outtype] *
|
|
(1.0 - esws->shieldfrac) *
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* 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)
|
|
Tile *tpfar;
|
|
Boundary *bp;
|
|
{
|
|
NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside);
|
|
NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar);
|
|
Tile *tpnear;
|
|
|
|
if (rfar != (NodeRegion *) extUnInit && 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, overlap, sep);
|
|
}
|
|
}
|
|
|
|
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)
|
|
Tile *tpfar;
|
|
Boundary *bp;
|
|
{
|
|
NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside);
|
|
NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar);
|
|
Tile *tpnear;
|
|
|
|
if (rfar != (NodeRegion *) extUnInit && 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, overlap, sep);
|
|
}
|
|
}
|
|
|
|
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)
|
|
Tile *tpfar;
|
|
Boundary *bp;
|
|
{
|
|
NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside);
|
|
NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar);
|
|
Tile *tpnear;
|
|
|
|
if (rfar != (NodeRegion *) extUnInit && 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, overlap, sep);
|
|
}
|
|
}
|
|
|
|
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)
|
|
Tile *tpfar;
|
|
Boundary *bp;
|
|
{
|
|
NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside);
|
|
NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar);
|
|
Tile *tpnear;
|
|
|
|
if (rfar != (NodeRegion *) extUnInit && 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, overlap, sep);
|
|
}
|
|
}
|
|
|
|
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 extUnInit, 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, overlap, sep)
|
|
NodeRegion *rinside, *rfar; /* Both must be valid */
|
|
Tile *tpnear, *tpfar; /* Tiles on near and far side of edge */
|
|
int overlap, sep; /* Overlap of this edge with original one,
|
|
* and distance between the two.
|
|
*/
|
|
{
|
|
TileType near = TiGetType(tpnear), far = TiGetType(tpfar);
|
|
HashEntry *he;
|
|
EdgeCap *e;
|
|
CoupleKey ck;
|
|
CapValue cap;
|
|
|
|
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;
|
|
if (CAP_DEBUG)
|
|
extAdjustCouple(he, (e->ec_cap * overlap) / sep, "sidewall");
|
|
}
|
|
extSetCapValue(he, cap);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extShieldLeft --
|
|
*
|
|
* Searching to the left of the boundary 'bp', we found the tile
|
|
* 'tpfar' which may lie on the far side of an edge to which the
|
|
* edge bp->b_inside | bp->b_outside shields the fringing capacitance.
|
|
*
|
|
* Walk along the right-hand side of 'tpfar' searching for such edges,
|
|
* and recording the amount of shielding in the passed structure.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Updates efss->shieldfrac
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
extShieldLeft(tpfar, efss)
|
|
Tile *tpfar;
|
|
extFringeShieldStruct *efss;
|
|
{
|
|
Boundary *bp = efss->bp;
|
|
Tile *tpnear;
|
|
float fshield; /* fraction shielded for this segment */
|
|
float frac; /* ratio of segment to boundary length */
|
|
|
|
int sep = bp->b_segment.r_xbot - RIGHT(tpfar);
|
|
int limit = MAX(bp->b_segment.r_ybot, BOTTOM(tpfar));
|
|
int start = MIN(bp->b_segment.r_ytop, TOP(tpfar));
|
|
float halo = (float)ExtCurStyle->exts_fringeShieldHalo;
|
|
float fsep = (float)sep;
|
|
|
|
for (tpnear = TR(tpfar); TOP(tpnear) > limit; tpnear = LB(tpnear))
|
|
{
|
|
int overlap = MIN(TOP(tpnear), start) - MAX(BOTTOM(tpnear), limit);
|
|
|
|
if (overlap > 0)
|
|
{
|
|
frac = (float)(bp->b_segment.r_ytop - bp->b_segment.r_ybot) /
|
|
(float)(start - limit);
|
|
/* Use sin() approximation for shielding effect */
|
|
fshield = 1.0 - sin(1.571 * fsep / halo);
|
|
efss->shieldfrac = fshield * frac + efss->shieldfrac * (1.0 - frac);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extShieldRight --
|
|
*
|
|
* Searching to the right of the boundary 'bp', we found the tile
|
|
* 'tpfar' which may lie on the far side of an edge to which the
|
|
* edge bp->b_inside | bp->b_outside shields the fringing capacitance.
|
|
*
|
|
* Walk along the left-hand side of 'tpfar' searching for such edges,
|
|
* and recording the amount of shielding in the passed structure.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Updates efss->shieldfrac
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
extShieldRight(tpfar, efss)
|
|
Tile *tpfar;
|
|
extFringeShieldStruct *efss;
|
|
{
|
|
Boundary *bp = efss->bp;
|
|
Tile *tpnear;
|
|
float fshield; /* fraction shielded for this segment */
|
|
float frac; /* ratio of segment to boundary length */
|
|
|
|
int sep = LEFT(tpfar) - bp->b_segment.r_xtop;
|
|
int limit = MIN(bp->b_segment.r_ytop, TOP(tpfar));
|
|
int start = MAX(bp->b_segment.r_ybot, BOTTOM(tpfar));
|
|
float halo = (float)ExtCurStyle->exts_fringeShieldHalo;
|
|
float fsep = (float)sep;
|
|
|
|
for (tpnear = BL(tpfar); BOTTOM(tpnear) < limit; tpnear = RT(tpnear))
|
|
{
|
|
int overlap = MIN(TOP(tpnear), limit) - MAX(BOTTOM(tpnear), start);
|
|
|
|
if (overlap > 0)
|
|
{
|
|
frac = (float)(bp->b_segment.r_ytop - bp->b_segment.r_ybot) /
|
|
(float)(limit - start);
|
|
/* Use sin() approximation for shielding effect */
|
|
fshield = 1.0 - sin(1.571 * fsep / halo);
|
|
efss->shieldfrac = fshield * frac + efss->shieldfrac * (1.0 - frac);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extShieldTop --
|
|
*
|
|
* Searching to the top of the boundary 'bp', we found the tile
|
|
* 'tpfar' which may lie on the far side of an edge to which the
|
|
* edge bp->b_inside | bp->b_outside shields the fringing capacitance.
|
|
*
|
|
* Walk along the bottom side of 'tpfar' searching for such edges,
|
|
* and recording the amount of shielding in the passed structure.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Updates efss->shieldfrac
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
extShieldTop(tpfar, efss)
|
|
Tile *tpfar;
|
|
extFringeShieldStruct *efss;
|
|
{
|
|
Boundary *bp = efss->bp;
|
|
Tile *tpnear;
|
|
float fshield; /* fraction shielded for this segment */
|
|
float frac; /* ratio of segment to boundary length */
|
|
|
|
int sep = BOTTOM(tpfar) - bp->b_segment.r_ytop;
|
|
int limit = MIN(bp->b_segment.r_xtop, RIGHT(tpfar));
|
|
int start = MAX(bp->b_segment.r_xbot, LEFT(tpfar));
|
|
float halo = (float)ExtCurStyle->exts_fringeShieldHalo;
|
|
float fsep = (float)sep;
|
|
|
|
for (tpnear = LB(tpfar); LEFT(tpnear) < limit; tpnear = TR(tpnear))
|
|
{
|
|
int overlap = MIN(RIGHT(tpnear), limit) - MAX(LEFT(tpnear), start);
|
|
|
|
if (overlap > 0)
|
|
{
|
|
frac = (float)(bp->b_segment.r_xtop - bp->b_segment.r_xbot) /
|
|
(float)(limit - start);
|
|
/* Use sin() approximation for shielding effect */
|
|
fshield = 1.0 - sin(1.571 * fsep / halo);
|
|
efss->shieldfrac = fshield * frac + efss->shieldfrac * (1.0 - frac);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extShieldBottom --
|
|
*
|
|
* Searching to the bottom of the boundary 'bp', we found the tile
|
|
* 'tpfar' which may lie on the far side of an edge to which the
|
|
* edge bp->b_inside | bp->b_outside shields the fringing capacitance.
|
|
*
|
|
* Walk along the top side of 'tpfar' searching for such
|
|
* and recording the amount of shielding in the passed structure.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Updates efss->shieldfrac
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
extShieldBottom(tpfar, efss)
|
|
Tile *tpfar;
|
|
extFringeShieldStruct *efss;
|
|
{
|
|
Boundary *bp = efss->bp;
|
|
Tile *tpnear;
|
|
float fshield; /* fraction shielded for this segment */
|
|
float frac; /* ratio of segment to boundary length */
|
|
|
|
int sep = bp->b_segment.r_ybot - TOP(tpfar);
|
|
int limit = MAX(bp->b_segment.r_xbot, LEFT(tpfar));
|
|
int start = MIN(bp->b_segment.r_xtop, RIGHT(tpfar));
|
|
float halo = (float)ExtCurStyle->exts_fringeShieldHalo;
|
|
float fsep = (float)sep;
|
|
|
|
for (tpnear = RT(tpfar); RIGHT(tpnear) > limit; tpnear = BL(tpnear))
|
|
{
|
|
int overlap = MIN(RIGHT(tpnear), start) - MAX(LEFT(tpnear), limit);
|
|
|
|
if (overlap > 0)
|
|
{
|
|
frac = (float)(bp->b_segment.r_xtop - bp->b_segment.r_xbot) /
|
|
(float)(start - limit);
|
|
/* Use sin() approximation for shielding effect */
|
|
fshield = 1.0 - sin(1.571 * fsep / halo);
|
|
efss->shieldfrac = fshield * frac + efss->shieldfrac * (1.0 - frac);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|