1036 lines
26 KiB
C
1036 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__");
|
|
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);
|
|
|
|
/* 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++;
|
|
}
|
|
|
|
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;
|
|
|
|
/* Because fix->fp_ttype might come from a label with a sticky type
|
|
* that does not correspond exactly to the layer underneath, include
|
|
* all connecting types.
|
|
*/
|
|
TTMaskZero(&FirstTileMask);
|
|
TTMaskSetMask(&FirstTileMask, &DBConnectTbl[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;
|
|
|
|
/* 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 = 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;
|
|
}
|