Changed the behavior of capacitance value output in ext2spice

and ext2sim to make use of the new esSIvalue() routine, so that
it no longer depends on a preformatted string.  Corrected an
issue where the esSIvalue() routine would output "a" for "atto"
which is not supported by ngspice.
This commit is contained in:
Tim Edwards 2023-03-13 13:21:34 -04:00
parent c077e1acef
commit a3f5f4db80
4 changed files with 86 additions and 90 deletions

View File

@ -62,7 +62,6 @@ bool esNoAttrs = FALSE;
bool esHierAP = FALSE; bool esHierAP = FALSE;
bool esMergeDevsA = FALSE; /* merge devices of equal length */ bool esMergeDevsA = FALSE; /* merge devices of equal length */
bool esMergeDevsC = FALSE; /* merge devices of equal length & width */ bool esMergeDevsC = FALSE; /* merge devices of equal length & width */
int esCapAccuracy = 1;
#else #else
extern bool esDevNodesOnly; extern bool esDevNodesOnly;
@ -70,7 +69,8 @@ extern bool esNoAttrs;
extern bool esHierAP; extern bool esHierAP;
extern bool esMergeDevsA; extern bool esMergeDevsA;
extern bool esMergeDevsC; extern bool esMergeDevsC;
extern int esCapAccuracy; extern char esSpiceDefaultGnd[];
extern char *esSpiceCapNode;
#endif #endif
bool esDoSimExtResis = FALSE; bool esDoSimExtResis = FALSE;
@ -690,11 +690,10 @@ runexttosim:
EFVisitDevs(simdevVisit, (ClientData)NULL); EFVisitDevs(simdevVisit, (ClientData)NULL);
if (flatFlags & EF_FLATCAPS) { if (flatFlags & EF_FLATCAPS) {
(void) sprintf( esCapFormat, " %%.%dlf\n", esCapAccuracy);
EFVisitCaps(simcapVisit, (ClientData) NULL); EFVisitCaps(simcapVisit, (ClientData) NULL);
} }
EFVisitResists(simresistVisit, (ClientData) NULL); EFVisitResists(simresistVisit, (ClientData) NULL);
(void) sprintf( esCapFormat, " GND %%.%dlf\n", esCapAccuracy); esSpiceCapNode = esSpiceDefaultGnd;
EFVisitNodes(simnodeVisit, (ClientData) NULL); EFVisitNodes(simnodeVisit, (ClientData) NULL);
EFFlatDone(NULL); EFFlatDone(NULL);
@ -817,12 +816,10 @@ main(argc, argv)
} }
EFVisitDevs(simdevVisit, (ClientData) NULL); EFVisitDevs(simdevVisit, (ClientData) NULL);
if (flatFlags & EF_FLATCAPS) { if (flatFlags & EF_FLATCAPS)
(void) sprintf( esCapFormat, " %%.%dlf\n", esCapAccuracy);
EFVisitCaps(simcapVisit, (ClientData) NULL); EFVisitCaps(simcapVisit, (ClientData) NULL);
}
EFVisitResists(simresistVisit, (ClientData) NULL); EFVisitResists(simresistVisit, (ClientData) NULL);
(void) sprintf( esCapFormat, " GND %%.%dlf\n", esCapAccuracy); esSpiceCapNode = esSpiceDefaultGnd;
EFVisitNodes(simnodeVisit, (ClientData) NULL); EFVisitNodes(simnodeVisit, (ClientData) NULL);
EFFlatDone(NULL); EFFlatDone(NULL);
@ -922,7 +919,7 @@ simParseArgs(pargc, pargv)
if (( t = ArgStr(&argc, &argv, "cap-accuracy") ) == NULL) if (( t = ArgStr(&argc, &argv, "cap-accuracy") ) == NULL)
goto usage; goto usage;
esCapAccuracy = atoi(t); TxPrintf("Cap accuracy option -y is deprecated.\n");
break; break;
} }
case 'J': case 'J':
@ -1535,7 +1532,7 @@ int simcapVisit(hierName1, hierName2, cap)
EFHNOut(hierName1, esSimF); EFHNOut(hierName1, esSimF);
fprintf(esSimF, " "); fprintf(esSimF, " ");
EFHNOut(hierName2, esSimF); EFHNOut(hierName2, esSimF);
fprintf(esSimF, esCapFormat, cap); fprintf(esSimF, " %.1lf\n", cap);
return 0; return 0;
} }
@ -1618,7 +1615,8 @@ int simnodeVisit(node, res, cap)
{ {
fprintf(esSimF, "C "); fprintf(esSimF, "C ");
EFHNOut(hierName, esSimF); EFHNOut(hierName, esSimF);
fprintf(esSimF, esCapFormat, cap); fprintf(esSimF, "%s ", esSpiceCapNode);
fprintf(esSimF, "%.1f\n", cap);
} }
if (res > EFResistThreshold) if (res > EFResistThreshold)
{ {

View File

@ -902,7 +902,7 @@ spcdevHierVisit(hc, dev, scale)
/* Capacitor is "Cnnn top bottom value" */ /* Capacitor is "Cnnn top bottom value" */
/* extraction sets top=gate bottom=source */ /* extraction sets top=gate bottom=source */
/* extracted units are fF; output is in fF */ /* extracted units are fF. */
spcdevOutNode(hc->hc_hierName, spcdevOutNode(hc->hc_hierName,
gate->dterm_node->efnode_name->efnn_hier, gate->dterm_node->efnode_name->efnn_hier,
@ -920,8 +920,7 @@ spcdevHierVisit(hc, dev, scale)
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " %ffF", (double)sdM * esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
(double)(dev->dev_cap));
spcHierWriteParams(hc, dev, scale, l, w, sdM); spcHierWriteParams(hc, dev, scale, l, w, sdM);
} }
else else
@ -950,7 +949,7 @@ spcdevHierVisit(hc, dev, scale)
/* Capacitor is "Cnnn bottom top value" */ /* Capacitor is "Cnnn bottom top value" */
/* extraction sets top=source bottom=gate */ /* extraction sets top=source bottom=gate */
/* extracted units are fF; output is in fF */ /* extracted units are fF. */
spcdevOutNode(hc->hc_hierName, spcdevOutNode(hc->hc_hierName,
gate->dterm_node->efnode_name->efnn_hier, gate->dterm_node->efnode_name->efnn_hier,
@ -968,8 +967,7 @@ spcdevHierVisit(hc, dev, scale)
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " %ffF", (double)sdM * esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
(double)(dev->dev_cap));
spcHierWriteParams(hc, dev, scale, l, w, sdM); spcHierWriteParams(hc, dev, scale, l, w, sdM);
} }
else else
@ -1226,9 +1224,11 @@ spccapHierVisit(hc, hierName1, hierName2, cap)
if (fabs(cap) <= EFCapThreshold) if (fabs(cap) <= EFCapThreshold)
return 0; return 0;
fprintf(esSpiceF, esSpiceCapFormat, esCapNum++, fprintf(esSpiceF, "C%d %s %s ", esCapNum++,
nodeSpiceHierName(hc, hierName1), nodeSpiceHierName(hc, hierName1),
nodeSpiceHierName(hc, hierName2), cap); nodeSpiceHierName(hc, hierName2));
esSIvalue(esSpiceF, 1.0E-15 *cap);
fprintf(esSpiceF, "\n");
return 0; return 0;
} }
@ -1397,10 +1397,14 @@ spcnodeHierVisit(hc, node, res, cap)
cap = cap / 1000; cap = cap / 1000;
if (fabs(cap) > EFCapThreshold) if (fabs(cap) > EFCapThreshold)
{ {
fprintf(esSpiceF, esSpiceCapFormat, esCapNum++, nsn, cap, fprintf(esSpiceF, "C%d %s %s ", esCapNum++, nsn, esSpiceCapNode);
(isConnected) ? "" : esSIvalue(esSpiceF, 1.0E-15 * cap);
(esFormat == NGSPICE) ? " $ **FLOATING" : if (!isConnected)
" **FLOATING"); {
if (esFormat == NGSPICE) fprintf(esSpiceF, " $");
fprintf(esSpiceF, " **FLOATING");
}
fprintf(esSpiceF, "\n");
} }
if (node->efnode_attrs && !esNoAttrs) if (node->efnode_attrs && !esNoAttrs)
{ {
@ -2121,18 +2125,17 @@ esHierVisit(hc, cdata)
EFHierVisitResists(hcf, spcresistHierVisit, (ClientData)NULL); EFHierVisitResists(hcf, spcresistHierVisit, (ClientData)NULL);
/* Output coupling capacitances */ /* Output coupling capacitances */
sprintf( esSpiceCapFormat, "C%%d %%s %%s %%.%dlffF\n", esCapAccuracy);
EFHierVisitCaps(hcf, spccapHierVisit, (ClientData)NULL); EFHierVisitCaps(hcf, spccapHierVisit, (ClientData)NULL);
if (EFCompat == FALSE) if (EFCompat == FALSE)
{ {
/* Find the substrate node */ /* Find the substrate node */
EFHierVisitNodes(hcf, spcsubHierVisit, (ClientData)&resstr); EFHierVisitNodes(hcf, spcsubHierVisit, (ClientData)&resstr);
if (resstr == NULL) resstr = StrDup((char **)NULL, "0"); if (resstr == NULL)
resstr = esSpiceDefaultGnd;
/* Output lumped capacitance and resistance to substrate */ /* Output lumped capacitance and resistance to substrate */
sprintf( esSpiceCapFormat, "C%%d %%s %s %%.%dlffF%%s\n", esSpiceCapNode = resstr;
resstr, esCapAccuracy);
EFHierVisitNodes(hcf, spcnodeHierVisit, (ClientData) NULL); EFHierVisitNodes(hcf, spcnodeHierVisit, (ClientData) NULL);
freeMagic(resstr); freeMagic(resstr);
} }

View File

@ -56,8 +56,8 @@ bool esMergeNames = TRUE;
bool esNoAttrs = FALSE; bool esNoAttrs = FALSE;
bool esHierAP = FALSE; bool esHierAP = FALSE;
char spcesDefaultOut[FNSIZE]; char spcesDefaultOut[FNSIZE];
int esCapAccuracy = 2; char *esSpiceCapNode;
char esSpiceCapFormat[FNSIZE]; char esSpiceDefaultGnd[] = "0";
char *spcesOutName = spcesDefaultOut; char *spcesOutName = spcesDefaultOut;
FILE *esSpiceF = NULL; FILE *esSpiceF = NULL;
float esScale = -1.0 ; /* negative if hspice the EFScale/100 otherwise */ float esScale = -1.0 ; /* negative if hspice the EFScale/100 otherwise */
@ -1116,21 +1116,17 @@ runexttospice:
EFVisitDevs(spcdevVisit, (ClientData) NULL); EFVisitDevs(spcdevVisit, (ClientData) NULL);
TTMaskZero(&initMask); TTMaskZero(&initMask);
if (flatFlags & EF_FLATCAPS) if (flatFlags & EF_FLATCAPS)
{
(void) sprintf( esSpiceCapFormat, "C%%d %%s %%s %%.%dlffF\n",
esCapAccuracy);
EFVisitCaps(spccapVisit, (ClientData) NULL); EFVisitCaps(spccapVisit, (ClientData) NULL);
}
EFVisitResists(spcresistVisit, (ClientData) NULL); EFVisitResists(spcresistVisit, (ClientData) NULL);
EFVisitSubcircuits(subcktVisit, (ClientData) NULL); EFVisitSubcircuits(subcktVisit, (ClientData) NULL);
/* Visit nodes to find the substrate node */ /* Visit nodes to find the substrate node */
EFVisitNodes(spcsubVisit, (ClientData)&substr); EFVisitNodes(spcsubVisit, (ClientData)&substr);
if (substr == NULL) if (substr == NULL)
substr = StrDup((char **)NULL, "0"); substr = esSpiceDefaultGnd;
(void) sprintf( esSpiceCapFormat, "C%%d %%s %s %%.%dlffF%%s", esSpiceCapNode = substr;
substr, esCapAccuracy);
EFVisitNodes(spcnodeVisit, (ClientData) NULL); EFVisitNodes(spcnodeVisit, (ClientData) NULL);
if (EFCompat == FALSE) freeMagic(substr); if (EFCompat == FALSE) freeMagic(substr);
@ -1295,13 +1291,12 @@ main(argc, argv)
EFVisitDevs(devDistJunctVisit, (ClientData) NULL); EFVisitDevs(devDistJunctVisit, (ClientData) NULL);
EFVisitDevs(spcdevVisit, (ClientData) NULL); EFVisitDevs(spcdevVisit, (ClientData) NULL);
TTMaskZero(&initMask); TTMaskZero(&initMask);
if (flatFlags & EF_FLATCAPS) { if (flatFlags & EF_FLATCAPS)
(void) sprintf( esSpiceCapFormat, "C%%d %%s %%s %%.%dlffF\n",esCapAccuracy);
EFVisitCaps(spccapVisit, (ClientData) NULL); EFVisitCaps(spccapVisit, (ClientData) NULL);
}
EFVisitResists(spcresistVisit, (ClientData) NULL); EFVisitResists(spcresistVisit, (ClientData) NULL);
EFVisitSubcircuits(subcktVisit, (ClientData) NULL); EFVisitSubcircuits(subcktVisit, (ClientData) NULL);
(void) sprintf( esSpiceCapFormat, "C%%d %%s GND %%.%dlffF%%s", esCapAccuracy); esSpiceCapNode = esSpiceDefaultGnd;
EFVisitNodes(spcnodeVisit, (ClientData) NULL); EFVisitNodes(spcnodeVisit, (ClientData) NULL);
if ((esDoSubckt == TRUE) || (locDoSubckt == TRUE)) if ((esDoSubckt == TRUE) || (locDoSubckt == TRUE))
@ -1359,10 +1354,10 @@ spcParseArgs(pargc, pargv)
{ {
char **argv = *pargv, *cp; char **argv = *pargv, *cp;
int argc = *pargc; int argc = *pargc;
char *ftmp, *t;
char usage_text[] = "Usage: ext2spice " char usage_text[] = "Usage: ext2spice "
"[-B] [-o spicefile] [-M|-m] [-y cap_digits] " "[-B] [-o spicefile] [-M|-m] [-J flat|hier]\n"
"[-J flat|hier]\n"
"[-f spice2|spice3|hspice|ngspice] [-M] [-m] " "[-f spice2|spice3|hspice|ngspice] [-M] [-m] "
"[file]\n"; "[file]\n";
@ -1371,66 +1366,66 @@ spcParseArgs(pargc, pargv)
case 'd': case 'd':
esDistrJunct = TRUE; esDistrJunct = TRUE;
break; break;
case 'M': case 'M':
esMergeDevsA = TRUE; esMergeDevsA = TRUE;
break; break;
case 'm': case 'm':
esMergeDevsC = TRUE; esMergeDevsC = TRUE;
break; break;
case 'B': case 'B':
esNoAttrs = TRUE; esNoAttrs = TRUE;
break; break;
case 'F': case 'F':
esDevNodesOnly = TRUE; esDevNodesOnly = TRUE;
break; break;
case 'o': case 'o':
if ((spcesOutName = ArgStr(&argc, &argv, "filename")) == NULL) if ((spcesOutName = ArgStr(&argc, &argv, "filename")) == NULL)
goto usage; goto usage;
break; break;
case 'f': {
char *ftmp ;
if ((ftmp = ArgStr(&argc, &argv, "format")) == NULL) case 'f':
if ((ftmp = ArgStr(&argc, &argv, "format")) == NULL)
goto usage; goto usage;
if (strcasecmp(ftmp, "SPICE2") == 0) if (strcasecmp(ftmp, "SPICE2") == 0)
esFormat = SPICE2; esFormat = SPICE2;
else if (strcasecmp(ftmp, "SPICE3") == 0) else if (strcasecmp(ftmp, "SPICE3") == 0)
esFormat = SPICE3; esFormat = SPICE3;
else if (strcasecmp(ftmp, "HSPICE") == 0) else if (strcasecmp(ftmp, "HSPICE") == 0)
{ {
esFormat = HSPICE; esFormat = HSPICE;
esScale = -1.0; esScale = -1.0;
} }
else if (strcasecmp(ftmp, "NGSPICE") == 0) else if (strcasecmp(ftmp, "NGSPICE") == 0)
esFormat = NGSPICE; esFormat = NGSPICE;
else goto usage; else goto usage;
break; break;
}
case 'J': case 'J':
{ if ((ftmp = ArgStr(&argc, &argv, "hierAP_SD")) == NULL)
char *ftmp ;
if ((ftmp = ArgStr(&argc, &argv, "hierAP_SD")) == NULL)
goto usage; goto usage;
if ( strcasecmp(ftmp, "HIER") == 0 ) if ( strcasecmp(ftmp, "HIER") == 0 )
esHierAP = TRUE ; esHierAP = TRUE ;
else if ( strcasecmp(ftmp, "FLAT") == 0 ) else if (strcasecmp(ftmp, "FLAT") == 0 )
esHierAP = FALSE ; esHierAP = FALSE ;
else goto usage; else goto usage;
break; break;
}
case 'y': {
char *t;
if (( t = ArgStr(&argc, &argv, "cap-accuracy") ) == NULL) case 'y':
if ((t = ArgStr(&argc, &argv, "cap-accuracy")) == NULL)
goto usage; goto usage;
esCapAccuracy = atoi(t); TxPrintf("The cap accuracy flag 'y' is deprecated.\n");
break; break;
}
case 'h': /* -h or -help, as suggested by "ext2spice help" */ case 'h': /* -h or -help, as suggested by "ext2spice help" */
TxPrintf(usage_text); TxPrintf(usage_text);
break; break;
default: default:
TxError("Unrecognized flag: %s\n", argv[0]); TxError("Unrecognized flag: %s\n", argv[0]);
goto usage; goto usage;
@ -2822,7 +2817,7 @@ spcdevVisit(dev, hc, scale, trans)
/* Capacitor is "Cnnn top bottom value" */ /* Capacitor is "Cnnn top bottom value" */
/* extraction sets top=gate bottom=source */ /* extraction sets top=gate bottom=source */
/* extracted units are fF; output is in fF */ /* extracted units are fF. */
spcdevOutNode(hierName, gate->dterm_node->efnode_name->efnn_hier, spcdevOutNode(hierName, gate->dterm_node->efnode_name->efnn_hier,
name, esSpiceF); name, esSpiceF);
@ -2838,8 +2833,7 @@ spcdevVisit(dev, hc, scale, trans)
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " %ffF", (double)sdM * esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
(double)(dev->dev_cap));
spcWriteParams(dev, hierName, scale, l, w, sdM); spcWriteParams(dev, hierName, scale, l, w, sdM);
} }
else else
@ -2866,7 +2860,7 @@ spcdevVisit(dev, hc, scale, trans)
/* Capacitor is "Cnnn bottom top value" */ /* Capacitor is "Cnnn bottom top value" */
/* extraction sets top=source bottom=gate */ /* extraction sets top=source bottom=gate */
/* extracted units are fF; output is in fF */ /* extracted units are fF. */
spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier, spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier,
name, esSpiceF); name, esSpiceF);
@ -2882,8 +2876,7 @@ spcdevVisit(dev, hc, scale, trans)
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " %ffF", (double)sdM * esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
(double)(dev->dev_cap));
spcWriteParams(dev, hierName, scale, l, w, sdM); spcWriteParams(dev, hierName, scale, l, w, sdM);
} }
else else
@ -3113,13 +3106,9 @@ esSIvalue(file, value)
{ {
/* Do nothing---value is probably zero */ /* Do nothing---value is probably zero */
} }
else if (avalue < 1.0E-15)
{
suffix = 'a';
value *= 1.0E18;
}
else if (avalue < 1.0E-12) else if (avalue < 1.0E-12)
{ {
/* NOTE: ngspice does not support "a" for "atto" */
suffix = 'f'; suffix = 'f';
value *= 1.0E15; value *= 1.0E15;
} }
@ -3155,9 +3144,9 @@ esSIvalue(file, value)
} }
if (suffix == '\0') if (suffix == '\0')
fprintf(file, "%g", value); fprintf(file, "%.3g", value);
else else
fprintf(file, "%g%c", value, suffix); fprintf(file, "%.3g%c", value, suffix);
} }
/* /*
@ -3470,8 +3459,10 @@ spccapVisit(hierName1, hierName2, cap)
if (cap <= EFCapThreshold) if (cap <= EFCapThreshold)
return 0; return 0;
fprintf(esSpiceF, esSpiceCapFormat ,esCapNum++,nodeSpiceName(hierName1, NULL), fprintf(esSpiceF, "C%d %s %s ", esCapNum++, nodeSpiceName(hierName1, NULL),
nodeSpiceName(hierName2, NULL), cap); nodeSpiceName(hierName2, NULL));
esSIvalue(esSpiceF, 1.0E-15 * cap);
fprintf(esSpiceF, "\n");
return 0; return 0;
} }
@ -3638,10 +3629,14 @@ spcnodeVisit(node, res, cap)
cap = cap / 1000; cap = cap / 1000;
if (cap > EFCapThreshold) if (cap > EFCapThreshold)
{ {
fprintf(esSpiceF, esSpiceCapFormat, esCapNum++, nsn, cap, fprintf(esSpiceF, "C%d %s %s ", esCapNum++, nsn, esSpiceCapNode);
(isConnected) ? "\n" : esSIvalue(esSpiceF, 1.0E-15 * cap);
(esFormat == NGSPICE) ? " $ **FLOATING\n" : if (!isConnected)
" **FLOATING\n"); {
if (esFormat == NGSPICE) fprintf(esSpiceF, " $");
fprintf(esSpiceF, " **FLOATING");
}
fprintf(esSpiceF, "\n");
} }
if (node->efnode_attrs && !esNoAttrs) if (node->efnode_attrs && !esNoAttrs)
{ {

View File

@ -65,8 +65,8 @@ extern bool esDevNodesOnly;
extern bool esNoAttrs; extern bool esNoAttrs;
extern bool esHierAP; extern bool esHierAP;
extern char spcesDefaultOut[FNSIZE]; extern char spcesDefaultOut[FNSIZE];
extern int esCapAccuracy; extern char *esSpiceCapNode;
extern char esSpiceCapFormat[FNSIZE]; extern char esSpiceDefaultGnd[];
extern char *spcesOutName; extern char *spcesOutName;
extern FILE *esSpiceF; extern FILE *esSpiceF;
extern float esScale; /* negative if hspice the EFScale/100 otherwise */ extern float esScale; /* negative if hspice the EFScale/100 otherwise */