mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-05 00:50:50 +02:00
simple FET device in extresist. Also: Extended the bloat-all CIF operator again, allowing the trigger layer for the bloat operation to include both CIF layers and magic layers (previously only magic layers were supported). This extension is possible due to the previous extension allowing the trigger layer and bloating layers to be on separate planes. This operator extension is useful for tagging geometry that is in the proximity of, but not overlapping, geometry on another plane.
392 lines
10 KiB
C
392 lines
10 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);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
* 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 nextwork 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef ARIEL
|
|
if (i = ExtCurStyle->exts_plugSignalNum[t1])
|
|
{
|
|
tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
|
|
|
|
tcell->te_thist= ResImageAddPlug(tile, i, resCurrentNode);
|
|
tcell->te_nextt = resCurrentNode->rn_te;
|
|
resCurrentNode->rn_te = tcell;
|
|
}
|
|
if (TTMaskHasType(&ResSubsTypeBitMask,t1) &&
|
|
(ResOptionsFlags & ResOpt_DoSubstrate))
|
|
{
|
|
int pNum;
|
|
Rect tileArea;
|
|
TileTypeBitMask *mask = &ExtCurStyle->exts_subsTransistorTypes[t1];
|
|
|
|
TiToRect(tile,&tileArea);
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
if (TTMaskIntersect(&DBPlaneTypes[pNum], mask))
|
|
{
|
|
(void)DBSrPaintArea((Tile *) NULL,
|
|
ResUse->cu_def->cd_planes[pNum],
|
|
&tileArea, mask, resSubDevFunc, (ClientData) tile);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
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;
|
|
}
|