Corrected an error in the original resistor network simplifying

routine that marks resistors in loops to prevent infinite
recursion, but later incorrectly eliminates those resistors.
Also:  Changed the "tolerance" command to affect only the R-C
time constant tolerance.  Added a "threshold" command option
that limits output of small resistors.  This can help reduce
large networks that are otherwise not reducible by the three
methods of reduction (serial, parallel, and delta-wye), but
does affect output values (slightly).  This will probably need
to be revisited at some point.
This commit is contained in:
Tim Edwards 2023-09-28 17:15:27 -04:00
parent 656b5dbabe
commit 088bb828ac
2 changed files with 89 additions and 59 deletions

View File

@ -96,9 +96,9 @@ struct saveList {
/* Structure stores information required to be sent to ExtResisForDef() */ /* Structure stores information required to be sent to ExtResisForDef() */
typedef struct typedef struct
{ {
float tolerance;
float tdiTolerance; float tdiTolerance;
float frequency; float frequency;
float rthresh;
struct saveList *savePlanes; struct saveList *savePlanes;
CellDef *mainDef; CellDef *mainDef;
} ResisData; } ResisData;
@ -118,14 +118,14 @@ ExtResisForDef(celldef, resisdata)
CellDef *celldef; CellDef *celldef;
ResisData *resisdata; ResisData *resisdata;
{ {
RDev *oldRDev; RDev *oldRDev;
HashSearch hs; HashSearch hs;
HashEntry *entry; HashEntry *entry;
devPtr *tptr, *oldtptr; devPtr *tptr, *oldtptr;
ResSimNode *node; ResSimNode *node;
int result, idx; int result, idx;
char *devname; char *devname;
Plane *savePlane; Plane *savePlane;
ResRDevList = NULL; ResRDevList = NULL;
ResOriginalNodes = NULL; ResOriginalNodes = NULL;
@ -150,18 +150,18 @@ ExtResisForDef(celldef, resisdata)
idx = 0; idx = 0;
while (ExtGetDevInfo(idx++, &devname, NULL, NULL, NULL, NULL, NULL)) while (ExtGetDevInfo(idx++, &devname, NULL, NULL, NULL, NULL, NULL))
{ {
if (idx == TT_MAXTYPES) if (idx == TT_MAXTYPES)
{ {
TxError("Error: Ran out of space for device types!\n"); TxError("Error: Ran out of space for device types!\n");
break; break;
} }
efBuildAddStr(EFDevTypes, &EFDevNumTypes, TT_MAXTYPES, devname); efBuildAddStr(EFDevTypes, &EFDevNumTypes, TT_MAXTYPES, devname);
} }
HashInit(&ResNodeTable, INITFLATSIZE, HT_STRINGKEYS); HashInit(&ResNodeTable, INITFLATSIZE, HT_STRINGKEYS);
/* read in .sim file */ /* read in .sim file */
result = (ResReadSim(celldef->cd_name, result = (ResReadSim(celldef->cd_name,
ResSimDevice, ResSimCapacitor, ResSimResistor, ResSimDevice, ResSimCapacitor, ResSimResistor,
ResSimAttribute, ResSimMerge, ResSimSubckt) == 0); ResSimAttribute, ResSimMerge, ResSimSubckt) == 0);
/* Clean up the EFDevTypes table */ /* Clean up the EFDevTypes table */
@ -212,7 +212,7 @@ ExtResisForDef(celldef, resisdata)
HashKill(&ResNodeTable); HashKill(&ResNodeTable);
while (ResRDevList != NULL) while (ResRDevList != NULL)
{ {
oldRDev = ResRDevList; oldRDev = ResRDevList;
ResRDevList = ResRDevList->nextDev; ResRDevList = ResRDevList->nextDev;
if (oldRDev->layout != NULL) if (oldRDev->layout != NULL)
{ {
@ -223,7 +223,6 @@ ExtResisForDef(celldef, resisdata)
} }
} }
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
@ -241,12 +240,13 @@ ExtResisForDef(celldef, resisdata)
void void
CmdExtResis(win, cmd) CmdExtResis(win, cmd)
MagWindow *win; MagWindow *win;
TxCommand *cmd; TxCommand *cmd;
{ {
int i, j, k, option, value, saveFlags; int i, j, k, option, value, saveFlags;
static int init = 1; static int init = 1;
static float tolerance, tdiTolerance, fhFrequency; static float rthresh, tdiTolerance, fhFrequency;
CellDef *mainDef; CellDef *mainDef;
CellUse *selectedUse; CellUse *selectedUse;
ResisData resisdata; ResisData resisdata;
@ -264,8 +264,9 @@ CmdExtResis(win, cmd)
static char *cmdExtresisCmd[] = static char *cmdExtresisCmd[] =
{ {
"tolerance [value] set ratio between resistor and device tol.",
"all extract all the nets", "all extract all the nets",
"threshold [value] set minimum resistor extraction threshold",
"tolerance [value] set ratio between resistor and device tol.",
"simplify [on/off] turn on/off simplification of resistor nets", "simplify [on/off] turn on/off simplification of resistor nets",
"extout [on/off] turn on/off writing of .res.ext file", "extout [on/off] turn on/off writing of .res.ext file",
"lumped [on/off] turn on/off writing of updated lumped resistances", "lumped [on/off] turn on/off writing of updated lumped resistances",
@ -286,8 +287,9 @@ CmdExtResis(win, cmd)
}; };
typedef enum { typedef enum {
RES_BAD=-2, RES_AMBIG, RES_TOL, RES_BAD=-2, RES_AMBIG, RES_ALL,
RES_ALL, RES_SIMP, RES_EXTOUT, RES_LUMPED, RES_SILENT, RES_THRESH, RES_TOL,
RES_SIMP, RES_EXTOUT, RES_LUMPED, RES_SILENT,
RES_SKIP, RES_IGNORE, RES_INCLUDE, RES_BOX, RES_CELL, RES_SKIP, RES_IGNORE, RES_INCLUDE, RES_BOX, RES_CELL,
RES_BLACKBOX, RES_FASTHENRY, RES_GEOMETRY, RES_HELP, RES_BLACKBOX, RES_FASTHENRY, RES_GEOMETRY, RES_HELP,
#ifdef LAPLACE #ifdef LAPLACE
@ -303,7 +305,7 @@ typedef enum {
TTMaskZero(&(ResCopyMask[i])); TTMaskZero(&(ResCopyMask[i]));
TTMaskSetMask(&ResCopyMask[i], &DBConnectTbl[i]); TTMaskSetMask(&ResCopyMask[i], &DBConnectTbl[i]);
} }
tolerance = 1; rthresh = 0;
tdiTolerance = 1; tdiTolerance = 1;
fhFrequency = 10e6; /* 10 MHz default */ fhFrequency = 10e6; /* 10 MHz default */
HashInit(&ResIgnoreTable, INITFLATSIZE, HT_STRINGKEYS); HashInit(&ResIgnoreTable, INITFLATSIZE, HT_STRINGKEYS);
@ -350,13 +352,12 @@ typedef enum {
ResOptionsFlags |= ResOpt_ExplicitRtol; ResOptionsFlags |= ResOpt_ExplicitRtol;
if (cmd->tx_argc > 2) if (cmd->tx_argc > 2)
{ {
tolerance = MagAtof(cmd->tx_argv[2]); tdiTolerance = MagAtof(cmd->tx_argv[2]);
if (tolerance <= 0) if (tdiTolerance <= 0)
{ {
TxError("Usage: %s tolerance [value]\n", cmd->tx_argv[0]); TxError("Usage: %s tolerance [value]\n", cmd->tx_argv[0]);
return; return;
} }
tdiTolerance = tolerance;
} }
else else
{ {
@ -368,6 +369,26 @@ typedef enum {
} }
return; return;
case RES_THRESH:
if (cmd->tx_argc > 2)
{
rthresh = MagAtof(cmd->tx_argv[2]);
if (rthresh < 0)
{
TxError("Usage: %s threshold [value]\n", cmd->tx_argv[0]);
return;
}
}
else
{
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewDoubleObj((double)rthresh));
#else
TxPrintf("Resistance threshold is %g.\n", rthresh);
#endif
}
return;
case RES_ALL: case RES_ALL:
ResOptionsFlags |= ResOpt_ExtractAll; ResOptionsFlags |= ResOpt_ExtractAll;
break; break;
@ -648,7 +669,7 @@ typedef enum {
ResOptionsFlags &= ~ResOpt_Power; ResOptionsFlags &= ~ResOpt_Power;
#endif #endif
resisdata.tolerance = tolerance; resisdata.rthresh = rthresh;
resisdata.tdiTolerance = tdiTolerance; resisdata.tdiTolerance = tdiTolerance;
resisdata.frequency = fhFrequency; resisdata.frequency = fhFrequency;
resisdata.mainDef = mainDef; resisdata.mainDef = mainDef;
@ -964,13 +985,13 @@ ResCheckSimNodes(celldef, resisdata)
{ {
ResSimNode *node; ResSimNode *node;
devPtr *ptr; devPtr *ptr;
float ftolerance, rctolerance, minRes, cumRes; float ftolerance, minRes, cumRes;
int failed1=0; int failed1=0;
int failed3=0; int failed3=0;
int total =0; int total =0;
char *outfile = celldef->cd_name; char *outfile = celldef->cd_name;
float tol = resisdata->tolerance;
float rctol = resisdata->tdiTolerance; float rctol = resisdata->tdiTolerance;
float rthresh = resisdata->rthresh;
int nidx = 1, eidx = 1; /* node & segment counters for geom. */ int nidx = 1, eidx = 1; /* node & segment counters for geom. */
if (ResOptionsFlags & ResOpt_DoExtFile) if (ResOptionsFlags & ResOpt_DoExtFile)
@ -1166,16 +1187,10 @@ ResCheckSimNodes(celldef, resisdata)
continue; continue;
} }
gparams.rg_bigdevres = (int)minRes * OHMSTOMILLIOHMS; gparams.rg_bigdevres = (int)minRes * OHMSTOMILLIOHMS;
if ((rctol == 0.0) || (tol == 0.0)) if (minRes > resisdata->rthresh)
{ ftolerance = minRes;
ftolerance = 0.0;
rctolerance = 0.0;
}
else else
{ ftolerance = resisdata->rthresh;
ftolerance = minRes / tol;
rctolerance = minRes / rctol;
}
/* /*
* Is the device resistance greater than the lumped node * Is the device resistance greater than the lumped node
@ -1201,11 +1216,10 @@ ResCheckSimNodes(celldef, resisdata)
ResWriteLumpFile(node); ResWriteLumpFile(node);
} }
if (gparams.rg_maxres >= ftolerance || if (gparams.rg_maxres >= ftolerance ||
gparams.rg_maxres >= rctolerance ||
(ResOptionsFlags & ResOpt_ExtractAll)) (ResOptionsFlags & ResOpt_ExtractAll))
{ {
resNodeNum = 0; resNodeNum = 0;
failed3 += ResWriteExtFile(celldef, node, tol, rctol, failed3 += ResWriteExtFile(celldef, node, rctol,
&nidx, &eidx); &nidx, &eidx);
} }
} }
@ -1780,10 +1794,10 @@ ResAlignNodes(nodelist, reslist)
*/ */
int int
ResWriteExtFile(celldef, node, tol, rctol, nidx, eidx) ResWriteExtFile(celldef, node, rctol, nidx, eidx)
CellDef *celldef; CellDef *celldef;
ResSimNode *node; ResSimNode *node;
float tol, rctol; float rctol;
int *nidx, *eidx; int *nidx, *eidx;
{ {
float RCdev; float RCdev;
@ -1793,7 +1807,7 @@ ResWriteExtFile(celldef, node, tol, rctol, nidx, eidx)
RCdev = gparams.rg_bigdevres * gparams.rg_nodecap; RCdev = gparams.rg_bigdevres * gparams.rg_nodecap;
if (tol == 0.0 || (node->status & FORCE) || if ((node->status & FORCE) ||
(ResOptionsFlags & ResOpt_ExtractAll) || (ResOptionsFlags & ResOpt_ExtractAll) ||
(ResOptionsFlags & ResOpt_Simplify) == 0 || (ResOptionsFlags & ResOpt_Simplify) == 0 ||
(rctol + 1) * RCdev < rctol * gparams.rg_Tdi) (rctol + 1) * RCdev < rctol * gparams.rg_Tdi)

View File

@ -41,7 +41,6 @@ void ResSetPathRes();
void resPathNode(); void resPathNode();
void resPathRes(); void resPathRes();
Heap ResistorHeap; Heap ResistorHeap;
int resRemoveLoops = FALSE;
/* Forward declarations */ /* Forward declarations */
@ -810,10 +809,12 @@ ResPruneTree(node, minTdi, nodelist1, nodelist2, resistorlist)
{ {
currentRes = current->re_thisEl; currentRes = current->re_thisEl;
current = current->re_nextEl; current = current->re_nextEl;
/* if branch points outward, call routine on subtrees */ /* Ignore previously found loops */
if (currentRes->rr_connection1 == node) if (!(currentRes->rr_status & RES_TDI_IGNORE))
ResPruneTree(currentRes->rr_connection2, minTdi, nodelist1, /* If branch points outward, call routine on subtrees */
nodelist2, resistorlist); if (currentRes->rr_connection1 == node)
ResPruneTree(currentRes->rr_connection2, minTdi, nodelist1,
nodelist2, resistorlist);
} }
/* We eliminate this branch if: /* We eliminate this branch if:
@ -863,7 +864,6 @@ ResDoSimplify(tolerance, rctol, goodies)
float totalcap; float totalcap;
resResistor *res; resResistor *res;
resRemoveLoops = FALSE;
ResSetPathRes(); ResSetPathRes();
for (node = ResNodeList; node != NULL; node = node->rn_more) for (node = ResNodeList; node != NULL; node = node->rn_more)
bigres = MAX(bigres, node->rn_noderes); bigres = MAX(bigres, node->rn_noderes);
@ -893,12 +893,16 @@ ResDoSimplify(tolerance, rctol, goodies)
res = res->rr_nextResistor; res = res->rr_nextResistor;
oldres->rr_status &= ~RES_HEAP; oldres->rr_status &= ~RES_HEAP;
/*------ NOTE: resistors marked with RES_TDI_IGNORE are
* part of loops but should NOT be removed.
if (oldres->rr_status & RES_TDI_IGNORE) if (oldres->rr_status & RES_TDI_IGNORE)
{ {
ResDeleteResPointer(oldres->rr_node[0], oldres); ResDeleteResPointer(oldres->rr_node[0], oldres);
ResDeleteResPointer(oldres->rr_node[1], oldres); ResDeleteResPointer(oldres->rr_node[1], oldres);
ResEliminateResistor(oldres, &ResResList); ResEliminateResistor(oldres, &ResResList);
} }
------*/
} }
if (ResOptionsFlags & ResOpt_Tdi) if (ResOptionsFlags & ResOpt_Tdi)
@ -1045,7 +1049,12 @@ ResSetPathRes()
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* resPathNode ---
* *
* Given node "node", add every resistor connected to the node, and
* for which the node on the other side has not been processed, to
* the heap. Node is marked with FINISHED to prevent going 'round
* and 'round loops.
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1073,6 +1082,18 @@ resPathNode(node)
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
* resPathRes ---
*
* Given resistor "res" pulled from the heap (in heap order, which
* is the highest valued resistor currently in the heap):
*
* If both ends of the resistor have been processed, then we have
* a loop, and should return.
*
* Otherwise, call resPathNode() on the node of whichever end of
* the resistor has not yet been processed, thus continuing through
* the path from the origin.
*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1093,12 +1114,7 @@ resPathRes(res)
if (flag0 && flag1) if (flag0 && flag1)
{ {
res->rr_status |= RES_TDI_IGNORE; res->rr_status |= RES_TDI_IGNORE;
if (resRemoveLoops) /* Loop found---return without calling resPathNode() */
{
ResDeleteResPointer(node0, res);
ResDeleteResPointer(node1, res);
ResEliminateResistor(res, &ResResList);
}
} }
else if (flag0) else if (flag0)
{ {