Reworked the code from the previous commit in a completely different

way.  The code as previously written was undermining other code
written to avoid long run-times on ext2spice, and didn't solve at
least one issue with unnecessary resistor shorts being added to the
netlist output.  The current solution fixes one underlying problem
where a wrongly-placed parenthesis caused the "preferred net name"
routine EFHNBest() not to be run, which prevented original node
names from being preferred over their suffixed versions created by
"extract unique".  However, I also added code to EFbuild.c to
merge unique nodes when the nodes are not really unique.  The
problem is caused by "extract unique" operating only on one level
of hierarchy and being unable to see where nets may connect through
subcircuits.  That can be determined from the "merge" statements
in the .ext file, and now the EFbuild routines will merge these
"false unique" names back into the original net.
This commit is contained in:
R. Timothy Edwards 2025-12-24 16:00:08 -05:00
parent bd417aa54b
commit 949ec7672c
2 changed files with 73 additions and 69 deletions

View File

@ -603,33 +603,57 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
}
if (!equalByCase)
{
if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE)
/* If one of the nodes has been generated from the
* other by "extract unique", then this is a case where
* the "extract unique" algorithm is blind to shorts
* through subcell hierarchy and has made a name unique
* unnecessarily. In that case, merge the node instead
* of generating a short.
*/
char *uniqstr1, *uniqstr2;
bool isuniq;
uniqstr1 = strstr(nodeName1, "_uq");
uniqstr2 = strstr(nodeName2, "_uq");
if (uniqstr1) *uniqstr1 = '\0';
if (uniqstr2) *uniqstr2 = '\0';
isuniq = !strcmp(nodeName1, nodeName2);
if (uniqstr1) *uniqstr1 = '_';
if (uniqstr2) *uniqstr2 = '_';
if (!isuniq)
{
int i;
int sdev;
char *argv[10], zeroarg[] = "0";
if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE)
{
int i;
int sdev;
char *argv[10], zeroarg[] = "0";
if ((EFOutputFlags & EF_SHORT_MASK) == EF_SHORT_R)
sdev = DEV_RES;
if ((EFOutputFlags & EF_SHORT_MASK) == EF_SHORT_R)
sdev = DEV_RES;
else
sdev = DEV_VOLT;
for (i = 0; i < 10; i++) argv[i] = zeroarg;
argv[0] = StrDup((char **)NULL, "0.0");
argv[1] = StrDup((char **)NULL, "dummy");
argv[4] = StrDup((char **)NULL, nodeName1);
argv[7] = StrDup((char **)NULL, nodeName2);
efBuildDevice(def, sdev, "None", &GeoNullRect, 10, argv);
freeMagic(argv[0]);
freeMagic(argv[1]);
freeMagic(argv[4]);
freeMagic(argv[7]);
return;
}
else if (!resist)
TxError("Warning: Ports \"%s\" and \"%s\" are electrically "
"shorted.\n", nodeName1, nodeName2);
else
sdev = DEV_VOLT;
for (i = 0; i < 10; i++) argv[i] = zeroarg;
argv[0] = StrDup((char **)NULL, "0.0");
argv[1] = StrDup((char **)NULL, "dummy");
argv[4] = StrDup((char **)NULL, nodeName1);
argv[7] = StrDup((char **)NULL, nodeName2);
efBuildDevice(def, sdev, "None", &GeoNullRect, 10, argv);
freeMagic(argv[0]);
freeMagic(argv[1]);
freeMagic(argv[4]);
freeMagic(argv[7]);
return;
/* Do not merge the nodes when folding in extresist parasitics */
return;
}
else if (!resist)
TxError("Warning: Ports \"%s\" and \"%s\" are electrically shorted.\n",
nodeName1, nodeName2);
else
else if (resist)
/* Do not merge the nodes when folding in extresist parasitics */
return;
}
@ -653,20 +677,6 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2);
lostnode = efNodeMerge(&nn1->efnn_node, &nn2->efnn_node);
/* Keep the lowest valid port number. This avoids preferring
* names generated by "extract unique" over the original port
* name.
*/
if (nn1->efnn_port > 0)
{
if ((nn2->efnn_port > 0) && (nn2->efnn_port < nn1->efnn_port))
nn1->efnn_port = nn2->efnn_port;
else
nn2->efnn_port = nn1->efnn_port;
}
else if (nn2->efnn_port > 0)
nn1->efnn_port = nn2->efnn_port;
/* Check if there are any device terminals pointing to the
* node that was just removed.
*/
@ -1558,7 +1568,25 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac)
unsigned size = sizeof (Connection)
+ (efNumResistClasses - 1) * sizeof (EFPerimArea);
if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE)
/* If one of the nodes has been generated from the
* other by "extract unique", then this is a case where
* the "extract unique" algorithm is blind to shorts
* through subcell hierarchy and has made a name unique
* unnecessarily. In that case, merge the node instead
* of generating a short.
*/
char *uniqstr1, *uniqstr2;
bool isuniq;
uniqstr1 = strstr(nodeName1, "_uq");
uniqstr2 = strstr(nodeName2, "_uq");
if (uniqstr1) *uniqstr1 = '\0';
if (uniqstr2) *uniqstr2 = '\0';
isuniq = !strcmp(nodeName1, nodeName2);
if (uniqstr1) *uniqstr1 = '_';
if (uniqstr2) *uniqstr2 = '_';
if (!isuniq && ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE))
{
/* Handle the case where two ports on different nets get merged.
* If "extract short resistor" or "extract short voltage" has
@ -1952,10 +1980,9 @@ EFNode *
efNodeMerge(node1ptr, node2ptr)
EFNode **node1ptr, **node2ptr; /* Pointers to hierarchical nodes */
{
EFNodeName *nn, *nnlast, *nn1, *nn2;
EFNodeName *nn, *nnlast;
EFAttr *ap;
int n;
int keep; /* Which node to keep (1 or 2; 0 = unknown) */
EFNode *keeping, *removing;
/* Sanity check: ignore if same node */
@ -1965,31 +1992,9 @@ efNodeMerge(node1ptr, node2ptr)
/*
* Keep the node with the greater number of entries, and merge
* the node with fewer entries into it.
* If one node is a port and the other isn't, keep the port node.
* If both nodes are ports, keep the lowest numbered port. Since
* ports generated by "extract unique" always have higher numbers,
* this will preserve the original name. This is necessary due to
* the "blindness" of "extract unique" to ports being merged
* through connecting geometry in descendent cells. The unique
* suffixes are overused, and ext2spice prunes the unnecessary
* entries but needs to preserve the original node name.
*/
*/
keep = 0;
nn1 = (*node1ptr)->efnode_name;
nn2 = (*node2ptr)->efnode_name;
if (nn1 && (nn1->efnn_port > 0))
{
if (nn2 && (nn2->efnn_port > 0) && (nn2->efnn_port < nn1->efnn_port))
keep = 2;
else
keep = 1;
}
else if (nn2 && nn2->efnn_port > 0)
keep = 2;
if ((keep == 1) || ((keep == 0) &&
((*node1ptr)->efnode_num >= (*node2ptr)->efnode_num)))
if ((*node1ptr)->efnode_num >= (*node2ptr)->efnode_num)
{
keeping = *node1ptr;
removing = *node2ptr;
@ -2027,7 +2032,7 @@ efNodeMerge(node1ptr, node2ptr)
/* Make all EFNodeNames point to "keeping" */
if (removing->efnode_name)
{
bool topportk, topportr;
bool topportk, topportr, bestname;
for (nn = removing->efnode_name; nn; nn = nn->efnn_next)
{
@ -2039,9 +2044,9 @@ efNodeMerge(node1ptr, node2ptr)
topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
/* Concatenate list of EFNodeNames, taking into account precedence */
if ((!keeping->efnode_name) || (!topportk && (topportr
if ((!keeping->efnode_name) || (!topportk && topportr)
|| EFHNBest(removing->efnode_name->efnn_hier,
keeping->efnode_name->efnn_hier))))
keeping->efnode_name->efnn_hier))
{
/*
* New official name is that of "removing".

View File

@ -562,8 +562,7 @@ efAddNodes(
HashSetValue(he, (char *) newname);
newname->efnn_node = newnode;
newname->efnn_hier = hierName;
// keep the port number
newname->efnn_port = node->efnode_name->efnn_port;
newname->efnn_port = -1;
newname->efnn_refc = 0;
if (newnode->efnode_name)
{