mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-29 17:39:28 +02:00
causing the SI suffix not to be the expected one. Adjusted the bounds where each SI suffix is used to keep output in the range of 0.1 to 100, although the boundary is very subjective. Made a correction to the extresist code to scan through all device records for a tile type. However, (1) there are cases being missed, and (2) this should not be necessary since all device types should be able to be known exactly from the contents of the .sim file. Needs more work.
479 lines
12 KiB
C
479 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"
|
|
|
|
/*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
* 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);
|
|
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;
|
|
ResNewSDDevice(tile, tp, 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 */
|
|
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;
|
|
ResNewSDDevice(tile, tp, 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 */
|
|
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;
|
|
ResNewSDDevice(tile, tp, 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 */
|
|
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;
|
|
ResNewSDDevice(tile, tp, 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 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);
|
|
}
|