1006 lines
26 KiB
C
1006 lines
26 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 "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 Region *ResFirst();
|
||
extern Tile *FindStartTile();
|
||
extern int ResEachTile();
|
||
extern int ResLaplaceTile();
|
||
extern ResSimNode *ResInitializeNode();
|
||
|
||
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, diff;
|
||
char *dev_name;
|
||
ExtDevice *devptr;
|
||
|
||
for (dev = TT_TECHDEPBASE; dev < TT_MAXTYPES; dev++)
|
||
{
|
||
devptr = ExtCurStyle->exts_device[dev];
|
||
if ((devptr != NULL) && ((dev_name = devptr->exts_deviceName) != NULL)
|
||
&& (strcmp(dev_name, "None")))
|
||
{
|
||
for (diff = TT_TECHDEPBASE; diff < TT_MAXTYPES; diff++)
|
||
{
|
||
if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), diff)
|
||
TTMaskSetType(&ResConnectWithSD[diff],dev);
|
||
|
||
if TTMaskHasType(&(devptr->exts_deviceSubstrateTypes),diff)
|
||
TTMaskSetType(&ResConnectWithSD[diff],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__", (char *) NULL);
|
||
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))
|
||
{
|
||
if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, t))
|
||
continue;
|
||
DBPaint(ResUse->cu_def, &(contacts->cp_rect), t);
|
||
}
|
||
}
|
||
|
||
tp = ResDef->cd_planes[DBPlane(contacts->cp_type)]->pl_hint;
|
||
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)
|
||
{
|
||
plane = def->cd_planes[DBPlane(node->rs_ttype)];
|
||
rect = &(node->rs_bbox);
|
||
|
||
TTMaskSetOnlyType(&mask, 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)
|
||
CellDef *def;
|
||
{
|
||
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)
|
||
{
|
||
entry = HashFind(&ResNodeTable, slab->lab_text);
|
||
node = ResInitializeNode(entry);
|
||
|
||
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;
|
||
|
||
plane = def->cd_planes[DBPlane(slab->lab_type)];
|
||
rect = &(node->rs_bbox);
|
||
|
||
TTMaskSetOnlyType(&mask, 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;
|
||
{
|
||
tileJunk *junk;
|
||
|
||
if (tile->ti_client == (ClientData) 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);
|
||
for (pNum=PL_TECHDEPBASE; pNum<DBNumPlanes; pNum++)
|
||
{
|
||
tile = ResDef->cd_planes[pNum]->pl_hint;
|
||
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 *)tile->ti_client;
|
||
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;
|
||
ResFixPoint *fix;
|
||
resNode *resptr;
|
||
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 = ResDef->cd_planes[DBPlane(fix->fp_ttype)]->pl_hint;
|
||
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 *)tile->ti_client)->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 *) tile->ti_client;
|
||
|
||
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 *) tile->ti_client;
|
||
|
||
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);
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------
|
||
*
|
||
* 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(startlist,goodies,cellname)
|
||
ResFixPoint *startlist;
|
||
ResGlobalParams *goodies;
|
||
char *cellname;
|
||
{
|
||
SearchContext scx;
|
||
int pNum;
|
||
ResDevTile *DevTiles,*lasttile;
|
||
TileTypeBitMask FirstTileMask;
|
||
Point startpoint;
|
||
ResFixPoint *fix;
|
||
static int first = 1;
|
||
|
||
/* 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);
|
||
|
||
|
||
/* Copy Paint */
|
||
DevTiles = NULL;
|
||
lasttile = NULL;
|
||
for (fix = startlist; fix != NULL;fix=fix->fp_next)
|
||
{
|
||
ResDevTile *newdevtiles,*tmp;
|
||
|
||
#ifdef ARIEL
|
||
if ((ResOptionsFlags & ResOpt_Power) &&
|
||
strcmp(fix->fp_name,goodies->rg_name) != 0) continue;
|
||
#endif
|
||
|
||
scx.scx_area.r_ll.p_x = fix->fp_loc.p_x-2;
|
||
scx.scx_area.r_ll.p_y = fix->fp_loc.p_y-2;
|
||
scx.scx_area.r_ur.p_x = fix->fp_loc.p_x+2;
|
||
scx.scx_area.r_ur.p_y = fix->fp_loc.p_y+2;
|
||
startpoint = fix->fp_loc;
|
||
TTMaskSetOnlyType(&FirstTileMask,fix->fp_ttype);
|
||
|
||
newdevtiles = DBTreeCopyConnectDCS(&scx, &FirstTileMask, 0,
|
||
ResCopyMask, &TiPlaneRect, ResUse);
|
||
|
||
for (tmp = newdevtiles; tmp && tmp->nextDev; tmp = tmp->nextDev);
|
||
if (newdevtiles)
|
||
{
|
||
if (DevTiles)
|
||
{
|
||
lasttile->nextDev = newdevtiles;
|
||
}
|
||
else
|
||
{
|
||
DevTiles = newdevtiles;
|
||
}
|
||
lasttile = tmp;
|
||
}
|
||
}
|
||
|
||
ExtResetTiles(scx.scx_use->cu_def, extUnInit);
|
||
|
||
/* find all contacts in design and note their position */
|
||
|
||
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);
|
||
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 = ResUse->cu_def->cd_planes[DBPlane(fix->fp_ttype)]->pl_hint;
|
||
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);
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
*-------------------------------------------------------------------------
|
||
*
|
||
* 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;
|
||
ExtDevice *devptr;
|
||
|
||
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 = ResUse->cu_def->cd_planes[pnum]->pl_hint;
|
||
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 = ResUse->cu_def->cd_planes[pnum]->pl_hint;
|
||
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);
|
||
|
||
devptr = ExtCurStyle->exts_device[t1];
|
||
/* left */
|
||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
|
||
{
|
||
t2 = TiGetRightType(tp);
|
||
if (TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t2))
|
||
{
|
||
SourcePoint->p_x = LEFT(tile);
|
||
SourcePoint->p_y = (MIN(TOP(tile),TOP(tp))+
|
||
MAX(BOTTOM(tile),BOTTOM(tp)))>>1;
|
||
return(tp);
|
||
}
|
||
}
|
||
|
||
/* right */
|
||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp))
|
||
{
|
||
t2 = TiGetLeftType(tp);
|
||
if (TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t2))
|
||
{
|
||
SourcePoint->p_x = RIGHT(tile);
|
||
SourcePoint->p_y = (MIN(TOP(tile),TOP(tp))+
|
||
MAX(BOTTOM(tile),BOTTOM(tp)))>>1;
|
||
return(tp);
|
||
}
|
||
}
|
||
|
||
/* top */
|
||
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp=BL(tp))
|
||
{
|
||
t2 = TiGetBottomType(tp);
|
||
if (TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t2))
|
||
{
|
||
SourcePoint->p_y = TOP(tile);
|
||
SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp))+
|
||
MAX(LEFT(tile),LEFT(tp)))>>1;
|
||
return(tp);
|
||
}
|
||
}
|
||
|
||
/* bottom */
|
||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
|
||
{
|
||
t2 = TiGetTopType(tp);
|
||
if (TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t2))
|
||
{
|
||
SourcePoint->p_y = BOTTOM(tile);
|
||
SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp))+
|
||
MAX(LEFT(tile),LEFT(tp)))>>1;
|
||
return(tp);
|
||
}
|
||
}
|
||
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.
|
||
*
|
||
* Results: returns device structure at location DevicePoint, if it
|
||
* exists.
|
||
*
|
||
* Side Effects: none
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
|
||
resDevice *
|
||
ResGetDevice(pt)
|
||
Point *pt;
|
||
|
||
{
|
||
Point workingPoint;
|
||
Tile *tile;
|
||
int pnum;
|
||
|
||
workingPoint.p_x = (*pt).p_x;
|
||
workingPoint.p_y = (*pt).p_y;
|
||
|
||
for (pnum= PL_TECHDEPBASE; pnum < DBNumPlanes; pnum++)
|
||
{
|
||
if (TTMaskIntersect(&ExtCurStyle->exts_deviceMask,&DBPlaneTypes[pnum]) == 0)
|
||
{
|
||
continue;
|
||
}
|
||
/*start at hint tile for device plane */
|
||
tile = ResUse->cu_def->cd_planes[pnum]->pl_hint;
|
||
GOTOPOINT(tile,&workingPoint);
|
||
|
||
if (IsSplit(tile))
|
||
{
|
||
if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetLeftType(tile))
|
||
|| TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetRightType(tile)))
|
||
return(((tileJunk *)tile->ti_client)->deviceList);
|
||
}
|
||
else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile)))
|
||
{
|
||
return(((tileJunk *)tile->ti_client)->deviceList);
|
||
}
|
||
}
|
||
return (NULL);
|
||
}
|