Added a fallback method for "extresist" whenever a device terminal

connection to a net that has been decomposed into a resistor array
cannot be found.  This indicates some fundamental error in the way
extresist works.  However, it should not be producing an invalid
and unsimulatable netlist.  Instead, it makes an arbitrary connection
from the device terminal to the resistor array and adds an entry in
the output netlist (.res.ext file).  This results in a poor
representation of the resistor network to that terminal, but an
otherwise simulatable netlist.  A warning is issued to note that an
arbitrary connection has been made.  This is most typically a
"garbage in, garbage out" situation in which insufficient information
exists in a layout to inform magic on which direction current is
traveling through a net.  However, it should be possible to rewrite
the extresist code so that magic makes somewhat informed decisions
about current paths and produces a halfway decent representation of
the actual net, instead of just giving up on the detailed extraction.
This commit is contained in:
Tim Edwards 2025-01-15 10:38:10 -05:00
parent 4445663cb1
commit 72368a3d13
4 changed files with 59 additions and 16 deletions

View File

@ -1 +1 @@
8.3.514
8.3.515

View File

@ -212,39 +212,54 @@ ResPrintExtDev(outextfile, devices)
*/
void
ResPrintExtNode(outextfile, nodelist, nodename)
ResPrintExtNode(outextfile, nodelist, node)
FILE *outextfile;
resNode *nodelist;
char *nodename;
ResSimNode *node;
{
char *nodename = node->name;
int nodenum = 0;
char newname[MAXNAME+32], tmpname[MAXNAME], *cp;
HashEntry *entry;
ResSimNode *node, *ResInitializeNode();
ResSimNode *newnode, *ResInitializeNode();
bool DoKillNode = TRUE;
resNode *snode = nodelist;
bool NeedFix = FALSE;
resNode *snode;
/* If any of the subnode names match the original node name, then */
/* we don't want to rip out that node with a "killnode" statement. */
for (; nodelist != NULL; nodelist = nodelist->rn_more)
for (snode = nodelist; snode != NULL; snode = snode->rn_more)
{
if (nodelist->rn_name != NULL)
if (!strcmp(nodelist->rn_name, nodename))
if (snode->rn_name != NULL)
if (!strcmp(snode->rn_name, nodename))
{
DoKillNode = FALSE;
break;
}
}
/* If any device terminal failed to extract for any reason, then */
/* this node cannot be killed. If it is already marked for killing */
/* then there are no connections from the node to any of its sub- */
/* nodes, so create one an flag a warning. Note that this */
/* condition indicates a fundamental underlying error in device */
/* extraction, but this prevents magic from generating an invalid */
/* netlist. */
if (node->status & DONTKILL)
if (DoKillNode == TRUE)
{
DoKillNode = FALSE;
NeedFix = TRUE;
}
if ((ResOptionsFlags & ResOpt_DoExtFile) && DoKillNode)
{
fprintf(outextfile, "killnode \"%s\"\n", nodename);
}
fprintf(outextfile, "killnode \"%s\"\n", nodename);
/* Create "rnode" entries for each subnode */
for (; snode != NULL; snode = snode->rn_more)
for (snode = nodelist; snode != NULL; snode = snode->rn_more)
{
if (snode->rn_name == NULL)
{
@ -255,9 +270,9 @@ ResPrintExtNode(outextfile, nodelist, nodename)
(void)sprintf(newname, "%s%s%d", tmpname, ".n", nodenum++);
entry = HashFind(&ResNodeTable, newname);
node = ResInitializeNode(entry);
snode->rn_name = node->name;
node->oldname = nodename;
newnode = ResInitializeNode(entry);
snode->rn_name = newnode->name;
newnode->oldname = nodename;
}
if (ResOptionsFlags & ResOpt_DoExtFile)
@ -272,6 +287,18 @@ ResPrintExtNode(outextfile, nodelist, nodename)
0);
}
}
if (NeedFix)
{
/* Patch up the output netlist for an orphaned node by
* creating a zero-valued resistance between it and the
* first subnode (arbitrary connection). Flag a warning.
*/
fprintf(outextfile, "resist \"%s\" \"%s\" 0.0\n",
node->name, nodelist->rn_name);
TxError("Warning: Orphaned node \"%s\" arbitrarily attached to \"%s\"\n",
node->name, nodelist->rn_name);
}
}
/*

View File

@ -1363,9 +1363,12 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
}
else
{
TxError("Missing gate connection of device at (%d %d) on net %s\n",
layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
nodename);
simNode->status |= DONTKILL;
}
}
if (simDev->subs == simNode)
{
@ -1381,9 +1384,12 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
}
else
{
TxError("Missing substrate connection of device at (%d %d) on net %s\n",
layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
nodename);
simNode->status |= DONTKILL;
}
}
if (simDev->source == simNode)
@ -1425,9 +1431,12 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
/* one to each */
}
else
{
TxError("Missing terminal connection of device at (%d %d) on net %s\n",
layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
nodename);
simNode->status |= DONTKILL;
}
}
else
{
@ -1468,9 +1477,12 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
}
else
{
TxError("Missing terminal connection of device at (%d %d) on net %s\n",
layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
nodename);
simNode->status |= DONTKILL;
}
}
}
else if (simDev->drain == simNode)
@ -1525,9 +1537,12 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
drain->rn_name = simDev->drain->name;
}
else
{
TxError("Missing terminal connection of device at (%d %d) on net %s\n",
layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
nodename);
simNode->status |= DONTKILL;
}
}
else
resNodeNum--;
@ -1845,7 +1860,7 @@ ResWriteExtFile(celldef, node, rctol, nidx, eidx)
}
if (ResOptionsFlags & ResOpt_DoExtFile)
{
ResPrintExtNode(ResExtFile, ResNodeList, node->name);
ResPrintExtNode(ResExtFile, ResNodeList, node);
ResPrintExtRes(ResExtFile, ResResList, newname);
}
if (ResOptionsFlags & ResOpt_FastHenry)

View File

@ -494,6 +494,7 @@ typedef struct capval
#define DRIVELOC 0x0000100
#define PORTNODE 0x0000200
#define REDUNDANT 0x0000400
#define DONTKILL 0x0000800
/* Capacitance table constants */
#define RES_CAP_GND 0