Extended the device parameters to allow a terminal width that is

different from the device (i.e., gate) width, for devices that do
not define a MOS-like gate spanning the width of the device.  This
is restricted to the assumption that the terminal is rectangular
and therefore a simple width and length can be derived from the
area and perimeter.  Also, length is defined as the smaller
dimension and width as the larger dimension.  For additional
restrictions, see the updated documentation.  This was added to
allow correct width and length extraction of a bipolar emitter
window, but may be more generally useful.
This commit is contained in:
Tim Edwards 2024-12-06 16:42:43 -05:00
parent 9184ccd395
commit 0a67151292
4 changed files with 114 additions and 21 deletions

View File

@ -1 +1 @@
8.3.503
8.3.504

View File

@ -300,15 +300,48 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
break;
case 'w':
fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0)
fprintf(esSpiceF, "%g", w * scale);
else if (plist->parm_scale != 1.0)
fprintf(esSpiceF, "%g", (double)w * scale * esScale
// Check for device width vs. terminal width
if (plist->parm_type[1] == '\0' || plist->parm_type[1] == '0')
{
fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0)
fprintf(esSpiceF, "%g", w * scale);
else if (plist->parm_scale != 1.0)
fprintf(esSpiceF, "%g", (double)w * scale * esScale
* plist->parm_scale * 1E-6);
else
esSIvalue(esSpiceF, 1.0E-6 * (w + plist->parm_offset)
else
esSIvalue(esSpiceF, 1.0E-6 * (w + plist->parm_offset)
* scale * esScale);
}
else
{
/* w1, w2, etc. used to indicate the width of the terminal */
/* Find value in dev_params */
for (dparam = dev->dev_params; dparam; dparam = dparam->parm_next)
{
if ((strlen(dparam->parm_name) > 2) &&
(dparam->parm_name[0] == 'w') &&
(dparam->parm_name[1] == plist->parm_type[1]) &&
(dparam->parm_name[2] == '='))
{
int dval;
if (sscanf(&dparam->parm_name[3], "%d", &dval) == 1)
{
fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0)
fprintf(esSpiceF, "%g", dval * scale);
else if (plist->parm_scale != 1.0)
fprintf(esSpiceF, "%g", (double)dval * scale * esScale
* plist->parm_scale * 1E-6);
else
esSIvalue(esSpiceF, (dval + plist->parm_offset)
* scale * esScale * 1.0E-6);
dparam->parm_name[0] = '\0';
break;
}
}
}
}
break;
case 's':
fprintf(esSpiceF, " %s=", plist->parm_name);

View File

@ -2181,15 +2181,48 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
break;
case 'w':
fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0)
fprintf(esSpiceF, "%g", w * scale);
else if (plist->parm_scale != 1.0)
fprintf(esSpiceF, "%g", (double)w * scale * esScale
// Check for width of device vs. width of terminal
if (plist->parm_type[1] == '\0' || plist->parm_type[1] == '0')
{
fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0)
fprintf(esSpiceF, "%g", w * scale);
else if (plist->parm_scale != 1.0)
fprintf(esSpiceF, "%g", (double)w * scale * esScale
* plist->parm_scale * 1E-6);
else
esSIvalue(esSpiceF, 1.0E-6 * (w + plist->parm_offset)
else
esSIvalue(esSpiceF, 1.0E-6 * (w + plist->parm_offset)
* scale * esScale);
}
else
{
/* w1, w2, etc. used to indicate the width of the terminal */
/* Find the value in dev_params */
for (dparam = dev->dev_params; dparam; dparam = dparam->parm_next)
{
if ((strlen(dparam->parm_name) > 2) &&
(dparam->parm_name[0] == 'w') &&
(dparam->parm_name[1] == plist->parm_type[1]) &&
(dparam->parm_name[2] == '='))
{
int dval;
if (sscanf(&dparam->parm_name[3], "%d", &dval) == 1)
{
fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0)
fprintf(esSpiceF, "%g", dval * scale);
else if (plist->parm_scale != 1.0)
fprintf(esSpiceF, "%g", (double)dval * scale * esScale
* plist->parm_scale * 1E-6);
else
esSIvalue(esSpiceF, (dval + plist->parm_offset)
* scale * esScale * 1.0E-6);
dparam->parm_name[0] = '\0';
break;
}
}
}
}
break;
case 's':
fprintf(esSpiceF, " %s=", plist->parm_name);

View File

@ -1768,13 +1768,14 @@ extOutputParameters(def, transList, outFile)
*/
void
extOutputDevParams(reg, devptr, outFile, length, width, areavec)
extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
TransRegion *reg;
ExtDevice *devptr;
FILE *outFile;
int length;
int width;
int *areavec;
int *perimvec;
{
ParamList *chkParam;
@ -1815,8 +1816,34 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec)
}
break;
case 'w':
fprintf(outFile, " %c=%d", chkParam->pl_param[0],
if (chkParam->pl_param[1] == '\0' ||
chkParam->pl_param[1] == '0')
fprintf(outFile, " %c=%d", chkParam->pl_param[0],
width);
else if (chkParam->pl_param[1] > '0' && chkParam->pl_param[1] <= '9')
{
int tidx = chkParam->pl_param[1] - '1';
/* NOTE: For a MOSFET, the gate width is the terminal
* width, and only "w" should be used as a parameter.
* For other devices, "w" with an index indicates that
* the device width is *not* the gate width. Since only
* the device area is maintained, then in this case the
* terminal must be a single rectangle, from which the
* length and width are extracted as the length of the
* short and long sides, respectively. This changes the
* value "width"; therefore, "w" with a suffix should
* come before "l" with a suffix in the device line in
* the tech file, since the "l" value will be derived
* from the area and width.
*/
double newwidth = (double)(perimvec[tidx] * perimvec[tidx]);
newwidth -= (double)(16 * areavec[tidx]);
newwidth = sqrt(newwidth);
newwidth += perimvec[tidx];
width = (int)(0.25 * newwidth);
fprintf(outFile, " %c%c=%d", chkParam->pl_param[0],
chkParam->pl_param[1], width);
}
break;
case 'c':
fprintf(outFile, " %c=%g", chkParam->pl_param[0],
@ -2546,7 +2573,7 @@ extOutputDevices(def, transList, outFile)
}
extOutputDevParams(reg, devptr, outFile, length, width,
extTransRec.tr_termarea);
extTransRec.tr_termarea, extTransRec.tr_termperim);
fprintf(outFile, " \"%s\"", (subsName == NULL) ?
"None" : subsName);
@ -2565,7 +2592,7 @@ extOutputDevices(def, transList, outFile)
reg->treg_ll.p_x + 1, reg->treg_ll.p_y + 1);
extOutputDevParams(reg, devptr, outFile, length, width,
extTransRec.tr_termarea);
extTransRec.tr_termarea, extTransRec.tr_termperim);
if (subsName != NULL)
fprintf(outFile, " \"%s\"", subsName);
break;
@ -2712,7 +2739,7 @@ extOutputDevices(def, transList, outFile)
fprintf(outFile, " %g", dres / 1000.0); /* mOhms -> Ohms */
extOutputDevParams(reg, devptr, outFile, length, width,
extTransRec.tr_termarea);
extTransRec.tr_termarea, extTransRec.tr_termperim);
if (devptr->exts_deviceClass == DEV_RSUBCKT)
{
@ -2811,7 +2838,7 @@ extOutputDevices(def, transList, outFile)
}
extOutputDevParams(reg, devptr, outFile, length, width,
extTransRec.tr_termarea);
extTransRec.tr_termarea, extTransRec.tr_termperim);
if (devptr->exts_deviceClass == DEV_CSUBCKT)
{