Corrected an error in EFbuild.c in routine efBuildDevice(), which

had one error and one missing method.  The error was an incorrect
argument count for regular (not subcircuit) FETs and BJTs.  The
missing method was to handle parameters w0, w1, w2, etc., like
l0, l1, l2, . . .   Those had been defined for output in ExtBasic.c
but were not being handled on input from the .ext file.  This fix
corresponds more or less to PR #480 on github, although that PR
incorrectly addressed the argument numbering problem, so I have
redone the code changes by hand.
This commit is contained in:
R. Timothy Edwards 2026-01-09 11:51:11 -05:00
parent a93d248a5a
commit d24d52e403
2 changed files with 74 additions and 38 deletions

View File

@ -1 +1 @@
8.3.589 8.3.590

View File

@ -860,13 +860,13 @@ efBuildDevice(
const Rect *r, /* Coordinates of 1x1 rectangle entirely inside device */ const Rect *r, /* Coordinates of 1x1 rectangle entirely inside device */
int argc, /* Size of argv */ int argc, /* Size of argv */
char *argv[]) /* Tokens for the rest of the dev line. char *argv[]) /* Tokens for the rest of the dev line.
* Starts with the last two position values, used to * Starts after the four device coordinate arguments.
* hash the device record. The next arguments depend * The next arguments (0, 1, or 2) depend on the type of
* on the type of device. The rest are taken in groups * device, followed by optional parameters. The rest are
* of 3, one for each terminal. Each group of 3 consists * taken in groups of 3, one for each terminal. Each
* of the node name to which the terminal connects, the * group of 3 consists of the node name to which the
* length of the terminal, and an attribute list (or the * terminal connects, the length of the terminal, and
* token 0). * an attribute list (or the token 0).
*/ */
{ {
int n, nterminals, pn; int n, nterminals, pn;
@ -878,7 +878,7 @@ efBuildDevice(
int dev_type; int dev_type;
char ptype, *pptr, **av; char ptype, *pptr, **av;
char devhash[64]; char devhash[64];
int argstart = 1; /* start of terminal list in argv[] */ int termstart;
bool hasModel = strcmp(type, "None") ? TRUE : FALSE; bool hasModel = strcmp(type, "None") ? TRUE : FALSE;
int area, perim; /* Total area, perimeter of primary type (i.e., channel) */ int area, perim; /* Total area, perimeter of primary type (i.e., channel) */
@ -893,24 +893,37 @@ efBuildDevice(
devtmp.dev_width = 0; devtmp.dev_width = 0;
devtmp.dev_params = NULL; devtmp.dev_params = NULL;
termstart = 1; /* Start of terminal list in argv[]; this is a default
* value if none of the cases below applies. The value
* of termstart does not initially account for parameter
* entries (<param>=<value>) but is adjusted as the
* parameters are parsed. The first terminal may be an
* (optional) substrate which is determined by whether
* the number of remaining arguments is divisible by 3
* or not.
*/
switch (class) switch (class)
{ {
case DEV_FET: case DEV_FET:
case DEV_MOSFET: case DEV_MOSFET:
case DEV_ASYMMETRIC: case DEV_ASYMMETRIC:
case DEV_BJT: case DEV_BJT:
argstart = 3; /* Terminals start after L and W values, plus parameters */
termstart = 2;
break; break;
case DEV_DIODE: case DEV_DIODE:
case DEV_NDIODE: case DEV_NDIODE:
case DEV_PDIODE: case DEV_PDIODE:
argstart = 0; /* Terminals start immediately after parameters */
termstart = 0;
break; break;
case DEV_RES: case DEV_RES:
case DEV_CAP: case DEV_CAP:
case DEV_CAPREV: case DEV_CAPREV:
if (hasModel) if (hasModel)
argstart = 2; /* Terminals start after L and W values, plus parameters */
termstart = 2;
/* Otherwise, terminals start after device value, plus parameters */
break; break;
case DEV_SUBCKT: case DEV_SUBCKT:
case DEV_VERILOGA: case DEV_VERILOGA:
@ -918,13 +931,14 @@ efBuildDevice(
case DEV_RSUBCKT: case DEV_RSUBCKT:
case DEV_CSUBCKT: case DEV_CSUBCKT:
case DEV_DSUBCKT: case DEV_DSUBCKT:
argstart = 0; /* Terminals start immediately after parameters */
termstart = 0;
} }
devp = efGetDeviceParams(type); devp = efGetDeviceParams(type);
/* Parse initial arguments for parameters */ /* Parse initial arguments for parameters */
while ((pptr = strchr(argv[argstart], '=')) != NULL) while ((pptr = strchr(argv[termstart], '=')) != NULL)
{ {
/* If the parameter is in the parameter list "devp", then save /* If the parameter is in the parameter list "devp", then save
* the value as appropriate. If not, then the entire phrase * the value as appropriate. If not, then the entire phrase
@ -936,7 +950,7 @@ efBuildDevice(
*pptr = '\0'; *pptr = '\0';
for (sparm = devp; sparm; sparm = sparm->parm_next) for (sparm = devp; sparm; sparm = sparm->parm_next)
if (!strncasecmp(sparm->parm_type, argv[argstart], 2)) if (!strncasecmp(sparm->parm_type, argv[termstart], 2))
break; break;
*pptr = '='; *pptr = '=';
if (sparm == NULL) if (sparm == NULL)
@ -944,18 +958,18 @@ efBuildDevice(
/* Copy the whole string into dev_params */ /* Copy the whole string into dev_params */
/* (parm_type and parm_scale records are not used) */ /* (parm_type and parm_scale records are not used) */
newparm = (DevParam *)mallocMagic(sizeof(DevParam)); newparm = (DevParam *)mallocMagic(sizeof(DevParam));
newparm->parm_name = StrDup((char **)NULL, argv[argstart]); newparm->parm_name = StrDup((char **)NULL, argv[termstart]);
newparm->parm_next = devtmp.dev_params; newparm->parm_next = devtmp.dev_params;
devtmp.dev_params = newparm; devtmp.dev_params = newparm;
argstart++; termstart++;
continue; continue;
} }
pptr++; pptr++;
switch(*argv[argstart]) switch(*argv[termstart])
{ {
case 'a': case 'a':
if ((pptr - argv[argstart]) == 2) if ((pptr - argv[termstart]) == 2)
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr) devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
* locScale * locScale); * locScale * locScale);
else else
@ -963,7 +977,7 @@ efBuildDevice(
/* Check for a0, a1, a2, ... If a0, handle like "a". /* Check for a0, a1, a2, ... If a0, handle like "a".
* Otherwise, don't handle it here. * Otherwise, don't handle it here.
*/ */
pn = *(argv[argstart] + 1) - '0'; pn = *(argv[termstart] + 1) - '0';
if (pn == 0) if (pn == 0)
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr) devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
* locScale * locScale); * locScale * locScale);
@ -971,21 +985,21 @@ efBuildDevice(
break; break;
case 'p': case 'p':
if ((pptr - argv[argstart]) == 2) if ((pptr - argv[termstart]) == 2)
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
else else
{ {
/* Check for p0, p1, p2, ... If p0, handle like "p". /* Check for p0, p1, p2, ... If p0, handle like "p".
* Otherwise, don't handle it here. * Otherwise, don't handle it here.
*/ */
pn = *(argv[argstart] + 1) - '0'; pn = *(argv[termstart] + 1) - '0';
if (pn == 0) if (pn == 0)
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
} }
break; break;
case 'l': case 'l':
if ((pptr - argv[argstart]) == 2) if ((pptr - argv[termstart]) == 2)
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
else else
{ {
@ -995,14 +1009,14 @@ efBuildDevice(
* values like "a1, a2, ..." or "p1, p2, ...". * values like "a1, a2, ..." or "p1, p2, ...".
*/ */
pn = *(argv[argstart] + 1) - '0'; pn = *(argv[termstart] + 1) - '0';
if (pn == 0) if (pn == 0)
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
else else
{ {
/* Copy the whole string into dev_params */ /* Copy the whole string into dev_params */
newparm = (DevParam *)mallocMagic(sizeof(DevParam)); newparm = (DevParam *)mallocMagic(sizeof(DevParam));
newparm->parm_name = StrDup((char **)NULL, argv[argstart]); newparm->parm_name = StrDup((char **)NULL, argv[termstart]);
newparm->parm_next = devtmp.dev_params; newparm->parm_next = devtmp.dev_params;
devtmp.dev_params = newparm; devtmp.dev_params = newparm;
} }
@ -1010,7 +1024,28 @@ efBuildDevice(
break; break;
case 'w': case 'w':
if ((pptr - argv[termstart]) == 2)
devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale);
else
{
/* Check for w0, w1, w2, ... If w0, handle like "w".
* Otherwise, save it verbatim like an unknown parameter,
* because its value will not be calculated from terminal
* values like "a1, a2, ..." or "p1, p2, ...".
*/
pn = *(argv[termstart] + 1) - '0';
if (pn == 0)
devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale);
else
{
/* Copy the whole string into dev_params */
newparm = (DevParam *)mallocMagic(sizeof(DevParam));
newparm->parm_name = StrDup((char **)NULL, argv[termstart]);
newparm->parm_next = devtmp.dev_params;
devtmp.dev_params = newparm;
}
}
break; break;
case 'c': case 'c':
devtmp.dev_cap = (float)atof(pptr); devtmp.dev_cap = (float)atof(pptr);
@ -1019,7 +1054,7 @@ efBuildDevice(
devtmp.dev_res = (float)atof(pptr); devtmp.dev_res = (float)atof(pptr);
break; break;
} }
argstart++; termstart++;
} }
/* Check for optional substrate node */ /* Check for optional substrate node */
@ -1027,6 +1062,7 @@ efBuildDevice(
{ {
case DEV_RES: case DEV_RES:
case DEV_CAP: case DEV_CAP:
case DEV_BJT:
case DEV_CAPREV: case DEV_CAPREV:
case DEV_RSUBCKT: case DEV_RSUBCKT:
case DEV_CSUBCKT: case DEV_CSUBCKT:
@ -1037,22 +1073,22 @@ efBuildDevice(
case DEV_DIODE: case DEV_DIODE:
case DEV_NDIODE: case DEV_NDIODE:
case DEV_PDIODE: case DEV_PDIODE:
n = argc - argstart; n = argc - termstart;
if ((n % 3) == 1) if ((n % 3) == 1)
{ {
if (strncmp(argv[argstart], "None", 4) != 0) if (strncmp(argv[termstart], "None", 4) != 0)
devtmp.dev_subsnode = efBuildDevNode(def, argv[argstart], TRUE); devtmp.dev_subsnode = efBuildDevNode(def, argv[termstart], TRUE);
argstart++; termstart++;
} }
break; break;
} }
/* Between argstart and argc, we should only have terminal triples */ /* Between termstart and argc, we should only have terminal triples */
if (((argc - argstart) % 3) != 0) if (((argc - termstart) % 3) != 0)
return 1; return 1;
nterminals = (argc - argstart) / 3; nterminals = (argc - termstart) / 3;
dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, TT_MAXTYPES, type); dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, TT_MAXTYPES, type);
@ -1215,17 +1251,17 @@ efBuildDevice(
case DEV_ASYMMETRIC: case DEV_ASYMMETRIC:
case DEV_BJT: case DEV_BJT:
/* "None" in the place of the substrate name means substrate is ignored */ /* "None" in the place of the substrate name means substrate is ignored */
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0)) if ((termstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE); newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break; break;
case DEV_RES: case DEV_RES:
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0)) if ((termstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE); newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break; break;
case DEV_CAP: case DEV_CAP:
case DEV_CAPREV: case DEV_CAPREV:
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0)) if ((termstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE); newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break; break;
@ -1235,7 +1271,7 @@ efBuildDevice(
#define TERM_PERIM 1 #define TERM_PERIM 1
#define TERM_ATTRS 2 #define TERM_ATTRS 2
for (av = &argv[argstart], n = 0; n < nterminals; n++, av += 3) for (av = &argv[termstart], n = 0; n < nterminals; n++, av += 3)
{ {
term = &newdev->dev_terms[n]; term = &newdev->dev_terms[n];
term->dterm_node = efBuildDevNode(def, av[TERM_NAME], FALSE); term->dterm_node = efBuildDevNode(def, av[TERM_NAME], FALSE);