Files
magic/resis/ResBasic.c
T
Tim Edwards 0bb6ac1fa9 Modified the extresist code to handle substrate extraction. Currently
this appears to work correctly but does not yet handle the implicit
substrate (space as substrate) or "virtually" isolated substrate regions
(which need to be removed for full parasitic extraction).
2021-09-15 16:25:46 -04:00

485 lines
12 KiB
C

#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResBasic.c,v 1.3 2010/06/24 12:37:56 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#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 "utils/malloc.h"
#include "textio/textio.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/tech.h"
#include "textio/txcommands.h"
#include "resis/resis.h"
int resSubDevFunc();
/*
*--------------------------------------------------------------------------
*
* resNodeIsPort --
*
* If the given position is inside any port declared on the tile,
* change the node name to the port name. Remove the port
* declaration if it was used.
*
*--------------------------------------------------------------------------
*/
void
resNodeIsPort(node, x, y, tile)
resNode *node;
int x;
int y;
Tile *tile;
{
Rect *rect;
Point p;
resPort *pl, *lp;
tileJunk *junk = (tileJunk *)(tile->ti_client);
p.p_x = x;
p.p_y = y;
for (pl = junk->portList; pl; pl = pl->rp_nextPort)
{
rect = &(pl->rp_bbox);
if (GEO_ENCLOSE(&p, rect))
{
node->rn_name = pl->rp_nodename;
if (junk->portList == pl)
junk->portList = pl->rp_nextPort;
else
{
for (lp = junk->portList; lp && (lp->rp_nextPort != pl);
lp = lp->rp_nextPort);
lp->rp_nextPort = pl->rp_nextPort;
}
freeMagic(pl);
break;
}
}
}
/*
*--------------------------------------------------------------------------
*
* resAllPortNodes --
*
* Generate new nodes and breakpoints for every unused port declared
* on a tile.
*
*--------------------------------------------------------------------------
*/
void
resAllPortNodes(tile, list)
Tile *tile;
resNode **list;
{
int x, y;
resNode *resptr;
resPort *pl;
tileJunk *junk = (tileJunk *)(tile->ti_client);
for (pl = junk->portList; pl; pl = pl->rp_nextPort)
{
x = pl->rp_loc.p_x;
y = pl->rp_loc.p_y;
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
resptr->rn_status = TRUE;
resptr->rn_noderes = 0;
resptr->rn_name = pl->rp_nodename;
ResAddToQueue(resptr, list);
NEWBREAK(resptr, tile, x, y, NULL);
freeMagic(pl);
}
}
/*
*--------------------------------------------------------------------------
*
* ResMultiPlaneFunc---
*
* If device is found overlapping one of its source/drain types, then
* generate a new device at the center of the tile and add to ResNodeQueue.
*
* Results:
* Always 0 to keep the search going.
*
* Side effects:
* Adds to ResNodeQueue
*
*--------------------------------------------------------------------------
*/
int
ResMultiPlaneFunc(tile, tpptr)
Tile *tile, **tpptr;
{
Tile *tp = *tpptr;
int xj, yj;
xj = (LEFT(tile) + RIGHT(tile)) / 2;
yj = (TOP(tile) + BOTTOM(tile)) / 2;
ResNewSDDevice(tp, tile, xj, yj, OTHERPLANE, &ResNodeQueue);
return 0;
}
/*
*--------------------------------------------------------------------------
*
* ResSubstrateFunc---
*
* If device is found overlapping its substrate type, then generate a new
* device at the center of the tile and add to ResNodeQueue.
*
* Results:
* Always 0 to keep the search going.
*
* Side effects:
* Adds to ResNodeQueue
*
*--------------------------------------------------------------------------
*/
int
ResSubstrateFunc(tile, tpptr)
Tile *tile, **tpptr;
{
Tile *tp = *tpptr;
int xj, yj;
xj = (LEFT(tile) + RIGHT(tile)) / 2;
yj = (TOP(tile) + BOTTOM(tile)) / 2;
ResNewSubDevice(tp, tile, xj, yj, OTHERPLANE, &ResNodeQueue);
return 0;
}
/*
*--------------------------------------------------------------------------
*
* ResEachTile--for each tile, make a list of all possible current sources/
* sinks including contacts, devices, and junctions. Once this
* list is made, calculate the resistor network for the tile.
*
* Results: returns TRUE or FALSE depending on whether a node was
* involved in a merge.
*
* Side Effects: creates Nodes, devices, junctions, and breakpoints.
*
*
*--------------------------------------------------------------------------
*/
bool
ResEachTile(tile, startpoint)
Tile *tile;
Point *startpoint;
{
Tile *tp;
resNode *resptr;
cElement *ce;
TileType t1, t2;
int xj, yj, i;
bool merged;
tElement *tcell;
tileJunk *tstructs= (tileJunk *)(tile->ti_client);
ExtDevice *devptr;
ResTileCount++;
/* Process startpoint, if any. */
if (IsSplit(tile))
{
t1 = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
}
else
t1 = TiGetTypeExact(tile);
if (startpoint != (Point *) NULL)
{
int x = startpoint->p_x;
int y = startpoint->p_y;
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
resptr->rn_status = TRUE;
resptr->rn_noderes = 0;
ResAddToQueue(resptr, &ResNodeQueue);
NEWBREAK(resptr, tile, x, y, NULL);
resCurrentNode = resptr;
resNodeIsPort(resptr, x, y, tile);
}
if TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t1)
{
/*
* The device is put in the center of the tile. This is fine
* for single tile device, but not as good for multiple ones.
*/
if (tstructs->tj_status & RES_TILE_DEV)
{
if (tstructs->deviceList->rd_fet_gate == NULL)
{
int x = (LEFT(tile) + RIGHT(tile)) >> 1;
int y = (TOP(tile) + BOTTOM(tile)) >> 1;
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
tstructs->deviceList->rd_fet_gate = resptr;
tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
tcell->te_thist = tstructs->deviceList;
tcell->te_nextt = NULL;
InitializeNode(resptr, x, y, RES_NODE_JUNCTION);
resptr->rn_te = tcell;
ResAddToQueue(resptr, &ResNodeQueue);
resNodeIsPort(resptr, x, y, tile);
NEWBREAK(resptr, tile, resptr->rn_loc.p_x,
resptr->rn_loc.p_y, NULL);
}
}
}
/* Process all the contact points */
ce = tstructs->contactList;
while (ce != (cElement *) NULL)
{
ResContactPoint *cp = ce->ce_thisc;
cElement *oldce;
if (cp->cp_cnode[0] == (resNode *) NULL)
{
ResDoContacts(cp, &ResNodeQueue, &ResResList);
}
oldce = ce;
ce = ce->ce_nextc;
freeMagic((char *)oldce);
}
tstructs->contactList = NULL;
/*
* Walk the four sides of the tile looking for adjoining connecting
* materials.
*/
/* left */
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
{
t2 = TiGetRightType(tp);
devptr = ExtCurStyle->exts_device[t2];
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
/* found device */
{
xj = LEFT(tile);
yj = (TOP(tp) + BOTTOM(tp)) >> 1;
ResNewSDDevice(tile, tp, xj, yj, RIGHTEDGE, &ResNodeQueue);
}
if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
/* tile is junction */
{
/*junction rn_loc */
xj = LEFT(tile);
yj = (MAX(BOTTOM(tile), BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1;
(void) ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
}
}
/* right */
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp))
{
t2 = TiGetLeftType(tp);
devptr = ExtCurStyle->exts_device[t2];
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
/* found device */
{
xj = RIGHT(tile);
yj = (TOP(tp)+BOTTOM(tp))>>1;
ResNewSDDevice(tile, tp, xj, yj, LEFTEDGE, &ResNodeQueue);
}
if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)
/* tile is junction */
{
/*junction rn_loc */
xj = RIGHT(tile);
yj = (MAX(BOTTOM(tile),BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1;
(void)ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
}
}
/* top */
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp=BL(tp))
{
t2 = TiGetBottomType(tp);
devptr = ExtCurStyle->exts_device[t2];
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
/* found device */
{
yj = TOP(tile);
xj = (LEFT(tp)+RIGHT(tp))>>1;
ResNewSDDevice(tile, tp, xj, yj, BOTTOMEDGE, &ResNodeQueue);
}
if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1],t2)
/* tile is junction */
{
yj = TOP(tile);
xj = (MAX(LEFT(tile),LEFT(tp)) + MIN(RIGHT(tile),RIGHT(tp))) >> 1;
ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
}
}
/* bottom */
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
{
t2 = TiGetTopType(tp);
devptr = ExtCurStyle->exts_device[t2];
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
/* found device */
{
yj = BOTTOM(tile);
xj = (LEFT(tp) + RIGHT(tp)) >> 1;
ResNewSDDevice(tile, tp, xj, yj, TOPEDGE, &ResNodeQueue);
}
if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
/* tile is junction */
{
yj = BOTTOM(tile);
xj = (MAX(LEFT(tile),LEFT(tp)) + MIN(RIGHT(tile),RIGHT(tp))) >> 1;
ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
}
}
/* Check for source/drain on other planes (e.g., capacitors, bipolars, ...) */
if (TTMaskHasType(&ResSDTypesBitMask, t1))
{
Rect r;
int pNum;
TileTypeBitMask devMask;
TiToRect(tile, &r);
for (pNum = 0; pNum < DBNumPlanes; pNum++)
{
if (DBTypeOnPlane(t1, pNum)) continue;
/* NOTE: This is ridiculously inefficient and should be done
* in a different way.
*/
TTMaskZero(&devMask);
for (t2 = TT_TECHDEPBASE; t2 < DBNumUserLayers; t2++)
for (devptr = ExtCurStyle->exts_device[t2]; devptr;
devptr = devptr->exts_next)
for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
if (TTMaskHasType(&devptr->exts_deviceSDTypes[i], t1))
TTMaskSetType(&devMask, t2);
DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum],
&r, &devMask, ResMultiPlaneFunc, (ClientData)&tile);
}
}
/* Check for substrate under device */
if (TTMaskHasType(&ResSubTypesBitMask, t1))
{
Rect r;
int pNum;
TileTypeBitMask devMask;
TiToRect(tile, &r);
for (pNum = 0; pNum < DBNumPlanes; pNum++)
{
if (DBTypeOnPlane(t1, pNum)) continue;
/* NOTE: This is ridiculously inefficient and should be done
* in a different way.
*/
TTMaskZero(&devMask);
for (t2 = TT_TECHDEPBASE; t2 < DBNumUserLayers; t2++)
for (devptr = ExtCurStyle->exts_device[t2]; devptr;
devptr = devptr->exts_next)
if (TTMaskHasType(&devptr->exts_deviceSubstrateTypes, t1))
TTMaskSetType(&devMask, t2);
DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum],
&r, &devMask, ResSubstrateFunc, (ClientData)&tile);
}
}
tstructs->tj_status |= RES_TILE_DONE;
resAllPortNodes(tile, &ResNodeQueue);
merged = ResCalcTileResistance(tile, tstructs, &ResNodeQueue,
&ResNodeList);
return(merged);
}
/*
*-------------------------------------------------------------------------
*
* resSubDevFunc -- called when DBSrPaintArea finds a device within
* a substrate area.
*
* Results: always returns 0 to keep search going.
*
* Side Effects: allocates substrate node.
*
*-------------------------------------------------------------------------
*/
int
resSubDevFunc(tile, tp)
Tile *tile, *tp;
{
tileJunk *junk = (tileJunk *)(tile->ti_client);
resNode *resptr;
tElement *tcell;
int x, y;
if (junk->deviceList->rd_fet_subs == NULL)
{
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
junk->deviceList->rd_fet_subs = resptr;
junk->tj_status |= RES_TILE_DEV;
tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
tcell->te_thist = junk->deviceList;
tcell->te_nextt = NULL;
x = (LEFT(tile) + RIGHT(tile)) >> 1;
y = (TOP(tile) + BOTTOM(tile)) >> 1;
InitializeNode(resptr, x, y, RES_NODE_JUNCTION);
resptr->rn_te = tcell;
ResAddToQueue(resptr, &ResNodeQueue);
NEWBREAK(resptr, tp, x, y, NULL);
}
return 0;
}