The method committed yesterday (last commit) was found to be too

time-consuming (note the commit message "There are still likely much
better ways to do this").  Worked out a method of hashing the location
of terminals on other planes so that they can be looked up from the
address of the tile.  This requires only one pass through the devices
to locate and record the terminals, and no loops through devices when
processing tiles.  Also corrected the positioning of the substrate
terminal to be the center position of the device tile, not the substrate
tile.  This not only better represents the substrate connections, but
it also eliminates the condition in which many thousands of resistors
converge on the same point, which causes stack overflow.  With the
current scheme, stack overflow is unlikely to occur.
This commit is contained in:
R. Timothy Edwards 2026-06-06 20:04:47 -04:00
parent 1db2567841
commit 14afb4bd52
6 changed files with 194 additions and 33 deletions

View File

@ -1 +1 @@
8.3.658
8.3.659

View File

@ -230,9 +230,9 @@ ResStartTile(tile, x, y)
#define IGNORE_BOTTOM 8
bool
ResEachTile(tile, devTiles)
ResEachTile(tile, devNodeTable)
Tile *tile; /* Tile being processed */
ResDevTile *devTiles; /* List of device tiles for reference */
HashTable *devNodeTable; /* Table of tiles connected to devices */
{
Tile *tp;
resNode *resptr;
@ -244,6 +244,7 @@ ResEachTile(tile, devTiles)
resInfo *tstructs = (resInfo *)TiGetClientPTR(tile);
ExtDevice *devptr;
int sides;
HashEntry *he;
ResTileCount++;
@ -457,6 +458,41 @@ ResEachTile(tile, devTiles)
/* Note: Need to tag these tiles per device to avoid checking through */
/* the device list for each tile. (To be done) */
he = HashLookOnly(devNodeTable, (char *)tile);
if (he != NULL)
{
resDevTerm *resdevRec, *resdevList;
Tile *devtile;
resdevList = (resDevTerm *)HashGetValue(he);
while (resdevList != NULL)
{
resdevRec = resdevList;
/* Set the position from the device, not the current tile */
devtile = resdevRec->rdt_tile;
xj = (RIGHT(devtile) + LEFT(devtile)) / 2;
yj = (TOP(devtile) + BOTTOM(devtile)) / 2;
if (resdevRec->rdt_term == -1) /* Substrate */
{
ResNewSubDevice(tile, resdevRec->rdt_tile, xj, yj,
OTHERPLANE, &ResNodeQueue);
}
else /* Terminal */
{
ResNewTermDevice(tile, resdevRec->rdt_tile, resdevRec->rdt_term,
xj, yj, OTHERPLANE, &ResNodeQueue);
}
resdevList = resdevList->rdt_next;
freeMagic(resdevRec);
}
HashSetValue(he, (char *)NULL); /* Done with hash record */
}
#if 0
/* Deprecated: Searching through all devices for all tiles is
* irresponsibly slow. Do not do this.
*/
if (TTMaskHasType(&ResTermTypesBitMask, t1))
{
Rect r;
@ -527,6 +563,7 @@ ResEachTile(tile, devTiles)
}
}
}
#endif /* 0 */
tstructs->ri_status |= RES_TILE_DONE;

View File

@ -697,10 +697,10 @@ ResFindNewContactTiles(contacts)
*/
int
ResProcessTiles(resisdata, origin, devices)
ResProcessTiles(resisdata, origin, devNodeTable)
ResisData *resisdata;
Point *origin;
ResDevTile *devices;
HashTable *devNodeTable;
{
Tile *startTile;
int tilenum, merged;
@ -718,7 +718,7 @@ ResProcessTiles(resisdata, origin, devices)
return 1;
resCurrentNode = NULL;
ResStartTile(startTile, origin->p_x, origin->p_y);
(void) ResEachTile(startTile, devices);
(void) ResEachTile(startTile, devNodeTable);
}
#ifdef PARANOID
else
@ -755,7 +755,7 @@ ResProcessTiles(resisdata, origin, devices)
if ((ri->ri_status & RES_TILE_DONE) == 0)
{
resCurrentNode = resptr2;
merged |= ResEachTile(tile, devices);
merged |= ResEachTile(tile, devNodeTable);
}
}
rj->rj_status = TRUE;
@ -781,7 +781,7 @@ ResProcessTiles(resisdata, origin, devices)
if (cp->cp_cnode[tilenum] == resptr2)
{
resCurrentNode = resptr2;
merged |= ResEachTile(tile, devices);
merged |= ResEachTile(tile, devNodeTable);
}
else
{
@ -1210,6 +1210,9 @@ ResExtractNet(node, resisdata, cellname)
int resMakeDevFunc();
int resExpandDevFunc();
int result;
HashTable DevNodeTable;
HashSearch hs;
HashEntry *he;
/* Make sure all global network variables are reset */
@ -1453,11 +1456,29 @@ ResExtractNet(node, resisdata, cellname)
/* Finish preprocessing. */
ResFindNewContactTiles(ResContactList);
ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def);
HashInit(&DevNodeTable, HT_DEFAULTSIZE, HT_CLIENTKEYS);
ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def, &DevNodeTable);
/* do extraction */
result = ResProcessTiles(resisdata, &startpoint, DevTiles);
ResFreeDevTiles(DevTiles);
result = ResProcessTiles(resisdata, &startpoint, &DevNodeTable);
/* Free remaining table entries (if any) */
HashStartSearch(&hs);
while ((he = HashNext(&DevNodeTable, &hs)) != NULL)
{
resDevTerm *resdevList, *resdevNext;
resdevList = (resDevTerm *)HashGetValue(he);
while (resdevList)
{
resdevNext = resdevList->rdt_next;
freeMagic((char *)resdevList);
resdevList = resdevNext;
}
}
HashKill(&DevNodeTable);
if (result != 0) return TRUE;
return FALSE;
}

View File

@ -186,6 +186,9 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
p2->br_this->rn_float.rn_area += height * (p2->br_loc.p_x - LEFT(tile));
while (p2->br_next != NULL)
{
p1 = p2;
p2 = p2->br_next;
/* Has the node been recorded as needing to be replaced? */
if (count >= 16)
{
@ -196,8 +199,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
p2->br_this = (resNode *)HashGetValue(he);
}
}
p1 = p2;
p2 = p2->br_next;
if (p2->br_loc.p_x == p1->br_loc.p_x)
{
if (p2->br_this == p1->br_this)
@ -396,6 +398,9 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
p2->br_this->rn_float.rn_area += width * (p2->br_loc.p_y - BOTTOM(tile));
while (p2->br_next != NULL)
{
p1 = p2;
p2 = p2->br_next;
/* Has the node been recorded as needing to be replaced? */
if (count >= 16)
{
@ -406,8 +411,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
p2->br_this = (resNode *)HashGetValue(he);
}
}
p1 = p2;
p2 = p2->br_next;
if (p1->br_loc.p_y == p2->br_loc.p_y)
{
if (p2->br_this == p1->br_this)

View File

@ -858,12 +858,17 @@ ResFreeDevTiles(TileList)
/*
*-------------------------------------------------------------------------
*
* ResPreProcessDevices-- Given a list of all the device tiles and
* a list of all the devices, this procedure calculates the width and
* length. The width is set equal to the sum of all edges that touch
* diffusion divided by 2. The length is the remaining perimeter divided by
* 2*tiles. The perimeter and area fields of device structures are also
* fixed.
* ResPreProcessDevices --
*
* Given a list of all the device tiles and a list of all the devices, this
* procedure calculates the width and length. The width is set equal to the
* sum of all edges that touch diffusion divided by 2. The length is the
* remaining perimeter divided by 2*tiles. The perimeter and area fields of
* device structures are also fixed.
*
* Each device is checked for terminals and substrate on a plane other than
* the plane of the device type. If so, find the tile on that plane
* directly under the device.
*
* Results: none
*
@ -873,20 +878,21 @@ ResFreeDevTiles(TileList)
*/
void
ResPreProcessDevices(TileList, DeviceList, Def)
ResPreProcessDevices(TileList, DeviceList, Def, devNodeTable)
ResDevTile *TileList;
resDevice *DeviceList;
CellDef *Def;
HashTable *devNodeTable;
{
Tile *tile;
ResDevTile *devTile;
ResDevTile *oldTile;
resInfo *tstruct;
TileType tt, residue;
int pNum;
for (devTile = TileList; devTile; devTile = devTile->nextDev)
while (TileList != (ResDevTile *)NULL)
{
tt = devTile->type;
tt = TileList->type;
if (DBIsContact(tt))
{
/* Find which residue of the contact is a device. */
@ -910,7 +916,7 @@ ResPreProcessDevices(TileList, DeviceList, Def)
pNum = DBPlane(tt); /* always correct for non-contact types */
tile = PlaneGetHint(Def->cd_planes[pNum]);
GOTOPOINT(tile, &(devTile->area.r_ll));
GOTOPOINT(tile, &(TileList->area.r_ll));
PlaneSetHint(Def->cd_planes[pNum], tile);
tt = TiGetType(tile);
@ -921,20 +927,103 @@ ResPreProcessDevices(TileList, DeviceList, Def)
!TTMaskHasType(&ExtCurStyle->exts_deviceMask, tt))
{
TxError("Bad Device Location at %d,%d\n",
devTile->area.r_ll.p_x,
devTile->area.r_ll.p_y);
TileList->area.r_ll.p_x,
TileList->area.r_ll.p_y);
}
else if ((tstruct->ri_status & RES_TILE_MARK) == 0)
{
resDevice *rd = tstruct->deviceList;
ExtDevice *devptr;
int i;
Tile *tp;
TileType ttype;
PlaneMask pmask;
TileTypeBitMask termMask, subMask;
resDevTerm *resdevRec, *resdevList;
HashEntry *he;
tstruct->ri_status |= RES_TILE_MARK;
rd->rd_perim += devTile->perim;
rd->rd_length += devTile->overlap;
rd->rd_area += (devTile->area.r_xtop - devTile->area.r_xbot)
* (devTile->area.r_ytop - devTile->area.r_ybot);
rd->rd_perim += TileList->perim;
rd->rd_length += TileList->overlap;
rd->rd_area += (TileList->area.r_xtop - TileList->area.r_xbot)
* (TileList->area.r_ytop - TileList->area.r_ybot);
rd->rd_tiles++;
/* Get the device record */
devptr = TileList->devptr;
TTMaskZero(&subMask);
TTMaskSetMask(&subMask, &devptr->exts_deviceSubstrateTypes);
/* Remove TT_SPACE from mask or else all planes will be flagged */
TTMaskClearType(&subMask, TT_SPACE);
pmask = DBTechTypesToPlanes(&subMask);
if ((pmask != 0) && !PlaneMaskHasPlane(pmask, DBPlane(tt)))
{
/* Record substrate tile if it exists */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (PlaneMaskHasPlane(pmask, pNum))
{
tp = PlaneGetHint(Def->cd_planes[pNum]);
GOTOPOINT(tp, &(TileList->area.r_ll));
PlaneSetHint(Def->cd_planes[pNum], tp);
ttype = TiGetType(tp);
if (TTMaskHasType(&subMask, ttype))
{
he = HashFind(devNodeTable, (char *)tp);
resdevList = (resDevTerm *)HashGetValue(he);
resdevRec = (resDevTerm *)mallocMagic(sizeof(resDevTerm));
resdevRec->rdt_term = -1; /* Indicates substrate */
resdevRec->rdt_tile = tile;
resdevRec->rdt_next = resdevList;
HashSetValue(he, (char *)resdevRec);
}
}
}
}
/* Record terminal tiles on other planes, if they exist */
for (i = 0; i < devptr->exts_deviceSDCount; i++)
{
TTMaskZero(&termMask);
TTMaskSetMask(&termMask, &devptr->exts_deviceSDTypes[i]);
/* Remove TT_SPACE from mask or else all planes will be flagged */
TTMaskClearType(&termMask, TT_SPACE);
pmask = DBTechTypesToPlanes(&termMask);
if ((pmask != 0) && !PlaneMaskHasPlane(pmask, DBPlane(tt)))
{
/* Record terminal tile if it exists */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (PlaneMaskHasPlane(pmask, pNum))
{
tp = PlaneGetHint(Def->cd_planes[pNum]);
GOTOPOINT(tp, &(TileList->area.r_ll));
PlaneSetHint(Def->cd_planes[pNum], tp);
ttype = TiGetType(tp);
if (TTMaskHasType(&termMask, ttype))
{
he = HashFind(devNodeTable, (char *)tp);
resdevList = (resDevTerm *)HashGetValue(he);
resdevRec = (resDevTerm *)mallocMagic(sizeof(resDevTerm));
resdevRec->rdt_term = i;
resdevRec->rdt_tile = tile;
resdevRec->rdt_next = resdevList;
HashSetValue(he, (char *)resdevRec);
}
}
}
}
}
}
/* Free up memory from the devTile list */
oldTile = TileList;
TileList = TileList->nextDev;
freeMagic((char *)oldTile);
}
for (; DeviceList != NULL; DeviceList = DeviceList->rd_nextDev)
@ -965,7 +1054,6 @@ ResPreProcessDevices(TileList, DeviceList, Def)
}
}
/*
*-------------------------------------------------------------------------
*

View File

@ -51,6 +51,17 @@ typedef struct resistor
#define rr_connection1 rr_node[0]
#define rr_connection2 rr_node[1]
/* The resDevTerm structure holds information needed to quickly check */
/* if a tile belongs to a terminal of a device in a plane other than */
/* the plane of the device. */
typedef struct resdevterm
{
struct resdevterm *rdt_next; /* next connected device in the list */
Tile *rdt_tile; /* the tile of the device */
int rdt_term; /* terminal number, or -1 for substrate */
} resDevTerm;
/* Definitions for old FET-style MOSFET devices. Actual devices may have
* any number of terminals. "GATE" is the identifying type; "SUBS" is
* the substrate/well connection (if it exists), and the other terminals