Implemented simple drain and source length calculations as device

parameters l1 and l2.  Provides a way to pass the source or drain
length as a parameter for, for example, an extended FET drain
implemented as a resistor abutting the FET gate.  Could potentially
be used as a way to determine source/drain area and perimeter
without resorting to measurements of a shared node.
This commit is contained in:
Tim Edwards 2022-12-14 21:40:24 -05:00
parent edecd81046
commit 677cd8ab5e
3 changed files with 130 additions and 25 deletions

View File

@ -149,7 +149,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
float sdM; /* Device multiplier */
{
bool hierD;
DevParam *plist;
DevParam *plist, *dparam;
int parmval;
EFNode *dnode, *subnodeFlat = NULL;
@ -253,14 +253,47 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
break;
case 'l':
fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0)
fprintf(esSpiceF, "%g", l * scale);
else if (plist->parm_scale != 1.0)
fprintf(esSpiceF, "%g", l * scale * esScale
// Check for device length vs. terminal length
if (plist->parm_type[1] == '\0' || plist->parm_type[1] == '0')
{
fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0)
fprintf(esSpiceF, "%g", l * scale);
else if (plist->parm_scale != 1.0)
fprintf(esSpiceF, "%g", l * scale * esScale
* plist->parm_scale * 1E-6);
else
fprintf(esSpiceF, "%gu", l * scale * esScale);
}
else
fprintf(esSpiceF, "%gu", l * scale * esScale);
{
/* l1, l2, etc. used to indicate the length 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] == 'l') &&
(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", dval * scale * esScale
* plist->parm_scale * 1E-6);
else
fprintf(esSpiceF, "%gu", dval * scale * esScale);
dparam->parm_name[0] = '\0';
break;
}
}
}
}
break;
case 'w':
fprintf(esSpiceF, " %s=", plist->parm_name);
@ -313,8 +346,9 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
}
/* Add parameters that are to be copied verbatim */
for (plist = dev->dev_params; plist; plist = plist->parm_next)
fprintf(esSpiceF, " %s", plist->parm_name);
for (dparam = dev->dev_params; dparam; dparam = dparam->parm_next)
if (dparam->parm_name[0] != '\0')
fprintf(esSpiceF, " %s", dparam->parm_name);
}
/*

View File

@ -1981,7 +1981,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
float sdM; /* Device multiplier */
{
bool hierD;
DevParam *plist;
DevParam *plist, *dparam;
int parmval;
EFNode *dnode, *subnodeFlat = NULL;
@ -2060,7 +2060,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
break;
case 'p':
// Check for area of terminal node vs. device area
// Check for perimeter of terminal node vs. device perimeter
if (plist->parm_type[1] == '\0' || plist->parm_type[1] == '0')
{
fprintf(esSpiceF, " %s=", plist->parm_name);
@ -2123,15 +2123,48 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
break;
case 'l':
fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0)
fprintf(esSpiceF, "%g", l * scale);
else if (plist->parm_scale != 1.0)
fprintf(esSpiceF, "%g", l * scale * esScale
// Check for length of device vs. depth 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", l * scale);
else if (plist->parm_scale != 1.0)
fprintf(esSpiceF, "%g", l * scale * esScale
* plist->parm_scale * 1E-6);
else
fprintf(esSpiceF, "%gu", l * scale * esScale);
}
else
fprintf(esSpiceF, "%gu", l * scale * esScale);
{
/* l1, l2, etc. used to indicate the length 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] == 'l') &&
(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", dval * scale * esScale
* plist->parm_scale * 1E-6);
else
fprintf(esSpiceF, "%gu", dval * scale * esScale);
dparam->parm_name[0] = '\0';
break;
}
}
}
}
break;
case 'w':
fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0)

View File

@ -105,6 +105,9 @@ struct transRec
int tr_termlen[MAXSD]; /* Length of each diff terminal edge,
* used for computing L/W for the fet.
*/
int tr_termdepth[MAXSD]; /* Length of the terminal perpendicular
* to the device edge.
*/
Point tr_termvector[MAXSD]; /* Perimeter traversal vector, used to
* find and calculate correct parameters
* for annular (ring) devices and other
@ -1058,7 +1061,7 @@ ExtSortTerminals(tran, ll)
TermTilePos *p1, *p2;
NodeRegion *tmp_node;
TermTilePos tmp_pos;
int tmp_len;
int tmp_len, tmp_depth;
LabelList *lp;
do
@ -1086,14 +1089,17 @@ ExtSortTerminals(tran, ll)
tmp_node = tran->tr_termnode[nsd];
tmp_pos = tran->tr_termpos[nsd];
tmp_len = tran->tr_termlen[nsd];
tmp_depth = tran->tr_termdepth[nsd];
tran->tr_termnode[nsd] = tran->tr_termnode[nsd+1];
tran->tr_termpos[nsd] = tran->tr_termpos[nsd+1];
tran->tr_termlen[nsd] = tran->tr_termlen[nsd+1];
tran->tr_termdepth[nsd] = tran->tr_termdepth[nsd+1];
tran->tr_termnode[nsd+1] = tmp_node;
tran->tr_termpos[nsd+1] = tmp_pos;
tran->tr_termlen[nsd+1] = tmp_len;
tran->tr_termdepth[nsd+1] = tmp_depth;
/* Need to SWAP the indices in the labRegion too.
* These for loops within the bubblesort in here are kinda slow
* but S,D attributes are not that common so it should not matter
@ -1684,12 +1690,13 @@ extOutputParameters(def, transList, outFile)
*/
void
extOutputDevParams(reg, devptr, outFile, length, width)
extOutputDevParams(reg, devptr, outFile, length, width, depthvec)
TransRegion *reg;
ExtDevice *devptr;
FILE *outFile;
int length;
int width;
int *depthvec;
{
ParamList *chkParam;
@ -1711,8 +1718,18 @@ extOutputDevParams(reg, devptr, outFile, length, width)
extTransRec.tr_perim);
break;
case 'l':
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],
length);
else if (chkParam->pl_param[1] > '0' && chkParam->pl_param[1] <= '9')
{
int tidx = chkParam->pl_param[1] - '1';
/* output depth of terminal */
fprintf(outFile, " %c%c=%d", chkParam->pl_param[0],
chkParam->pl_param[1],
depthvec[tidx]);
}
break;
case 'w':
fprintf(outFile, " %c=%d", chkParam->pl_param[0],
@ -1936,6 +1953,7 @@ extOutputDevices(def, transList, outFile)
while (extTransRec.tr_nterm < nsd)
{
extTransRec.tr_termlen[extTransRec.tr_nterm] = 0;
extTransRec.tr_termdepth[extTransRec.tr_nterm] = 0;
extTransRec.tr_termnode[extTransRec.tr_nterm++] = node;
}
}
@ -2158,7 +2176,8 @@ extOutputDevices(def, transList, outFile)
fprintf(outFile, " %d %d", length, width);
}
extOutputDevParams(reg, devptr, outFile, length, width);
extOutputDevParams(reg, devptr, outFile, length, width,
extTransRec.tr_termdepth);
fprintf(outFile, " \"%s\"", (subsName == NULL) ?
"None" : subsName);
@ -2167,7 +2186,8 @@ extOutputDevices(def, transList, outFile)
case DEV_DIODE: /* Only handle the optional substrate node */
case DEV_NDIODE:
case DEV_PDIODE:
extOutputDevParams(reg, devptr, outFile, length, width);
extOutputDevParams(reg, devptr, outFile, length, width,
extTransRec.tr_termdepth);
if (subsName != NULL)
fprintf(outFile, " \"%s\"", subsName);
break;
@ -2294,7 +2314,8 @@ extOutputDevices(def, transList, outFile)
else /* regular resistor */
fprintf(outFile, " %g", dres / 1000.0); /* mOhms -> Ohms */
extOutputDevParams(reg, devptr, outFile, length, width);
extOutputDevParams(reg, devptr, outFile, length, width,
extTransRec.tr_termdepth);
if (devptr->exts_deviceClass == DEV_RSUBCKT)
{
@ -2384,7 +2405,8 @@ extOutputDevices(def, transList, outFile)
fprintf(outFile, " \"%s\"", subsName);
}
extOutputDevParams(reg, devptr, outFile, length, width);
extOutputDevParams(reg, devptr, outFile, length, width,
extTransRec.tr_termdepth);
if (devptr->exts_deviceClass == DEV_CSUBCKT)
{
@ -2853,7 +2875,7 @@ extTransPerimFunc(bp)
Tile *tile;
NodeRegion *diffNode = (NodeRegion *) extGetRegion(bp->b_outside);
ExtDevice *devptr, *deventry;
int i, len = BoundaryLength(bp);
int i, depth, len = BoundaryLength(bp);
int thisterm;
LabelList *ll;
Label *lab;
@ -2871,6 +2893,17 @@ extTransPerimFunc(bp)
else
toutside = TiGetTypeExact(bp->b_outside);
/* Experimental---find the depth of the area outside the boundary.
* This can be used in limited circumstances to extract the terminal
* length (here, called tr_depth).
*/
if (toutside == TT_SPACE)
depth = 0;
else if (bp->b_segment.r_xtop == bp->b_segment.r_xbot)
depth = RIGHT(bp->b_outside) - LEFT(bp->b_outside);
else
depth = TOP(bp->b_outside) - BOTTOM(bp->b_outside);
if (extTransRec.tr_devrec != NULL)
devptr = extTransRec.tr_devrec;
else
@ -2910,6 +2943,7 @@ extTransPerimFunc(bp)
extTransRec.tr_nterm++;
extTransRec.tr_termnode[thisterm] = diffNode;
extTransRec.tr_termlen[thisterm] = 0;
extTransRec.tr_termdepth[thisterm] = 0;
extTransRec.tr_termvector[thisterm].p_x = 0;
extTransRec.tr_termvector[thisterm].p_y = 0;
extTransRec.tr_termpos[thisterm].pnum = DBPlane(toutside);
@ -2952,6 +2986,10 @@ extTransPerimFunc(bp)
/* Add the length to this terminal's perimeter */
extTransRec.tr_termlen[thisterm] += len;
/* Update the terminal depth */
if (depth > extTransRec.tr_termdepth[thisterm])
extTransRec.tr_termdepth[thisterm] = depth;
/* Update the boundary traversal vector */
switch(bp->b_direction) {
case BD_LEFT: