535 lines
13 KiB
C
535 lines
13 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"
|
|
|
|
/*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
* resMakePortBreakpoints --
|
|
*
|
|
* Generate new nodes and breakpoints for every unused port declared
|
|
* on a tile. However, if "startpoint" is inside the port position,
|
|
* then it has already been processed, so ignore it.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Adds breakpoints where ports (drivers, sinks, or labels) have been
|
|
* defined as connected to the tile.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
resMakePortBreakpoints(tile, list)
|
|
Tile *tile;
|
|
resNode **list;
|
|
{
|
|
int x, y;
|
|
resNode *resptr;
|
|
resPort *pl;
|
|
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
|
ResConnect *connect;
|
|
|
|
free_magic1_t mm1 = freeMagic1_init();
|
|
for (pl = info->portList; pl; pl = pl->rp_nextPort)
|
|
{
|
|
x = pl->rp_loc.p_x;
|
|
y = pl->rp_loc.p_y;
|
|
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
|
InitializeResNode(resptr, x, y, RES_NODE_ORIGIN);
|
|
resptr->rn_status = TRUE;
|
|
resptr->rn_noderes = 0;
|
|
resptr->rn_name = pl->rp_nodename;
|
|
|
|
/* Link back to the resnode from the ResConnect record */
|
|
connect = pl->rp_connect;
|
|
connect->rc_node = resptr;
|
|
|
|
ResAddToQueue(resptr, list);
|
|
ResNewBreak(resptr, tile, x, y, NULL);
|
|
freeMagic1(&mm1, pl);
|
|
}
|
|
freeMagic1_end(&mm1);
|
|
}
|
|
|
|
/*
|
|
* Structure used by ResEachTile for the callback to ResMultiPlaneFunc()
|
|
* to pass a pointer to the tile being processed, and the terminal being
|
|
* searched.
|
|
*/
|
|
|
|
typedef struct tile_and_term
|
|
{
|
|
Tile *tat_tile;
|
|
int tat_term;
|
|
} TileAndTerm;
|
|
|
|
/*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
* 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, dinfo, tat)
|
|
Tile *tile;
|
|
TileType dinfo; /* Not used, but needs to be handled */
|
|
TileAndTerm *tat;
|
|
{
|
|
Tile *tp = tat->tat_tile;
|
|
int term = tat->tat_term;
|
|
int xj, yj;
|
|
|
|
/* Simplified split tile handling---Ignore the right side of
|
|
* tiles that have non-space types on both sides.
|
|
*/
|
|
if (IsSplit(tile))
|
|
if (TiGetLeftType(tile) != TT_SPACE && TiGetRightType(tile) != TT_SPACE)
|
|
if (dinfo & TT_SIDE)
|
|
return 0;
|
|
|
|
xj = (LEFT(tile) + RIGHT(tile)) / 2;
|
|
yj = (TOP(tile) + BOTTOM(tile)) / 2;
|
|
ResNewTermDevice(tp, tile, term, 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, dinfo, tpptr)
|
|
Tile *tile;
|
|
TileType dinfo;
|
|
Tile **tpptr;
|
|
{
|
|
Tile *tp = *tpptr;
|
|
int xj, yj;
|
|
|
|
/* Simplified split tile handling---Ignore the right side of
|
|
* tiles that have non-space types on both sides.
|
|
*/
|
|
if (IsSplit(tile))
|
|
if (TiGetLeftType(tile) != TT_SPACE && TiGetRightType(tile) != TT_SPACE)
|
|
if (dinfo & TT_SIDE)
|
|
return 0;
|
|
|
|
xj = (LEFT(tile) + RIGHT(tile)) / 2;
|
|
yj = (TOP(tile) + BOTTOM(tile)) / 2;
|
|
ResNewSubDevice(tp, tile, xj, yj, OTHERPLANE, &ResNodeQueue);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
* ResStartTile --
|
|
*
|
|
* For the tile at the starting point of the net, create an initial
|
|
* resNode entry.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* creates a node.
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResStartTile(tile, x, y)
|
|
Tile *tile;
|
|
int x, y;
|
|
|
|
{
|
|
resNode *resptr;
|
|
|
|
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
|
InitializeResNode(resptr, x, y, RES_NODE_ORIGIN);
|
|
resptr->rn_status = TRUE;
|
|
resptr->rn_noderes = 0;
|
|
ResAddToQueue(resptr, &ResNodeQueue);
|
|
ResNewBreak(resptr, tile, x, y, NULL);
|
|
if (resCurrentNode == NULL) resCurrentNode = resptr;
|
|
}
|
|
|
|
/*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
* 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.
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
|
|
#define IGNORE_LEFT 1
|
|
#define IGNORE_RIGHT 2
|
|
#define IGNORE_TOP 4
|
|
#define IGNORE_BOTTOM 8
|
|
|
|
bool
|
|
ResEachTile(tile)
|
|
Tile *tile;
|
|
{
|
|
Tile *tp;
|
|
resNode *resptr;
|
|
cElement *ce;
|
|
TileType t1, t2;
|
|
int xj, yj, i;
|
|
bool merged;
|
|
tElement *tcell;
|
|
resInfo *tstructs = (resInfo *)TiGetClientPTR(tile);
|
|
ExtDevice *devptr;
|
|
int sides;
|
|
|
|
ResTileCount++;
|
|
|
|
/* Simplification: Split tiles handle either the non-space side,
|
|
* or if neither side is space, then handle the left side.
|
|
*/
|
|
if (IsSplit(tile))
|
|
{
|
|
if (TiGetLeftType(tile) == TT_SPACE)
|
|
{
|
|
t1 = SplitRightType(tile);
|
|
sides = IGNORE_LEFT;
|
|
sides |= (SplitDirection(tile)) ? IGNORE_BOTTOM : IGNORE_TOP;
|
|
}
|
|
else
|
|
{
|
|
t1 = SplitLeftType(tile);
|
|
sides = IGNORE_RIGHT;
|
|
sides |= (SplitDirection(tile)) ? IGNORE_TOP : IGNORE_BOTTOM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sides = 0;
|
|
t1 = TiGetTypeExact(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->ri_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;
|
|
|
|
InitializeResNode(resptr, x, y, RES_NODE_JUNCTION);
|
|
resptr->rn_te = tcell;
|
|
ResAddToQueue(resptr, &ResNodeQueue);
|
|
ResNewBreak(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 */
|
|
if (!(sides & IGNORE_LEFT))
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
|
{
|
|
t2 = TiGetRightType(tp);
|
|
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2))
|
|
{
|
|
for (devptr = ExtCurStyle->exts_device[t2]; devptr;
|
|
devptr = devptr->exts_next)
|
|
{
|
|
for (i = 0; i < devptr->exts_deviceSDCount; i++)
|
|
{
|
|
if (TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t1))
|
|
{
|
|
/* found device */
|
|
xj = LEFT(tile);
|
|
yj = (TOP(tp) + BOTTOM(tp)) >> 1;
|
|
ResNewTermDevice(tile, tp, i, xj, yj, RIGHTEDGE, &ResNodeQueue);
|
|
break;
|
|
}
|
|
}
|
|
if (i < devptr->exts_deviceSDCount) break;
|
|
}
|
|
}
|
|
if (TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2))
|
|
{
|
|
/* tile is junction */
|
|
xj = LEFT(tile);
|
|
yj = (MAX(BOTTOM(tile), BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1;
|
|
(void) ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
|
|
}
|
|
}
|
|
|
|
/* right */
|
|
if (!(sides & IGNORE_RIGHT))
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
|
{
|
|
t2 = TiGetLeftType(tp);
|
|
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2))
|
|
{
|
|
for (devptr = ExtCurStyle->exts_device[t2]; devptr;
|
|
devptr = devptr->exts_next)
|
|
{
|
|
for (i = 0; i < devptr->exts_deviceSDCount; i++)
|
|
{
|
|
if (TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t1))
|
|
{
|
|
/* found device */
|
|
xj = RIGHT(tile);
|
|
yj = (TOP(tp) + BOTTOM(tp)) >> 1;
|
|
ResNewTermDevice(tile, tp, i, xj, yj, LEFTEDGE, &ResNodeQueue);
|
|
break;
|
|
}
|
|
}
|
|
if (i < devptr->exts_deviceSDCount) break;
|
|
}
|
|
}
|
|
if (TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2))
|
|
{
|
|
/* tile is junction */
|
|
xj = RIGHT(tile);
|
|
yj = (MAX(BOTTOM(tile), BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1;
|
|
(void)ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
|
|
}
|
|
}
|
|
|
|
/* top */
|
|
if (!(sides & IGNORE_TOP))
|
|
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
|
{
|
|
t2 = TiGetBottomType(tp);
|
|
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2))
|
|
{
|
|
for (devptr = ExtCurStyle->exts_device[t2]; devptr;
|
|
devptr = devptr->exts_next)
|
|
{
|
|
for (i = 0; i < devptr->exts_deviceSDCount; i++)
|
|
{
|
|
if (TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t1))
|
|
{
|
|
/* found device */
|
|
yj = TOP(tile);
|
|
xj = (LEFT(tp) + RIGHT(tp)) >> 1;
|
|
ResNewTermDevice(tile, tp, i, xj, yj, BOTTOMEDGE, &ResNodeQueue);
|
|
break;
|
|
}
|
|
}
|
|
if (i < devptr->exts_deviceSDCount) break;
|
|
}
|
|
}
|
|
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 */
|
|
if (!(sides & IGNORE_BOTTOM))
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
|
{
|
|
t2 = TiGetTopType(tp);
|
|
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2))
|
|
{
|
|
for (devptr = ExtCurStyle->exts_device[t2]; devptr;
|
|
devptr = devptr->exts_next)
|
|
{
|
|
for (i = 0; i < devptr->exts_deviceSDCount; i++)
|
|
{
|
|
if (TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t1))
|
|
{
|
|
/* found device */
|
|
yj = BOTTOM(tile);
|
|
xj = (LEFT(tp) + RIGHT(tp)) >> 1;
|
|
ResNewTermDevice(tile, tp, i, xj, yj, TOPEDGE, &ResNodeQueue);
|
|
break;
|
|
}
|
|
}
|
|
if (i < devptr->exts_deviceSDCount) break;
|
|
}
|
|
}
|
|
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 terminals on other planes (e.g., capacitors, bipolars, ...) */
|
|
|
|
if (TTMaskHasType(&ResTermTypesBitMask, t1))
|
|
{
|
|
Rect r;
|
|
int pNum;
|
|
TileTypeBitMask devMask;
|
|
TileAndTerm tat;
|
|
|
|
TiToRect(tile, &r);
|
|
|
|
for (pNum = 0; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
if (DBTypeOnPlane(t1, pNum)) continue;
|
|
|
|
for (devptr = ExtCurStyle->exts_device[t2]; devptr;
|
|
devptr = devptr->exts_next)
|
|
{
|
|
for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
|
|
{
|
|
/* Check if any type in the terminal type list exists on this
|
|
* plane before calling the search function.
|
|
*/
|
|
TileTypeBitMask termtypes;
|
|
|
|
TTMaskAndMask3(&termtypes, &devptr->exts_deviceSDTypes[i],
|
|
&DBPlaneTypes[pNum]);
|
|
|
|
if (TTMaskIsZero(&termtypes))
|
|
{
|
|
tat.tat_tile = tile;
|
|
tat.tat_term = i;
|
|
DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum],
|
|
&r, &devptr->exts_deviceSDTypes[i],
|
|
ResMultiPlaneFunc, (ClientData)&tat);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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->ri_status |= RES_TILE_DONE;
|
|
|
|
resMakePortBreakpoints(tile, &ResNodeQueue);
|
|
|
|
merged = ResCalcTileResistance(tile, tstructs, &ResNodeQueue,
|
|
&ResNodeList);
|
|
|
|
return(merged);
|
|
}
|