magic/resis/ResUtils.c

736 lines
18 KiB
C

#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResUtils.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/stack.h"
#include "utils/tech.h"
#include "textio/txcommands.h"
#include "resis/resis.h"
/*
* ---------------------------------------------------------------------------
*
* ResFirst -- Checks to see if tile is a contact. If it is, allocate a
* contact structure.
*
*
* Results: Always returns NULL (in the form of a Region pointer)
*
* Side effects:
* Memory is allocated by ResFirst.
* We cons the newly allocated region onto the front of the existing
* region list.
*
*
* -------------------------------------------------------------------------
*/
Region *
ResFirst(tile, arg)
Tile *tile;
FindRegion *arg;
{
ResContactPoint *reg;
TileType t;
int i;
if (IsSplit(tile))
{
t = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
}
else
t = TiGetType(tile);
if (DBIsContact(t))
{
reg = (ResContactPoint *) mallocMagic((unsigned) (sizeof(ResContactPoint)));
reg->cp_center.p_x = (LEFT(tile)+RIGHT(tile))>>1;
reg->cp_center.p_y = (TOP(tile)+BOTTOM(tile))>>1;
reg->cp_status = FALSE;
reg->cp_type = t;
reg->cp_width = RIGHT(tile)-LEFT(tile);
reg->cp_height = TOP(tile)-BOTTOM(tile);
for (i=0; i< LAYERS_PER_CONTACT; i++)
{
reg->cp_tile[i] = (Tile *) NULL;
reg->cp_cnode[i] = (resNode *) NULL;
}
reg->cp_currentcontact = 0;
reg->cp_rect.r_ll.p_x = tile->ti_ll.p_x;
reg->cp_rect.r_ll.p_y = tile->ti_ll.p_y;
reg->cp_rect.r_ur.p_x = RIGHT(tile);
reg->cp_rect.r_ur.p_y = TOP(tile);
reg->cp_contactTile = tile;
/* Prepend it to the region list */
reg->cp_nextcontact = (ResContactPoint *) arg->fra_region;
arg->fra_region = (Region *) reg;
}
return((Region *) NULL);
}
/*
*--------------------------------------------------------------------------
*
* ResEach--
*
* ResEach calls ResFirst unless this is the first contact, in which case it
* has alreay been processed
*
* results: returns 0
*
* Side Effects: see ResFirst
*
* -------------------------------------------------------------------------
*/
int
ResEach(tile, pNum, arg)
Tile *tile;
int pNum;
FindRegion *arg;
{
if ( ((ResContactPoint *)(arg->fra_region))->cp_contactTile != tile)
{
(void) ResFirst(tile, arg);
}
return(0);
}
/*
*-------------------------------------------------------------------------
*
* ResAddPlumbing-- Each tile is a tileJunk structure associated with it
* to keep track of various things used by the extractor. ResAddPlumbing
* adds this structure and sets the tile's ClientData field to point to it.
* If the tile is a device, then a device structure is also added;
* all connected device tiles are enumerated and their deviceList
* fields set to the new structure.
*
* Results: always returns 0
*
* Side Effects:see above
*
*-------------------------------------------------------------------------
*/
int
ResAddPlumbing(tile, arg)
Tile *tile;
ClientData *arg;
{
tileJunk *Junk,*junk2;
static Stack *resDevStack=NULL;
TileType loctype, t1;
Tile *tp1,*tp2,*source;
resDevice *resDev;
ExtDevice *devptr;
if (resDevStack == NULL)
resDevStack = StackNew(64);
if (tile->ti_client == (ClientData) CLIENTDEFAULT)
{
if (IsSplit(tile))
loctype = (SplitSide(tile)) ? SplitRightType(tile) :
SplitLeftType(tile);
else
loctype = TiGetTypeExact(tile);
devptr = ExtCurStyle->exts_device[loctype];
junk2 = resAddField(tile);
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), loctype))
{
int i, nterms;
/* Count SD terminals of the device */
nterms = 0;
for (i = 0; ; i++)
{
if (TTMaskIsZero(&(devptr->exts_deviceSDTypes[i]))) break;
nterms++;
}
if (nterms < devptr->exts_deviceSDCount)
nterms = devptr->exts_deviceSDCount;
/* resDev terminals includes device identifier (e.g., gate) and
* substrate, so add two to nterms.
*/
nterms += 2;
resDev = (resDevice *) mallocMagic((unsigned)(sizeof(resDevice)));
resDev->rd_nterms = nterms;
resDev->rd_terminals = (resNode **) mallocMagic(nterms * sizeof(resNode *));
for (i=0; i != nterms;i++)
resDev->rd_terminals[i] = (resNode *) NULL;
resDev->rd_tile = tile;
resDev->rd_inside.r_ll.p_x = LEFT(tile);
resDev->rd_inside.r_ll.p_y = BOTTOM(tile);
resDev->rd_inside.r_ur.p_x = RIGHT(tile);
resDev->rd_inside.r_ur.p_y = TOP(tile);
resDev->rd_devtype = loctype;
resDev->rd_tiles = 0;
resDev->rd_length = 0;
resDev->rd_width = 0;
resDev->rd_perim = 0;
resDev->rd_area = 0;
resDev->rd_status = 0;
resDev->rd_nextDev = (resDevice *) *arg;
*arg = (ClientData)resDev;
junk2->deviceList = resDev;
junk2->tj_status |= RES_TILE_DEV;
source = NULL;
/* find diffusion (if present) to be source contact */
/* top */
for (tp2= RT(tile); RIGHT(tp2) > LEFT(tile); tp2 = BL(tp2))
{
if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetBottomType(tp2))
{
junk2->sourceEdge |= TOPEDGE;
source = tp2;
Junk = resAddField(source);
Junk->tj_status |= RES_TILE_SD;
break;
}
}
/*bottom*/
if (source == NULL)
for (tp2= LB(tile); LEFT(tp2) < RIGHT(tile); tp2 = TR(tp2))
{
if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetTopType(tp2))
{
junk2->sourceEdge |= BOTTOMEDGE;
source = tp2;
Junk = resAddField(source);
Junk->tj_status |= RES_TILE_SD;
break;
}
}
/*right*/
if (source == NULL)
for (tp2= TR(tile); TOP(tp2) > BOTTOM(tile); tp2 = LB(tp2))
{
if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetLeftType(tp2))
{
junk2->sourceEdge |= RIGHTEDGE;
source = tp2;
Junk = resAddField(source);
Junk->tj_status |= RES_TILE_SD;
break;
}
}
/*left*/
if (source == NULL)
for (tp2= BL(tile); BOTTOM(tp2) < TOP(tile); tp2 = RT(tp2))
{
if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetRightType(tp2))
{
source = tp2;
Junk = resAddField(source);
Junk->tj_status |= RES_TILE_SD;
junk2->sourceEdge |= LEFTEDGE;
break;
}
}
/* We need to know whether a given diffusion tile connects to
* the source or to the drain of a device. A single
* diffusion tile is marked, and all connecting diffusion tiles
* are enumerated and called the source. Any other SD tiles
* are assumed to be the drain. BUG: this does not work
* correctly with multi SD structures.
*/
if (source != (Tile *) NULL)
{
STACKPUSH((ClientData) (source),resDevStack);
}
while (!StackEmpty(resDevStack))
{
tp1 = (Tile *) STACKPOP(resDevStack);
if (IsSplit(tp1))
{
t1 = (SplitSide(tp1)) ? SplitRightType(tp1) :
SplitLeftType(tp1);
}
else
t1 = TiGetTypeExact(tp1);
/* top */
for (tp2= RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2))
{
if (TiGetBottomType(tp2) == t1)
{
tileJunk *j= resAddField(tp2);
if ((j->tj_status & RES_TILE_SD) ==0)
{
j->tj_status |= RES_TILE_SD;
STACKPUSH((ClientData)tp2,resDevStack);
}
}
}
/*bottom*/
for (tp2= LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2))
{
if (TiGetTopType(tp2) == t1)
{
tileJunk *j= resAddField(tp2);
if ((j->tj_status & RES_TILE_SD) == 0)
{
j->tj_status |= RES_TILE_SD;
STACKPUSH((ClientData) (tp2),resDevStack);
}
}
}
/*right*/
for (tp2= TR(tp1); TOP(tp2) > BOTTOM(tp1); tp2 = LB(tp2))
{
if (TiGetLeftType(tp2) == t1)
{
tileJunk *j= resAddField(tp2);
if ((j->tj_status & RES_TILE_SD) == 0)
{
j->tj_status |= RES_TILE_SD;
STACKPUSH((ClientData) (tp2),resDevStack);
}
}
}
/*left*/
for (tp2= BL(tp1); BOTTOM(tp2) < TOP(tp1); tp2 = RT(tp2))
{
if (TiGetRightType(tp2) == t1)
{
tileJunk *j= resAddField(tp2);
if ((j->tj_status & RES_TILE_SD) == 0)
{
j->tj_status |= RES_TILE_SD;
STACKPUSH((ClientData) (tp2),resDevStack);
}
}
}
}
/* find rest of device; search for source edges */
STACKPUSH((ClientData) (tile), resDevStack);
while (!StackEmpty(resDevStack))
{
tileJunk *j0;
tp1= (Tile *) STACKPOP(resDevStack);
if (IsSplit(tp1))
{
t1 = (SplitSide(tp1)) ? SplitRightType(tp1) :
SplitLeftType(tp1);
}
else
t1 = TiGetTypeExact(tp1);
devptr = ExtCurStyle->exts_device[t1];
j0 = (tileJunk *) tp1->ti_client;
/* top */
for (tp2= RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2))
{
if ((TiGetBottomType(tp2) == t1) &&
(tp2->ti_client == (ClientData) CLIENTDEFAULT))
{
Junk = resAddField(tp2);
STACKPUSH((ClientData)(tp2),resDevStack);
Junk->deviceList = resDev;
Junk->tj_status |= RES_TILE_DEV;
}
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetBottomType(tp2))
{
Junk = resAddField(tp2);
if (Junk->tj_status & RES_TILE_SD)
j0->sourceEdge |= TOPEDGE;
}
}
/*bottom*/
for (tp2= LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2))
{
if ((TiGetTopType(tp2) == t1) &&
(tp2->ti_client == (ClientData) CLIENTDEFAULT))
{
Junk = resAddField(tp2);
STACKPUSH((ClientData)(tp2),resDevStack);
Junk->deviceList = resDev;
Junk->tj_status |= RES_TILE_DEV;
}
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetTopType(tp2))
{
Junk = resAddField(tp2);
if (Junk->tj_status & RES_TILE_SD)
j0->sourceEdge |= BOTTOMEDGE;
}
}
/*right*/
for (tp2= TR(tp1); TOP(tp2) > BOTTOM(tp1); tp2 = LB(tp2))
{
if ((TiGetLeftType(tp2) == t1) &&
(tp2->ti_client == (ClientData) CLIENTDEFAULT))
{
Junk = resAddField(tp2);
STACKPUSH((ClientData)(tp2),resDevStack);
Junk->deviceList = resDev;
Junk->tj_status |= RES_TILE_DEV;
}
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetLeftType(tp2))
{
Junk = resAddField(tp2);
if (Junk->tj_status & RES_TILE_SD)
j0->sourceEdge |= RIGHTEDGE;
}
}
/*left*/
for (tp2= BL(tp1); BOTTOM(tp2) < TOP(tp1); tp2 = RT(tp2))
{
if ((TiGetRightType(tp2) == t1) &&
(tp2->ti_client == (ClientData) CLIENTDEFAULT))
{
Junk = resAddField(tp2);
STACKPUSH((ClientData)(tp2),resDevStack);
Junk->deviceList = resDev;
Junk->tj_status |= RES_TILE_DEV;
}
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetRightType(tp2))
{
Junk = resAddField(tp2);
if (Junk->tj_status & RES_TILE_SD)
j0->sourceEdge |= LEFTEDGE;
}
}
}
/* unmark all tiles marked as being part of source */
if (source != (Tile *) NULL)
{
tileJunk *j = (tileJunk *) source->ti_client;
STACKPUSH((ClientData) (source),resDevStack);
j->tj_status &= ~RES_TILE_SD;
}
while (!StackEmpty(resDevStack))
{
tp1 = (Tile *) STACKPOP(resDevStack);
if (IsSplit(tp1))
{
t1 = (SplitSide(tp1)) ? SplitRightType(tp1) :
SplitLeftType(tp1);
}
else
t1 = TiGetTypeExact(tp1);
/* top */
for (tp2= RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2))
{
tileJunk *j2 = (tileJunk *) tp2->ti_client;
if (TiGetBottomType(tp2) == t1)
{
if (j2->tj_status & RES_TILE_SD)
{
j2->tj_status &= ~RES_TILE_SD;
STACKPUSH((ClientData) tp2,resDevStack);
}
}
}
/*bottom*/
for(tp2= LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2))
{
tileJunk *j2 = (tileJunk *) tp2->ti_client;
if (TiGetTopType(tp2) == t1)
{
if (j2->tj_status & RES_TILE_SD)
{
j2->tj_status &= ~RES_TILE_SD;
STACKPUSH((ClientData) tp2,resDevStack);
}
}
}
/*right*/
for (tp2= TR(tp1); TOP(tp2) > BOTTOM(tp1); tp2 = LB(tp2))
{
tileJunk *j2 = (tileJunk *) tp2->ti_client;
if (TiGetLeftType(tp2) == t1)
{
if (j2->tj_status & RES_TILE_SD)
{
j2->tj_status &= ~RES_TILE_SD;
STACKPUSH((ClientData) tp2,resDevStack);
}
}
}
/*left*/
for (tp2= BL(tp1); BOTTOM(tp2) < TOP(tp1); tp2 = RT(tp2))
{
tileJunk *j2 = (tileJunk *) tp2->ti_client;
if (TiGetRightType(tp2) == t1)
{
if (j2->tj_status & RES_TILE_SD)
{
j2->tj_status &= ~RES_TILE_SD;
STACKPUSH((ClientData) tp2,resDevStack);
}
}
}
}
}
}
return(0);
}
/*
*-------------------------------------------------------------------------
*
* ResRemovePlumbing-- Removes and deallocates all the tileJunk fields.
*
* Results: returns 0
*
* Side Effects: frees up memory; resets tile->ti_client fields to CLIENTDEFAULT
*
*-------------------------------------------------------------------------
*/
int
ResRemovePlumbing(tile, arg)
Tile *tile;
ClientData *arg;
{
if (tile->ti_client != (ClientData) CLIENTDEFAULT)
{
freeMagic(((char *)(tile->ti_client)));
tile->ti_client = (ClientData) CLIENTDEFAULT;
}
return(0);
}
/*
*-------------------------------------------------------------------------
*
* ResPreprocessDevices-- Given a list of all the device tiles and
* a list of all the devices, this procedure calculates the width and
* length. The width is set equal to the sum of all edges that touch
* diffusion divided by 2. The length is the remaining perimeter divided by
* 2*tiles. The perimeter and area fields of device structures are also
* fixed.
*
* Results: none
*
* Side Effects: sets length and width of devices. "ResDevTile"
* structures are freed.
*
*-------------------------------------------------------------------------
*/
void
ResPreProcessDevices(TileList, DeviceList, Def)
ResDevTile *TileList;
resDevice *DeviceList;
CellDef *Def;
{
Tile *tile;
ResDevTile *oldTile;
tileJunk *tstruct;
TileType tt, residue;
int pNum;
while (TileList != (ResDevTile *) NULL)
{
tt = TileList->type;
if (DBIsContact(tt))
{
/* Find which residue of the contact is a device. */
TileTypeBitMask ttresidues;
DBFullResidueMask(tt, &ttresidues);
for (residue = TT_TECHDEPBASE; residue < DBNumUserLayers; residue++)
{
if (TTMaskHasType(&ttresidues, residue))
{
if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, residue))
{
pNum = DBPlane(residue);
break;
}
}
}
}
else
pNum = DBPlane(tt); /* always correct for non-contact types */
tile = (Def->cd_planes[pNum])->pl_hint;
GOTOPOINT(tile, &(TileList->area.r_ll));
tt = TiGetType(tile);
tstruct = (tileJunk *) tile->ti_client;
if (!TTMaskHasType(&ExtCurStyle->exts_deviceMask, tt) ||
tstruct->deviceList == NULL)
{
TxError("Bad Device Location at %d,%d\n",
TileList->area.r_ll.p_x,
TileList->area.r_ll.p_y);
}
else if ((tstruct->tj_status & RES_TILE_MARK) == 0)
{
resDevice *rd = tstruct->deviceList;
tstruct->tj_status |= RES_TILE_MARK;
rd->rd_perim += TileList->perim;
rd->rd_length += TileList->overlap;
rd->rd_area += (TileList->area.r_xtop - TileList->area.r_xbot)
* (TileList->area.r_ytop - TileList->area.r_ybot);
rd->rd_tiles++;
}
oldTile = TileList;
TileList = TileList->nextDev;
freeMagic((char *)oldTile);
}
for(; DeviceList != NULL;DeviceList = DeviceList->rd_nextDev)
{
int width = DeviceList->rd_perim;
int length = DeviceList->rd_length;
if (DeviceList->rd_tiles != 0)
{
if (length)
{
DeviceList->rd_length = (float) length /
((float)((DeviceList->rd_tiles) << 1));
DeviceList->rd_width = (width-length) >> 1;
}
else
{
double perimeter = DeviceList->rd_perim;
double area = DeviceList->rd_area;
perimeter /= 4.0;
DeviceList->rd_width = perimeter +
sqrt(perimeter * perimeter-area);
DeviceList->rd_length = (DeviceList->rd_perim
- 2 * DeviceList->rd_width) >> 1;
}
}
}
}
/*
*-------------------------------------------------------------------------
*
* ResAddToQueue-- adds new nodes to list of nodes requiring processing.
*
* Side Effects: nodes are added to list (i.e they have their linked list
* pointers modified.)
*
*-------------------------------------------------------------------------
*/
void
ResAddToQueue(node,list)
resNode *node,**list;
{
node->rn_more = *list;
node->rn_less = NULL;
if (*list) (*list)->rn_less = node;
*list = node;
}
/*
*-------------------------------------------------------------------------
*
* ResRemoveFromQueue-- removes node from queue. Complains if it notices
* that the node isn't in the supplied list.
*
* Results: none
*
* Side Effects: modifies nodelist
*
*-------------------------------------------------------------------------
*/
void
ResRemoveFromQueue(node,list)
resNode *node,**list;
{
if (node->rn_less != NULL)
{
node->rn_less->rn_more = node->rn_more;
}
else
{
if (node != (*list))
{
TxError("Error: Attempt to remove node from wrong list\n");
}
else
{
*list = node->rn_more;
}
}
if (node->rn_more != NULL)
{
node->rn_more->rn_less = node->rn_less;
}
node->rn_more = NULL;
node->rn_less = NULL;
}
tileJunk *
resAddField(tile)
Tile *tile;
{
tileJunk *Junk;
if ((Junk=(tileJunk *)tile->ti_client) == (tileJunk *) CLIENTDEFAULT)
{
Junk = (tileJunk *) mallocMagic((unsigned) (sizeof(tileJunk)));
ResJunkInit(Junk);
tile->ti_client = (ClientData) Junk;
}
return Junk;
}