mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-02 11:08:30 +02:00
Added a ARG_UNUSED macro in utils/magic.h, which produces a simple cast to void to silence the warnings. The reasons this is used as opposed to an attribute is that most compilers should support this. Besides this, the macro can be easily searched for in the future to potentially remove (where possible) the unused parameters.
1760 lines
47 KiB
C
1760 lines
47 KiB
C
#ifndef lint
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResMain.c,v 1.4 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 "select/select.h"
|
|
#include "textio/txcommands.h"
|
|
#include "resis/resis.h"
|
|
|
|
CellUse *ResUse = NULL; /* Our use and def */
|
|
CellDef *ResDef = NULL;
|
|
TileTypeBitMask ResConnectWithSD[NT]; /* A mask that goes from */
|
|
/* SD's to devices. */
|
|
TileTypeBitMask ResCopyMask[NT]; /* Indicates which tiles */
|
|
/* are to be copied. */
|
|
resResistor *ResResList = NULL; /* Resistor list */
|
|
resNode *ResNodeList = NULL; /* Processed Nodes */
|
|
resDevice *ResDevList = NULL; /* Devices */
|
|
ResContactPoint *ResContactList = NULL; /* Contacts */
|
|
resNode *ResNodeQueue = NULL; /* Pending nodes */
|
|
resNode *ResOriginNode = NULL; /* node where R=0 */
|
|
resNode *resCurrentNode;
|
|
int ResTileCount = 0; /* Number of tiles rn_status */
|
|
extern ExtRegion *ResFirst();
|
|
extern Tile *FindStartTile();
|
|
extern int ResEachTile();
|
|
extern int ResLaplaceTile();
|
|
extern ResSimNode *ResInitializeNode();
|
|
TileTypeBitMask ResSDTypesBitMask;
|
|
TileTypeBitMask ResSubTypesBitMask;
|
|
|
|
extern HashTable ResNodeTable;
|
|
|
|
/*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
* ResInitializeConn--
|
|
*
|
|
* Sets up mask by Source/Drain type of devices. This is
|
|
* exts_deviceSDtypes turned inside out.
|
|
*
|
|
* Results: none
|
|
*
|
|
* Side Effects: Sets up ResConnectWithSD.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResInitializeConn()
|
|
{
|
|
TileType dev, ttype;
|
|
char *dev_name;
|
|
int i;
|
|
ExtDevice *devptr;
|
|
|
|
for (dev = TT_TECHDEPBASE; dev < TT_MAXTYPES; dev++)
|
|
{
|
|
for (devptr = ExtCurStyle->exts_device[dev]; devptr; devptr = devptr->exts_next)
|
|
{
|
|
if ((devptr != NULL) && ((dev_name = devptr->exts_deviceName) != NULL)
|
|
&& (strcmp(dev_name, "None")))
|
|
{
|
|
for (ttype = TT_TECHDEPBASE; ttype < TT_MAXTYPES; ttype++)
|
|
{
|
|
for (i = 0; ; i++)
|
|
{
|
|
if (TTMaskIsZero(&(devptr->exts_deviceSDTypes[i])))
|
|
break;
|
|
if TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), ttype)
|
|
TTMaskSetType(&ResConnectWithSD[ttype], dev);
|
|
}
|
|
|
|
if TTMaskHasType(&(devptr->exts_deviceSubstrateTypes), ttype)
|
|
TTMaskSetType(&ResConnectWithSD[ttype], dev);
|
|
}
|
|
}
|
|
}
|
|
TTMaskSetMask(&ResConnectWithSD[dev], &DBConnectTbl[dev]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* ResGetReCell --
|
|
*
|
|
* This procedure makes sure that ResUse,ResDef
|
|
* have been properly initialized to refer to a cell definition
|
|
* named "__RESIS__".
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* A new cell use and/or def are created if necessary.
|
|
*
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResGetReCell()
|
|
{
|
|
if (ResUse != NULL) return;
|
|
ResDef = DBCellLookDef("__RESIS__");
|
|
if (ResDef == NULL)
|
|
{
|
|
ResDef = DBCellNewDef("__RESIS__");
|
|
ASSERT (ResDef != (CellDef *) NULL, "ResGetReCell");
|
|
DBCellSetAvail(ResDef);
|
|
ResDef->cd_flags |= CDINTERNAL;
|
|
}
|
|
ResUse = DBCellNewUse(ResDef, (char *) NULL);
|
|
DBSetTrans(ResUse, &GeoIdentityTransform);
|
|
ResUse->cu_expandMask = CU_DESCEND_SPECIAL;
|
|
}
|
|
|
|
/*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
* ResDissolveContacts--
|
|
*
|
|
* results: none
|
|
*
|
|
* Side Effects: All contacts in the design are broken into their
|
|
* constituent layers. There should be no contacts in ResDef after
|
|
* this procedure runs.
|
|
*
|
|
*
|
|
*------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
ResDissolveContacts(contacts)
|
|
ResContactPoint *contacts;
|
|
{
|
|
TileType t, oldtype;
|
|
Tile *tp;
|
|
TileTypeBitMask residues;
|
|
|
|
for (; contacts != (ResContactPoint *)NULL; contacts = contacts->cp_nextcontact)
|
|
{
|
|
oldtype=contacts->cp_type;
|
|
|
|
#ifdef PARANOID
|
|
if (oldtype == TT_SPACE)
|
|
TxError("Error in Contact Dissolving for %s \n",ResCurrentNode);
|
|
#endif
|
|
DBFullResidueMask(oldtype, &residues);
|
|
|
|
DBErase(ResUse->cu_def, &(contacts->cp_rect), oldtype);
|
|
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
|
if (TTMaskHasType(&residues, t))
|
|
DBPaint(ResUse->cu_def, &(contacts->cp_rect), t);
|
|
|
|
tp = PlaneGetHint(ResDef->cd_planes[DBPlane(contacts->cp_type)]);
|
|
GOTOPOINT(tp, &(contacts->cp_rect.r_ll));
|
|
|
|
#ifdef PARANOID
|
|
if (TiGetTypeExact(tp) == contacts->cp_type)
|
|
TxError("Error in Contact Preprocess Routines\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
*---------------------------------------------------------------------------
|
|
*
|
|
* ResMakePortBreakpoints --
|
|
*
|
|
* Search for nodes which are ports, and force them to be breakpoints
|
|
* in the "tileJunk" field of their respective tiles in ResUse. This
|
|
* ensures that connected nodes that stretch between two ports will
|
|
* not be assumed to be "hanging" nodes.
|
|
*
|
|
* Do the same thing for labels.
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
ResMakePortBreakpoints(def)
|
|
CellDef *def;
|
|
{
|
|
Plane *plane;
|
|
Rect *rect;
|
|
TileTypeBitMask mask;
|
|
HashSearch hs;
|
|
HashEntry *entry;
|
|
ResSimNode *node;
|
|
int ResAddBreakpointFunc(); /* Forward Declaration */
|
|
|
|
HashStartSearch(&hs);
|
|
while((entry = HashNext(&ResNodeTable,&hs)) != NULL)
|
|
{
|
|
node = (ResSimNode *)HashGetValue(entry);
|
|
if (node->status & PORTNODE)
|
|
{
|
|
if (node->rs_ttype <= 0)
|
|
{
|
|
TxError("Warning: Label \"%s\" is unconnected.\n", node->name);
|
|
continue;
|
|
}
|
|
|
|
rect = &(node->rs_bbox);
|
|
|
|
/* Beware of zero-area ports */
|
|
if (rect->r_xbot == rect->r_xtop)
|
|
{
|
|
rect->r_xbot--;
|
|
rect->r_xtop++;
|
|
}
|
|
if (rect->r_ybot == rect->r_ytop)
|
|
{
|
|
rect->r_ybot--;
|
|
rect->r_ytop++;
|
|
}
|
|
|
|
/* If label is on a contact, the contact has been dissolved. */
|
|
/* Assume that the uppermost residue is the port. This may */
|
|
/* not necessarily be the case. Could do a boundary scan on */
|
|
/* each residue plane to see which side of the contact is */
|
|
/* the internal connection in the def. . . */
|
|
|
|
if (DBIsContact(node->rs_ttype))
|
|
{
|
|
TileType type;
|
|
|
|
DBFullResidueMask(node->rs_ttype, &mask);
|
|
for (type = DBNumUserLayers - 1; type >= TT_TECHDEPBASE; type--)
|
|
if (TTMaskHasType(&mask, type))
|
|
{
|
|
plane = def->cd_planes[DBPlane(type)];
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TTMaskSetOnlyType(&mask, node->rs_ttype);
|
|
plane = def->cd_planes[DBPlane(node->rs_ttype)];
|
|
}
|
|
|
|
(void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask,
|
|
ResAddBreakpointFunc, (ClientData)node);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
*---------------------------------------------------------------------------
|
|
*
|
|
* ResMakeLabelBreakpoints --
|
|
*
|
|
* Search for labels that are part of a node, and force them to be
|
|
* breakpoints in the "tileJunk" field of their respective tiles in
|
|
* ResUse. This ensures (among other things) that pins of a top level
|
|
* cell will be retained and become the endpoint of a net.
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
ResMakeLabelBreakpoints(def, goodies)
|
|
CellDef *def;
|
|
ResGlobalParams *goodies;
|
|
{
|
|
Plane *plane;
|
|
Rect *rect;
|
|
TileTypeBitMask mask;
|
|
HashEntry *entry;
|
|
ResSimNode *node;
|
|
Label *slab;
|
|
int ResAddBreakpointFunc(); /* Forward Declaration */
|
|
|
|
for (slab = def->cd_labels; slab != NULL; slab = slab->lab_next)
|
|
{
|
|
/* Avoid any empty-string labels, or it will end up as */
|
|
/* missing terminal on a device. */
|
|
if (*(slab->lab_text) == '\0') continue;
|
|
|
|
entry = HashFind(&ResNodeTable, slab->lab_text);
|
|
node = ResInitializeNode(entry);
|
|
|
|
/* If the drivepoint position changes and the drivepoint is */
|
|
/* in the "goodies" record, then make sure the tile type in */
|
|
/* "goodies" gets changed to match. */
|
|
|
|
if (goodies->rg_devloc == &node->drivepoint)
|
|
goodies->rg_ttype = slab->lab_type;
|
|
|
|
node->drivepoint = slab->lab_rect.r_ll;
|
|
node->rs_bbox = slab->lab_rect;
|
|
node->location = slab->lab_rect.r_ll;
|
|
node->rs_ttype = slab->lab_type;
|
|
node->type = slab->lab_type;
|
|
|
|
rect = &(node->rs_bbox);
|
|
|
|
/* If label is on a contact, the contact has been dissolved. */
|
|
/* Assume that the uppermost residue is the port. This may */
|
|
/* not necessarily be the case. Could do a boundary scan on */
|
|
/* each residue plane to see which side of the contact is */
|
|
/* the internal connection in the def. . . */
|
|
|
|
if (DBIsContact(slab->lab_type))
|
|
{
|
|
TileType type;
|
|
|
|
DBFullResidueMask(slab->lab_type, &mask);
|
|
for (type = DBNumUserLayers - 1; type >= TT_TECHDEPBASE; type--)
|
|
if (TTMaskHasType(&mask, type))
|
|
{
|
|
plane = def->cd_planes[DBPlane(type)];
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TTMaskSetOnlyType(&mask, slab->lab_type);
|
|
plane = def->cd_planes[DBPlane(slab->lab_type)];
|
|
}
|
|
|
|
(void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask,
|
|
ResAddBreakpointFunc, (ClientData)node);
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
*----------------------------------------------------------------------------
|
|
*
|
|
* ResAddBreakpointFunc --
|
|
*
|
|
* Add a breakpoint to the "tileJunk" structure of the tile
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
ResAddBreakpointFunc(tile, node)
|
|
Tile *tile;
|
|
ResSimNode *node;
|
|
{
|
|
|
|
if (TiGetClient(tile) == CLIENTDEFAULT)
|
|
return 0;
|
|
|
|
NEWPORT(node, tile);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*---------------------------------------------------------------------------
|
|
*
|
|
* ResFindNewContactTiles --
|
|
*
|
|
*
|
|
* Results: none
|
|
*
|
|
* Side Effects: dissolving contacts eliminated the tiles that
|
|
* contacts->nextcontact pointed to. This procedure finds the tile now under
|
|
* center and sets that tile's ti_client field to point to the contact. The
|
|
* old value of clientdata is set to nextTilecontact.
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResFindNewContactTiles(contacts)
|
|
ResContactPoint *contacts;
|
|
{
|
|
int pNum;
|
|
Tile *tile;
|
|
TileTypeBitMask mask;
|
|
|
|
for (; contacts != (ResContactPoint *) NULL; contacts = contacts->cp_nextcontact)
|
|
{
|
|
DBFullResidueMask(contacts->cp_type, &mask);
|
|
|
|
/* Watch for types that connect to the substrate plane or well; */
|
|
/* e.g., psubstratepdiff connects to nwell but not through a */
|
|
/* contact. */
|
|
|
|
if (ExtCurStyle->exts_globSubstratePlane != -1)
|
|
{
|
|
TileTypeBitMask cMask;
|
|
TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type],
|
|
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
|
|
|
|
if (!TTMaskIsZero(&cMask))
|
|
TTMaskSetMask(&mask, &cMask);
|
|
}
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
tile = PlaneGetHint(ResDef->cd_planes[pNum]);
|
|
GOTOPOINT(tile, &(contacts->cp_center));
|
|
#ifdef PARANOID
|
|
if (tile == (Tile *) NULL)
|
|
{
|
|
TxError("Error: setting contact tile to null\n");
|
|
}
|
|
#endif
|
|
|
|
if ((IsSplit(tile) && TTMaskHasType(&mask, TiGetRightType(tile)))
|
|
|| TTMaskHasType(&mask, TiGetType(tile)))
|
|
{
|
|
tileJunk *j = (tileJunk *)TiGetClientPTR(tile);
|
|
cElement *ce;
|
|
|
|
ce = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
|
|
contacts->cp_tile[contacts->cp_currentcontact] = tile;
|
|
ce->ce_thisc = contacts;
|
|
ce->ce_nextc = j->contactList;
|
|
(contacts->cp_currentcontact) += 1;
|
|
j->contactList = ce;
|
|
}
|
|
else if (!IsSplit(tile))
|
|
{
|
|
TileType ttype = TiGetTypeExact(tile);
|
|
if (DBIsContact(ttype))
|
|
{
|
|
/* Handle the exceptional case in which a contact
|
|
* type is its own residue. This can be used for
|
|
* devices whose terminals are always a contact
|
|
* and for which a non-contact type cannot be drawn.
|
|
*/
|
|
if (TTMaskIntersect(DBResidueMask(ttype), &mask))
|
|
{
|
|
tileJunk *j = (tileJunk *)TiGetClientPTR(tile);
|
|
cElement *ce;
|
|
|
|
ce = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
|
|
contacts->cp_tile[contacts->cp_currentcontact] = tile;
|
|
ce->ce_thisc = contacts;
|
|
ce->ce_nextc = j->contactList;
|
|
(contacts->cp_currentcontact) += 1;
|
|
j->contactList = ce;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifdef PARANOID
|
|
if (contacts->cp_currentcontact >= LAYERS_PER_CONTACT)
|
|
{
|
|
TxError("Error: Not enough space allocated for contact nodes\n");
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
* ResProcessTiles--Calls ResEachTile with processed tiles belonging to
|
|
* nodes in ResNodeQueue. When all the tiles corresponding
|
|
* to a node have been processed, the node is moved to
|
|
* ResNodeList.
|
|
*
|
|
* Results: Return 1 if any error occurred, 0 otherwise.
|
|
*
|
|
* Side Effects: Cleans extraneous linked lists from nodes.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
ResProcessTiles(goodies, origin)
|
|
Point *origin;
|
|
ResGlobalParams *goodies;
|
|
|
|
{
|
|
Tile *startTile;
|
|
int tilenum, merged;
|
|
resNode *resptr2;
|
|
jElement *workingj;
|
|
cElement *workingc;
|
|
int (*tilefunc)();
|
|
|
|
#ifdef LAPLACE
|
|
tilefunc = (ResOptionsFlags & ResOpt_DoLaplace) ? ResLaplaceTile : ResEachTile;
|
|
#else
|
|
tilefunc = ResEachTile;
|
|
#endif
|
|
|
|
if (ResOptionsFlags & ResOpt_Signal)
|
|
{
|
|
startTile = FindStartTile(goodies, origin);
|
|
if (startTile == NULL) return(1);
|
|
resCurrentNode = NULL;
|
|
(void) (*tilefunc)(startTile, origin);
|
|
}
|
|
#ifdef ARIEL
|
|
else if (ResOptionsFlags & ResOpt_Power)
|
|
{
|
|
for (fix = ResFixList; fix != NULL; fix = fix->fp_next)
|
|
{
|
|
Tile *tile = fix->fp_tile;
|
|
if (tile == NULL)
|
|
{
|
|
tile = PlaneGetHint(ResDef->cd_planes[DBPlane(fix->fp_ttype)]);
|
|
GOTOPOINT(tile, &(fix->fp_loc));
|
|
if (TiGetTypeExact(tile) != TT_SPACE)
|
|
{
|
|
fix->fp_tile = tile;
|
|
}
|
|
else
|
|
{
|
|
tile = NULL;
|
|
}
|
|
}
|
|
if (tile != NULL)
|
|
{
|
|
int x = fix->fp_loc.p_x;
|
|
int y = fix->fp_loc.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);
|
|
fix->fp_node = resptr;
|
|
NEWBREAK(resptr, tile, x, y, NULL);
|
|
}
|
|
}
|
|
for (fix = ResFixList; fix != NULL; fix = fix->fp_next)
|
|
{
|
|
Tile *tile = fix->fp_tile;
|
|
|
|
if (tile != NULL && (((tileJunk *)TiGetClientPTR(tile)->tj_status &
|
|
RES_TILE_DONE) == 0)
|
|
{
|
|
resCurrentNode = fix->fp_node;
|
|
(void) (*tilefunc)(tile, (Point *)NULL);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef PARANOID
|
|
else
|
|
{
|
|
TxError("Unknown analysis type in ResProcessTiles\n");
|
|
}
|
|
#endif
|
|
|
|
/* Process Everything else */
|
|
|
|
while (ResNodeQueue != NULL)
|
|
{
|
|
/*
|
|
* merged keeps track of whether another node gets merged into
|
|
* the current one. If it does, then the node must be processed
|
|
* because additional junctions or contacts were added
|
|
*/
|
|
|
|
resptr2 = ResNodeQueue;
|
|
merged = FALSE;
|
|
|
|
/* Process all junctions associated with node */
|
|
|
|
for (workingj = resptr2->rn_je; workingj != NULL; workingj = workingj->je_nextj)
|
|
{
|
|
ResJunction *rj = workingj->je_thisj;
|
|
if (rj->rj_status == FALSE)
|
|
{
|
|
for (tilenum = 0; tilenum < TILES_PER_JUNCTION; tilenum++)
|
|
{
|
|
Tile *tile = rj->rj_Tile[tilenum];
|
|
tileJunk *j = (tileJunk *)TiGetClientPTR(tile);
|
|
|
|
if ((j->tj_status & RES_TILE_DONE) == 0)
|
|
{
|
|
resCurrentNode = resptr2;
|
|
merged |= (*tilefunc)(tile, (Point *)NULL);
|
|
}
|
|
if (merged & ORIGIN) break;
|
|
}
|
|
if (merged & ORIGIN) break;
|
|
rj->rj_status = TRUE;
|
|
}
|
|
}
|
|
|
|
/* Next, Process all contacts. */
|
|
|
|
for (workingc = resptr2->rn_ce; workingc != NULL; workingc = workingc->ce_nextc)
|
|
{
|
|
ResContactPoint *cp = workingc->ce_thisc;
|
|
|
|
if (merged & ORIGIN) break;
|
|
if (cp->cp_status == FALSE)
|
|
{
|
|
int newstatus = TRUE;
|
|
for (tilenum = 0; tilenum < cp->cp_currentcontact; tilenum++)
|
|
{
|
|
Tile *tile = cp->cp_tile[tilenum];
|
|
tileJunk *j = (tileJunk *) TiGetClientPTR(tile);
|
|
|
|
if ((j->tj_status & RES_TILE_DONE) == 0)
|
|
{
|
|
if (cp->cp_cnode[tilenum] == resptr2)
|
|
{
|
|
resCurrentNode = resptr2;
|
|
merged |= (*tilefunc)(tile,(Point *)NULL);
|
|
}
|
|
else
|
|
{
|
|
newstatus = FALSE;
|
|
}
|
|
}
|
|
if (merged & ORIGIN) break;
|
|
}
|
|
if (merged & ORIGIN) break;
|
|
cp->cp_status = newstatus;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If nothing new has been added via a merge, then the node is
|
|
* finished. It is removed from the pending queue, added to the
|
|
* done list, cleaned up, and passed to ResDoneWithNode
|
|
*/
|
|
|
|
if (merged == FALSE)
|
|
{
|
|
ResRemoveFromQueue(resptr2, &ResNodeQueue);
|
|
resptr2->rn_more = ResNodeList;
|
|
resptr2->rn_less = NULL;
|
|
resptr2->rn_status &= ~PENDING;
|
|
resptr2->rn_status |= FINISHED | MARKED;
|
|
if (ResNodeList != NULL)
|
|
{
|
|
ResNodeList->rn_less = resptr2;
|
|
}
|
|
if (resptr2->rn_noderes == 0)
|
|
{
|
|
ResOriginNode=resptr2;
|
|
}
|
|
ResNodeList = resptr2;
|
|
ResCleanNode(resptr2, FALSE, &ResNodeList, &ResNodeQueue);
|
|
ResDoneWithNode(resptr2);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResCalcPerimOverlap ---
|
|
*
|
|
* Given a device tile, compute simple perimeter and overlap of the device
|
|
* by the net under consideration.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* The ResDevTile structure is updated with the overlap and perimeter
|
|
* values.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResCalcPerimOverlap(tile, dev)
|
|
Tile *tile;
|
|
ResDevTile *dev;
|
|
{
|
|
Tile *tp;
|
|
int t1;
|
|
int overlap;
|
|
TileTypeBitMask *omask;
|
|
|
|
dev->perim = (TOP(tile) - BOTTOM(tile) - LEFT(tile) + RIGHT(tile)) << 1;
|
|
overlap = 0;
|
|
|
|
t1 = TiGetType(tile);
|
|
omask = &(ExtCurStyle->exts_nodeConn[t1]);
|
|
|
|
/* left */
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
|
{
|
|
if TTMaskHasType(omask, TiGetType(tp))
|
|
overlap += MIN(TOP(tile), TOP(tp)) - MAX(BOTTOM(tile), BOTTOM(tp));
|
|
}
|
|
|
|
/* right */
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp))
|
|
{
|
|
if TTMaskHasType(omask, TiGetType(tp))
|
|
overlap += MIN(TOP(tile), TOP(tp)) - MAX(BOTTOM(tile), BOTTOM(tp));
|
|
}
|
|
|
|
/* top */
|
|
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
|
{
|
|
if TTMaskHasType(omask, TiGetType(tp))
|
|
overlap += MIN(RIGHT(tile), RIGHT(tp)) - MAX(LEFT(tile), LEFT(tp));
|
|
}
|
|
|
|
/* bottom */
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
|
|
{
|
|
if TTMaskHasType(omask, TiGetType(tp))
|
|
overlap += MIN(RIGHT(tile), RIGHT(tp)) - MAX(LEFT(tile), LEFT(tp));
|
|
}
|
|
dev->overlap += overlap;
|
|
}
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* resMakeDevFunc --
|
|
*
|
|
* Callback function from ResExtractNet. For each device in a node's
|
|
* device list pulled from the .sim file, find the tile(s) corresponding
|
|
* to the device in the source tree, and fill out the complete device
|
|
* record (namely the full device area).
|
|
*
|
|
* Result:
|
|
* Return 1 to stop the search because the device has been found.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
resMakeDevFunc(tile, cx)
|
|
Tile *tile;
|
|
TreeContext *cx;
|
|
{
|
|
ResDevTile *thisDev = (ResDevTile *)cx->tc_filter->tf_arg;
|
|
Rect devArea;
|
|
TileType ttype;
|
|
|
|
TiToRect(tile, &devArea);
|
|
GeoTransRect(&cx->tc_scx->scx_trans, &devArea, &thisDev->area);
|
|
|
|
if (IsSplit(tile))
|
|
ttype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
|
|
else
|
|
ttype = TiGetType(tile);
|
|
|
|
/* If more than one tile type extracts to the same device, then */
|
|
/* the device type may be different from what was recorded when */
|
|
/* the sim file was read. Restricted to the plane of the */
|
|
/* original type to avoid conflict with completely different */
|
|
/* devices (like transistors vs. MiM caps). */
|
|
|
|
if (ttype != thisDev->type)
|
|
{
|
|
if (DBPlane(ttype) != DBPlane(thisDev->type))
|
|
return 0; /* Completely different device? */
|
|
thisDev->type = ttype;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* resExpandDevFunc --
|
|
*
|
|
* Do a boundary search on the first tile found in the search context
|
|
* path belonging to a device, including all tiles that belong to the
|
|
* device. For each compatible tile found, paint the device tile
|
|
* type into ResUse and calculate the overlap.
|
|
*
|
|
* Returns:
|
|
* 1 to stop the search (only the first tile of a device needs to be
|
|
* found).
|
|
*
|
|
* Side effects:
|
|
* Paints into ResUse and recalculates values of thisDev.
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#define DEV_PROCESSED 1
|
|
|
|
int
|
|
resExpandDevFunc(tile, cx)
|
|
Tile *tile;
|
|
TreeContext *cx;
|
|
{
|
|
ResDevTile *thisDev = (ResDevTile *)cx->tc_filter->tf_arg;
|
|
static Stack *devExtentsStack = NULL;
|
|
static Stack *devResetStack = NULL;
|
|
Tile *tp, *tp2;
|
|
TileType ttype;
|
|
int pNum;
|
|
Rect area;
|
|
|
|
pNum = DBPlane(thisDev->type);
|
|
if (devExtentsStack == NULL)
|
|
devExtentsStack = StackNew(8);
|
|
if (devResetStack == NULL)
|
|
devResetStack = StackNew(8);
|
|
|
|
TiSetClientINT(tile, DEV_PROCESSED);
|
|
STACKPUSH((ClientData)tile, devExtentsStack);
|
|
|
|
while (!StackEmpty(devExtentsStack))
|
|
{
|
|
tp = (Tile *) STACKPOP(devExtentsStack);
|
|
STACKPUSH((ClientData)tp, devResetStack);
|
|
TiToRect(tp, &area);
|
|
|
|
/* Paint type thisDev->type into ResUse over area of tile "tp" */
|
|
DBNMPaintPlane(ResUse->cu_def->cd_planes[pNum], TiGetTypeExact(tp),
|
|
&area, DBStdPaintTbl(thisDev->type, pNum), (PaintUndoInfo *)NULL);
|
|
|
|
/* Add source/drain perimeter overlap to the device for this tile */
|
|
ResCalcPerimOverlap(tp, thisDev);
|
|
|
|
/* Search boundary of the device tile for more tiles belonging */
|
|
/* to the device. If contacts are found, replace them with the */
|
|
/* device type. */
|
|
|
|
/* top */
|
|
for (tp2 = RT(tp); RIGHT(tp2) > LEFT(tp); tp2 = BL(tp2))
|
|
{
|
|
if (TiGetClientINT(tp2) == DEV_PROCESSED) continue;
|
|
ttype = TiGetBottomType(tp2);
|
|
if ((ttype == thisDev->type) || (DBIsContact(ttype)
|
|
&& TTMaskHasType(DBResidueMask(ttype), thisDev->type)))
|
|
{
|
|
TiSetClientINT(tp2, DEV_PROCESSED);
|
|
STACKPUSH((ClientData)tp2, devExtentsStack);
|
|
}
|
|
}
|
|
|
|
/* bottom */
|
|
for (tp2 = LB(tp); LEFT(tp2) < RIGHT(tp); tp2 = TR(tp2))
|
|
{
|
|
if (TiGetClientINT(tp2) == DEV_PROCESSED) continue;
|
|
ttype = TiGetTopType(tp2);
|
|
if ((ttype == thisDev->type) || (DBIsContact(ttype)
|
|
&& TTMaskHasType(DBResidueMask(ttype), thisDev->type)))
|
|
{
|
|
TiSetClientINT(tp2, DEV_PROCESSED);
|
|
STACKPUSH((ClientData)tp2, devExtentsStack);
|
|
}
|
|
}
|
|
|
|
/* right */
|
|
for (tp2 = TR(tp); TOP(tp2) > BOTTOM(tp); tp2 = LB(tp2))
|
|
{
|
|
if (TiGetClientINT(tp2) == DEV_PROCESSED) continue;
|
|
ttype = TiGetLeftType(tp2);
|
|
if ((ttype == thisDev->type) || (DBIsContact(ttype)
|
|
&& TTMaskHasType(DBResidueMask(ttype), thisDev->type)))
|
|
{
|
|
TiSetClientINT(tp2, DEV_PROCESSED);
|
|
STACKPUSH((ClientData)tp2, devExtentsStack);
|
|
}
|
|
}
|
|
|
|
/* left */
|
|
for (tp2 = BL(tp); BOTTOM(tp2) < TOP(tp); tp2 = RT(tp2))
|
|
{
|
|
if (TiGetClientINT(tp2) == DEV_PROCESSED) continue;
|
|
ttype = TiGetRightType(tp2);
|
|
if ((ttype == thisDev->type) || (DBIsContact(ttype)
|
|
&& TTMaskHasType(DBResidueMask(ttype), thisDev->type)))
|
|
{
|
|
TiSetClientINT(tp2, DEV_PROCESSED);
|
|
STACKPUSH((ClientData)tp2, devExtentsStack);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Reset the device tile client records */
|
|
while (!StackEmpty(devResetStack))
|
|
{
|
|
tp = (Tile *) STACKPOP(devResetStack);
|
|
TiSetClient(tp, CLIENTDEFAULT);
|
|
}
|
|
|
|
/* Return 1 to stop the search; we only need to run this from */
|
|
/* the first device tile. */
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResShaveContacts ---
|
|
*
|
|
* Remove the top layer off of every contact in the design, leaving
|
|
* only the bottom layer. This also resolves issues with stacked
|
|
* contacts by leaving clean contact areas where stacked types
|
|
* overlap. Contacts are removed from the plane above the search
|
|
* plane, so the removal does not corrupt the current plane search.
|
|
*
|
|
* Results:
|
|
* Return 0 to keep the search going.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
ResShaveContacts(tile, def)
|
|
Tile *tile;
|
|
CellDef *def;
|
|
{
|
|
TileType ttype;
|
|
Rect area;
|
|
Plane *plane;
|
|
int pNum;
|
|
int pMask;
|
|
|
|
/* To do: Handle split tiles, although this is unlikely for
|
|
* contact types.
|
|
*/
|
|
ttype = TiGetType(tile);
|
|
|
|
if (DBIsContact(ttype))
|
|
{
|
|
/* Remove the contact type from the plane above */
|
|
TiToRect(tile, &area);
|
|
pMask = DBTypePlaneMaskTbl[ttype];
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(pMask, pNum))
|
|
break;
|
|
|
|
for (++pNum; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(pMask, pNum))
|
|
{
|
|
plane = def->cd_planes[pNum];
|
|
DBPaintPlane(plane, &area, DBStdEraseTbl(ttype, pNum),
|
|
(PaintUndoInfo *)NULL);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResExtractNet-- extracts the resistance net at the specified
|
|
* rn_loc. If the resulting net is greater than the tolerance,
|
|
* simplify and return the resulting network.
|
|
*
|
|
* Results: 0 iff it worked.
|
|
*
|
|
* Side effects: Produces a resistance network for the node.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
ResExtractNet(node, goodies, cellname)
|
|
ResSimNode *node;
|
|
ResGlobalParams *goodies;
|
|
char *cellname;
|
|
{
|
|
SearchContext scx;
|
|
TileTypeBitMask FirstTileMask;
|
|
TileTypeBitMask tMask;
|
|
Point startpoint;
|
|
static int first = 1;
|
|
ResDevTile *DevTiles, *thisDev;
|
|
devPtr *tptr;
|
|
int pNum;
|
|
int resMakeDevFunc();
|
|
int resExpandDevFunc();
|
|
|
|
/* Make sure all global network variables are reset */
|
|
|
|
ResResList = NULL;
|
|
ResNodeList = NULL;
|
|
ResDevList = NULL;
|
|
ResNodeQueue = NULL;
|
|
ResContactList = NULL;
|
|
ResOriginNode = NULL;
|
|
|
|
/* Pass back network pointers */
|
|
|
|
goodies->rg_maxres = 0;
|
|
goodies->rg_tilecount = 0;
|
|
|
|
/* Set up internal stuff if this is the first time through */
|
|
|
|
if (first)
|
|
{
|
|
ResInitializeConn();
|
|
first = 0;
|
|
ResGetReCell();
|
|
}
|
|
|
|
/* Initialize Cell */
|
|
|
|
if (cellname)
|
|
{
|
|
CellDef *def = DBCellLookDef(cellname);
|
|
if (def == (CellDef *)NULL)
|
|
{
|
|
TxError("Error: No such cell \"%s\"\n", cellname);
|
|
return TRUE;
|
|
}
|
|
scx.scx_use = DBCellNewUse(def, (char *)NULL);
|
|
DBSetTrans (scx.scx_use, &GeoIdentityTransform);
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
}
|
|
else
|
|
{
|
|
MagWindow *w = ToolGetBoxWindow(&scx.scx_area, (int *)NULL);
|
|
if (w == (MagWindow *)NULL)
|
|
{
|
|
TxError("Sorry, the box must appear in one of the windows.\n");
|
|
return TRUE;
|
|
}
|
|
scx.scx_use = (CellUse *) w->w_surfaceID;
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
}
|
|
|
|
DBCellClearDef(ResUse->cu_def);
|
|
|
|
#ifdef ARIEL
|
|
if ((ResOptionsFlags & ResOpt_Power) &&
|
|
strcmp(node->name, goodies->rg_name) != 0) continue;
|
|
#endif
|
|
|
|
/* Copy Paint */
|
|
|
|
scx.scx_area.r_ll.p_x = node->location.p_x - 2;
|
|
scx.scx_area.r_ll.p_y = node->location.p_y - 2;
|
|
scx.scx_area.r_ur.p_x = node->location.p_x + 2;
|
|
scx.scx_area.r_ur.p_y = node->location.p_y + 2;
|
|
startpoint = node->location;
|
|
|
|
/* Because node->type might come from a label with a sticky type
|
|
* that does not correspond exactly to the layer underneath, include
|
|
* all connecting types.
|
|
*/
|
|
if (node->type != TT_SPACE)
|
|
{
|
|
TTMaskZero(&FirstTileMask);
|
|
TTMaskSetMask(&FirstTileMask, &DBConnectTbl[node->type]);
|
|
|
|
DBTreeCopyConnect(&scx, &FirstTileMask, 0, ResCopyMask, &TiPlaneRect,
|
|
SEL_DO_LABELS, ResUse);
|
|
}
|
|
|
|
TTMaskZero(&ResSDTypesBitMask);
|
|
TTMaskZero(&ResSubTypesBitMask);
|
|
|
|
/* Add devices to ResUse from list in node */
|
|
DevTiles = NULL;
|
|
for (tptr = node->firstDev; tptr; tptr = tptr->nextDev)
|
|
{
|
|
int result;
|
|
int i;
|
|
ExtDevice *devptr;
|
|
|
|
thisDev = (ResDevTile *)mallocMagic(sizeof(ResDevTile));
|
|
thisDev->devptr = tptr->thisDev->rs_devptr;
|
|
thisDev->type = tptr->thisDev->rs_ttype;
|
|
thisDev->overlap = 0;
|
|
scx.scx_area.r_ll.p_x = tptr->thisDev->location.p_x;
|
|
scx.scx_area.r_ll.p_y = tptr->thisDev->location.p_y;
|
|
scx.scx_area.r_xtop = scx.scx_area.r_xbot + 1;
|
|
scx.scx_area.r_ytop = scx.scx_area.r_ybot + 1;
|
|
result = DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
|
resMakeDevFunc, (ClientData)thisDev);
|
|
if (result == 0)
|
|
{
|
|
TxError("No device of type %s found at location %d,%d\n",
|
|
DBTypeLongNameTbl[thisDev->type],
|
|
tptr->thisDev->location.p_x,
|
|
tptr->thisDev->location.p_y);
|
|
freeMagic(thisDev);
|
|
continue;
|
|
}
|
|
thisDev->nextDev = DevTiles;
|
|
DevTiles = thisDev;
|
|
|
|
/* Paint the entire device into ResUse */
|
|
TTMaskSetOnlyType(&tMask, thisDev->type);
|
|
DBTreeSrTiles(&scx, &tMask, 0, resExpandDevFunc, (ClientData)thisDev);
|
|
|
|
/* If the device has source/drain types in a different plane than */
|
|
/* the device identifier type, then add the source/drain types to */
|
|
/* the mask ResSDTypesBitMask. */
|
|
|
|
devptr = tptr->thisDev->rs_devptr;
|
|
for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
|
|
TTMaskSetMask(&ResSDTypesBitMask, &devptr->exts_deviceSDTypes[i]);
|
|
|
|
/* Add the substrate types to the mask ResSubTypesBitMask */
|
|
TTMaskSetMask(&ResSubTypesBitMask, &devptr->exts_deviceSubstrateTypes);
|
|
|
|
/* TT_SPACE should be removed from ResSubTypesBitMask */
|
|
TTMaskClearType(&ResSubTypesBitMask, TT_SPACE);
|
|
}
|
|
DBReComputeBbox(ResUse->cu_def);
|
|
|
|
ExtResetTiles(scx.scx_use->cu_def, extUnInit);
|
|
|
|
/* To avoid issues with overlapping stacked contact types and */
|
|
/* double-counting contacts on multiple planes, erase the top */
|
|
/* contact layers of all contacts. ExtFindRegions() will still */
|
|
/* find the connectivity above but will only process one tile per */
|
|
/* contact. This temporarily creates an improper database, but */
|
|
/* the contacts are all immediately erased by ResDissolveContacts().*/
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
Plane *plane = ResUse->cu_def->cd_planes[pNum];
|
|
DBSrPaintArea(PlaneGetHint(plane), plane, &(ResUse->cu_def->cd_bbox),
|
|
&DBAllButSpaceAndDRCBits, ResShaveContacts,
|
|
(ClientData)ResUse->cu_def);
|
|
}
|
|
|
|
/* Find all contacts in design and note their position */
|
|
|
|
/* NOTE: ExtFindRegions() will call ResFirst or ResEach for BOTH */
|
|
/* planes of a contact. Rather than attempting to limit the */
|
|
/* search, ResDoContacts() will just double the resistance per via */
|
|
/* so that the final value is correct. */
|
|
|
|
ResContactList = (ResContactPoint *)ExtFindRegions(ResUse->cu_def,
|
|
&(ResUse->cu_def->cd_bbox),
|
|
&DBAllButSpaceAndDRCBits,
|
|
ResConnectWithSD, extUnInit, ResFirst,
|
|
ResEach);
|
|
ExtResetTiles(ResUse->cu_def, extUnInit);
|
|
|
|
/*
|
|
* dissolve the contacts and find which tiles now cover the point
|
|
* where the tile used to be.
|
|
*/
|
|
|
|
ResDissolveContacts(ResContactList);
|
|
|
|
/* Add "junk" fields to tiles */
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
Plane *plane = ResUse->cu_def->cd_planes[pNum];
|
|
Rect *rect = &ResUse->cu_def->cd_bbox;
|
|
ResFracture(plane, rect);
|
|
(void) DBSrPaintClient((Tile *) NULL, plane, rect,
|
|
&DBAllButSpaceAndDRCBits,
|
|
(ClientData) CLIENTDEFAULT, ResAddPlumbing,
|
|
(ClientData) &ResDevList);
|
|
}
|
|
|
|
/* Finish preprocessing. */
|
|
|
|
ResMakePortBreakpoints(ResUse->cu_def);
|
|
ResMakeLabelBreakpoints(ResUse->cu_def, goodies);
|
|
ResFindNewContactTiles(ResContactList);
|
|
ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def);
|
|
|
|
#ifdef LAPLACE
|
|
if (ResOptionsFlags & ResOpt_DoLaplace)
|
|
{
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
Plane *plane = ResUse->cu_def->cd_planes[pNum];
|
|
Rect *rect = &ResUse->cu_def->cd_bbox;
|
|
Res1d(plane, rect);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef ARIEL
|
|
if (ResOptionsFlags & ResOpt_Power)
|
|
{
|
|
for (fix = startlist; fix != NULL; fix = fix->fp_next)
|
|
{
|
|
fix->fp_tile = PlaneGetHint(ResUse->cu_def->cd_planes[DBPlane(fix->fp_ttype)]);
|
|
GOTOPOINT(fix->fp_tile, &fix->fp_loc);
|
|
if (TiGetTypeExact(fix->fp_tile) == TT_SPACE) fix->fp_tile = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* do extraction */
|
|
if (ResProcessTiles(goodies, &startpoint) != 0) return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResCleanUpEverything--After each net is extracted by ResExtractNet,
|
|
* the resulting memory must be freed up, and varius trash swept under
|
|
* the carpet in preparation for the next extraction.
|
|
*
|
|
* Results: none
|
|
*
|
|
* Side Effects: Frees up memory formerly occupied by network elements.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ResCleanUpEverything()
|
|
{
|
|
|
|
int pNum;
|
|
resResistor *oldRes;
|
|
resDevice *oldDev;
|
|
ResContactPoint *oldCon;
|
|
|
|
/* Check integrity of internal database. Free up lists. */
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
(void) DBSrPaintClient((Tile *)NULL, ResUse->cu_def->cd_planes[pNum],
|
|
&(ResUse->cu_def->cd_bbox), &DBAllButSpaceAndDRCBits,
|
|
(ClientData)CLIENTDEFAULT, ResRemovePlumbing,
|
|
(ClientData)NULL);
|
|
}
|
|
|
|
while (ResNodeList != NULL)
|
|
{
|
|
ResCleanNode(ResNodeList, TRUE, &ResNodeList, &ResNodeQueue);
|
|
}
|
|
while (ResContactList != NULL)
|
|
{
|
|
oldCon = ResContactList;
|
|
ResContactList = oldCon->cp_nextcontact;
|
|
freeMagic((char *)oldCon);
|
|
}
|
|
while (ResResList != NULL)
|
|
{
|
|
oldRes = ResResList;
|
|
ResResList = ResResList->rr_nextResistor;
|
|
freeMagic((char *)oldRes);
|
|
}
|
|
while (ResDevList != NULL)
|
|
{
|
|
oldDev = ResDevList;
|
|
ResDevList = ResDevList->rd_nextDev;
|
|
if ((oldDev->rd_status & RES_DEV_SAVE) == 0)
|
|
{
|
|
freeMagic((char *)oldDev->rd_terminals);
|
|
freeMagic((char *)oldDev);
|
|
}
|
|
}
|
|
DBCellClearDef(ResUse->cu_def);
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResGetTileFunc --
|
|
*
|
|
* Callback function used by FindStartTile() when searching for
|
|
* terminal connections of a device that may be on planes other
|
|
* than the plane of the device identifier type. Ignore space
|
|
* tiles. Otherwise, for any tile found, record the tile in
|
|
* the client data record and return 1 to stop the search.
|
|
*
|
|
* Results:
|
|
* Return 0 if tile is a space tile, to keep the search going.
|
|
* Return 1 otherwise to stop the search immediately because
|
|
* a valid start tile has been found.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
ResGetTileFunc(tile, tpptr)
|
|
Tile *tile, **tpptr;
|
|
{
|
|
if (TiGetType(tile) != TT_SPACE)
|
|
{
|
|
*tpptr = tile;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* FindStartTile-- To start the extraction, we need to find the first driver.
|
|
* The sim file gives us the location of a point in or near (within 1
|
|
* unit) of the device. FindStartTile looks for the device, then
|
|
* for adjoining diffusion. The diffusion tile is returned.
|
|
*
|
|
* Results: returns source diffusion tile, if it exists. Otherwise, return
|
|
* NULL.
|
|
*
|
|
* Side Effects: none
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
Tile *
|
|
FindStartTile(goodies, SourcePoint)
|
|
Point *SourcePoint;
|
|
ResGlobalParams *goodies;
|
|
|
|
{
|
|
Point workingPoint;
|
|
Tile *tile, *tp;
|
|
int pnum, t1, t2, i;
|
|
ExtDevice *devptr;
|
|
Rect r;
|
|
bool complex;
|
|
static Stack *devStack = NULL;
|
|
|
|
/* If the drive point is on a contact, check for the contact residues */
|
|
/* first, then the contact type itself. */
|
|
|
|
if (DBIsContact(goodies->rg_ttype))
|
|
{
|
|
TileTypeBitMask *rmask = DBResidueMask(goodies->rg_ttype);
|
|
TileType savtype = goodies->rg_ttype;
|
|
TileType rtype;
|
|
|
|
for (rtype = TT_TECHDEPBASE; rtype < DBNumUserLayers; rtype++)
|
|
if (TTMaskHasType(rmask, rtype))
|
|
{
|
|
goodies->rg_ttype = rtype;
|
|
if ((tile = FindStartTile(goodies, SourcePoint)) != NULL)
|
|
{
|
|
goodies->rg_ttype = savtype;
|
|
return tile;
|
|
}
|
|
}
|
|
goodies->rg_ttype = savtype;
|
|
}
|
|
|
|
workingPoint.p_x = goodies->rg_devloc->p_x;
|
|
workingPoint.p_y = goodies->rg_devloc->p_y;
|
|
|
|
pnum = DBPlane(goodies->rg_ttype);
|
|
|
|
/* for drivepoints, we don't have to find a device */
|
|
if (goodies->rg_status & DRIVEONLY)
|
|
{
|
|
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
|
GOTOPOINT(tile, &workingPoint);
|
|
SourcePoint->p_x = workingPoint.p_x;
|
|
SourcePoint->p_y = workingPoint.p_y;
|
|
|
|
if (TiGetTypeExact(tile) == goodies->rg_ttype)
|
|
return tile;
|
|
else
|
|
{
|
|
/* On the other hand, drivepoints derived from subcircuit */
|
|
/* boundaries lie on tile boundaries, and GOTOPOINT() will */
|
|
/* pick the tile on the wrong side for TOP and RIGHT */
|
|
/* segment coincidences. */
|
|
|
|
if (workingPoint.p_x == LEFT(tile))
|
|
{
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
|
|
if (TiGetRightType(tp) == goodies->rg_ttype)
|
|
return(tp);
|
|
}
|
|
else if (workingPoint.p_y == BOTTOM(tile))
|
|
{
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
|
|
if (TiGetTopType(tp) == goodies->rg_ttype)
|
|
return(tp);
|
|
}
|
|
}
|
|
TxError("Couldn't find wire at %d %d\n",
|
|
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
|
return NULL;
|
|
}
|
|
|
|
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
|
GOTOPOINT(tile, &workingPoint);
|
|
|
|
if (IsSplit(tile))
|
|
{
|
|
if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetLeftType(tile)) != 0)
|
|
{
|
|
t1 = TiGetLeftType(tile);
|
|
TiSetBody(tile, t1 & ~TT_SIDE);
|
|
}
|
|
else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetRightType(tile)) != 0)
|
|
{
|
|
t1 = TiGetRightType(tile);
|
|
TiSetBody(tile, t1 & TT_SIDE);
|
|
}
|
|
else
|
|
{
|
|
TxError("Couldn't find device at %d %d\n",
|
|
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
|
return(NULL);
|
|
}
|
|
}
|
|
else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile)) == 0)
|
|
{
|
|
TxError("Couldn't find device at %d %d\n",
|
|
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
|
return(NULL);
|
|
}
|
|
else
|
|
t1 = TiGetType(tile);
|
|
|
|
/* NOTE: There must be a way to pass the device type from a device
|
|
* record's rs_devptr instead of groping around for it.
|
|
*/
|
|
|
|
for (devptr = ExtCurStyle->exts_device[t1]; devptr; devptr = devptr->exts_next)
|
|
{
|
|
for (i = 0; i < devptr->exts_deviceSDCount; i++)
|
|
{
|
|
complex = FALSE; /* Assume device is a single tile */
|
|
|
|
/* left */
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
|
{
|
|
t2 = TiGetRightType(tp);
|
|
if ((t2 != TT_SPACE) &&
|
|
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
|
{
|
|
SourcePoint->p_x = LEFT(tile);
|
|
SourcePoint->p_y = (MIN(TOP(tile),TOP(tp)) +
|
|
MAX(BOTTOM(tile), BOTTOM(tp))) >> 1;
|
|
return(tp);
|
|
}
|
|
else
|
|
{
|
|
const ClientData ticlient = TiGetClient(tp);
|
|
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
|
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
|
complex = TRUE;
|
|
}
|
|
}
|
|
|
|
/* right */
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
|
{
|
|
t2 = TiGetLeftType(tp);
|
|
if ((t2 != TT_SPACE) &&
|
|
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
|
{
|
|
SourcePoint->p_x = RIGHT(tile);
|
|
SourcePoint->p_y = (MIN(TOP(tile), TOP(tp))+
|
|
MAX(BOTTOM(tile), BOTTOM(tp))) >> 1;
|
|
return(tp);
|
|
}
|
|
else
|
|
{
|
|
const ClientData ticlient = TiGetClient(tp);
|
|
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
|
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
|
complex = TRUE;
|
|
}
|
|
}
|
|
|
|
/* top */
|
|
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
|
{
|
|
t2 = TiGetBottomType(tp);
|
|
if ((t2 != TT_SPACE) &&
|
|
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
|
{
|
|
SourcePoint->p_y = TOP(tile);
|
|
SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp)) +
|
|
MAX(LEFT(tile), LEFT(tp))) >> 1;
|
|
return(tp);
|
|
}
|
|
else
|
|
{
|
|
const ClientData ticlient = TiGetClient(tp);
|
|
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
|
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
|
complex = TRUE;
|
|
}
|
|
}
|
|
|
|
/* bottom */
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
|
{
|
|
t2 = TiGetTopType(tp);
|
|
if ((t2 != TT_SPACE) &&
|
|
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
|
{
|
|
SourcePoint->p_y = BOTTOM(tile);
|
|
SourcePoint->p_x = (MIN(RIGHT(tile), RIGHT(tp)) +
|
|
MAX(LEFT(tile), LEFT(tp))) >> 1;
|
|
return(tp);
|
|
}
|
|
else
|
|
{
|
|
const ClientData ticlient = TiGetClient(tp);
|
|
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
|
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
|
complex = TRUE;
|
|
}
|
|
}
|
|
|
|
if (complex == TRUE)
|
|
{
|
|
/* Didn't find a terminal but device has multiple */
|
|
/* tiles, so make a secondary search looking at all */
|
|
/* tiles of the device. */
|
|
|
|
if (devStack == NULL) devStack = StackNew(8);
|
|
|
|
((tileJunk *)TiGetClientPTR(tile))->tj_status |= RES_TILE_PUSHED;
|
|
STACKPUSH((ClientData)tile, devStack);
|
|
while (!StackEmpty(devStack))
|
|
{
|
|
tile = (Tile *)STACKPOP(devStack);
|
|
|
|
/* left */
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
|
{
|
|
t2 = TiGetRightType(tp);
|
|
if ((t2 != TT_SPACE) &&
|
|
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
|
{
|
|
SourcePoint->p_x = LEFT(tile);
|
|
SourcePoint->p_y = (MIN(TOP(tile),TOP(tp)) +
|
|
MAX(BOTTOM(tile), BOTTOM(tp))) >> 1;
|
|
while (!StackEmpty(devStack))
|
|
{
|
|
STACKPOP(devStack);
|
|
}
|
|
return(tp);
|
|
}
|
|
else
|
|
{
|
|
const ClientData ticlient = TiGetClient(tp);
|
|
if (ticlient != CLIENTDEFAULT)
|
|
{
|
|
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
|
if (tj->tj_status & RES_TILE_DEV)
|
|
{
|
|
if (!(tj->tj_status & RES_TILE_PUSHED))
|
|
{
|
|
tj->tj_status |= RES_TILE_PUSHED;
|
|
STACKPUSH((ClientData)tp, devStack);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* right */
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
|
{
|
|
t2 = TiGetLeftType(tp);
|
|
if ((t2 != TT_SPACE) &&
|
|
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
|
{
|
|
SourcePoint->p_x = RIGHT(tile);
|
|
SourcePoint->p_y = (MIN(TOP(tile), TOP(tp))+
|
|
MAX(BOTTOM(tile), BOTTOM(tp))) >> 1;
|
|
while (!StackEmpty(devStack))
|
|
{
|
|
STACKPOP(devStack);
|
|
}
|
|
return(tp);
|
|
}
|
|
else
|
|
{
|
|
const ClientData ticlient = TiGetClient(tp);
|
|
if (ticlient != CLIENTDEFAULT)
|
|
{
|
|
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
|
if (tj->tj_status & RES_TILE_DEV)
|
|
{
|
|
if (!(tj->tj_status & RES_TILE_PUSHED))
|
|
{
|
|
tj->tj_status |= RES_TILE_PUSHED;
|
|
STACKPUSH((ClientData)tp, devStack);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* top */
|
|
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
|
{
|
|
t2 = TiGetBottomType(tp);
|
|
if ((t2 != TT_SPACE) &&
|
|
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
|
{
|
|
SourcePoint->p_y = TOP(tile);
|
|
SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp)) +
|
|
MAX(LEFT(tile), LEFT(tp))) >> 1;
|
|
while (!StackEmpty(devStack))
|
|
{
|
|
STACKPOP(devStack);
|
|
}
|
|
return(tp);
|
|
}
|
|
else
|
|
{
|
|
const ClientData ticlient = TiGetClient(tp);
|
|
if (ticlient != CLIENTDEFAULT)
|
|
{
|
|
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
|
if (tj->tj_status & RES_TILE_DEV)
|
|
{
|
|
if (!(tj->tj_status & RES_TILE_PUSHED))
|
|
{
|
|
tj->tj_status |= RES_TILE_PUSHED;
|
|
STACKPUSH((ClientData)tp, devStack);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* bottom */
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
|
{
|
|
t2 = TiGetTopType(tp);
|
|
if ((t2 != TT_SPACE) &&
|
|
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
|
{
|
|
SourcePoint->p_y = BOTTOM(tile);
|
|
SourcePoint->p_x = (MIN(RIGHT(tile), RIGHT(tp)) +
|
|
MAX(LEFT(tile), LEFT(tp))) >> 1;
|
|
while (!StackEmpty(devStack))
|
|
{
|
|
STACKPOP(devStack);
|
|
}
|
|
return(tp);
|
|
}
|
|
else
|
|
{
|
|
const ClientData ticlient = TiGetClient(tp);
|
|
if (ticlient != CLIENTDEFAULT)
|
|
{
|
|
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
|
if (tj->tj_status & RES_TILE_DEV)
|
|
{
|
|
if (!(tj->tj_status & RES_TILE_PUSHED))
|
|
{
|
|
tj->tj_status |= RES_TILE_PUSHED;
|
|
STACKPUSH((ClientData)tp, devStack);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Didn't find a terminal (S/D) type tile in the perimeter search. */
|
|
/* Check if S/D types are in a different plane from the identifier. */
|
|
|
|
TiToRect(tile, &r);
|
|
tp = NULL;
|
|
for (i = 0; i < devptr->exts_deviceSDCount; i++)
|
|
{
|
|
for (pnum = 0; pnum < DBNumPlanes; pnum++)
|
|
{
|
|
DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pnum],
|
|
&r, &(devptr->exts_deviceSDTypes[i]), ResGetTileFunc, &tp);
|
|
if (tp != NULL) return tp;
|
|
}
|
|
}
|
|
|
|
/* Is it possible that the net is the substrate under the device? */
|
|
for (pnum = 0; pnum < DBNumPlanes; pnum++)
|
|
{
|
|
DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pnum],
|
|
&r, &(devptr->exts_deviceSubstrateTypes), ResGetTileFunc, &tp);
|
|
if (tp != NULL) return tp;
|
|
}
|
|
}
|
|
|
|
/* If any device type has TT_SPACE as a substrate type, then don't
|
|
* issue an error; however, not handling the substrate as a
|
|
* resistive network is not a good idea and "extresist" needs to use
|
|
* the method employed by "extract" of drawing a substrate type out
|
|
* to the boundary of each subcell.
|
|
*/
|
|
|
|
for (devptr = ExtCurStyle->exts_device[t1]; devptr; devptr = devptr->exts_next)
|
|
if (TTMaskHasType(&(devptr->exts_deviceSubstrateTypes), TT_SPACE))
|
|
break;
|
|
|
|
/* Didn't find a terminal (S/D or substrate) type tile anywhere. Flag an error. */
|
|
|
|
if (devptr == NULL)
|
|
TxError("Couldn't find a terminal of the device at %d %d\n",
|
|
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
|
return((Tile *) NULL);
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* ResGetDevice -- Once the net is extracted, we still have to equate
|
|
* the sim file devices with the layout devices. ResGetDevice
|
|
* looks for a device at the given location. "type" is also
|
|
* specified to that the right plane will be searched.
|
|
*
|
|
* Results: returns device structure at location DevicePoint, if it
|
|
* exists.
|
|
*
|
|
* Side Effects: none
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
resDevice *
|
|
ResGetDevice(pt, type)
|
|
Point *pt;
|
|
TileType type;
|
|
{
|
|
Point workingPoint;
|
|
Tile *tile;
|
|
int pnum;
|
|
|
|
workingPoint.p_x = (*pt).p_x;
|
|
workingPoint.p_y = (*pt).p_y;
|
|
|
|
pnum = DBPlane(type);
|
|
|
|
/* Start at hint tile for device plane */
|
|
|
|
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
|
GOTOPOINT(tile, &workingPoint);
|
|
|
|
const ClientData ticlient = TiGetClient(tile);
|
|
if (IsSplit(tile))
|
|
{
|
|
if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetLeftType(tile))
|
|
|| TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetRightType(tile)))
|
|
return (((tileJunk *)CD2PTR(ticlient))->deviceList);
|
|
}
|
|
else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile)))
|
|
{
|
|
/* Failure to have a valid client data will result in a "Bad Device"
|
|
* error and indicates a problem that needs debugging.
|
|
*/
|
|
if (ticlient != CLIENTDEFAULT)
|
|
return (((tileJunk *)CD2PTR(ticlient))->deviceList);
|
|
}
|
|
return NULL;
|
|
}
|