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:
parent
edecd81046
commit
677cd8ab5e
|
|
@ -149,7 +149,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
||||||
float sdM; /* Device multiplier */
|
float sdM; /* Device multiplier */
|
||||||
{
|
{
|
||||||
bool hierD;
|
bool hierD;
|
||||||
DevParam *plist;
|
DevParam *plist, *dparam;
|
||||||
int parmval;
|
int parmval;
|
||||||
EFNode *dnode, *subnodeFlat = NULL;
|
EFNode *dnode, *subnodeFlat = NULL;
|
||||||
|
|
||||||
|
|
@ -253,14 +253,47 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
// Check for device length vs. terminal length
|
||||||
if (esScale < 0)
|
if (plist->parm_type[1] == '\0' || plist->parm_type[1] == '0')
|
||||||
fprintf(esSpiceF, "%g", l * scale);
|
{
|
||||||
else if (plist->parm_scale != 1.0)
|
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||||
fprintf(esSpiceF, "%g", l * scale * esScale
|
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);
|
* plist->parm_scale * 1E-6);
|
||||||
|
else
|
||||||
|
fprintf(esSpiceF, "%gu", l * scale * esScale);
|
||||||
|
}
|
||||||
else
|
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;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
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 */
|
/* Add parameters that are to be copied verbatim */
|
||||||
for (plist = dev->dev_params; plist; plist = plist->parm_next)
|
for (dparam = dev->dev_params; dparam; dparam = dparam->parm_next)
|
||||||
fprintf(esSpiceF, " %s", plist->parm_name);
|
if (dparam->parm_name[0] != '\0')
|
||||||
|
fprintf(esSpiceF, " %s", dparam->parm_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -1981,7 +1981,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
||||||
float sdM; /* Device multiplier */
|
float sdM; /* Device multiplier */
|
||||||
{
|
{
|
||||||
bool hierD;
|
bool hierD;
|
||||||
DevParam *plist;
|
DevParam *plist, *dparam;
|
||||||
int parmval;
|
int parmval;
|
||||||
EFNode *dnode, *subnodeFlat = NULL;
|
EFNode *dnode, *subnodeFlat = NULL;
|
||||||
|
|
||||||
|
|
@ -2060,7 +2060,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'p':
|
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')
|
if (plist->parm_type[1] == '\0' || plist->parm_type[1] == '0')
|
||||||
{
|
{
|
||||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||||
|
|
@ -2123,15 +2123,48 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
// Check for length of device vs. depth of terminal
|
||||||
if (esScale < 0)
|
if (plist->parm_type[1] == '\0' || plist->parm_type[1] == '0')
|
||||||
fprintf(esSpiceF, "%g", l * scale);
|
{
|
||||||
else if (plist->parm_scale != 1.0)
|
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||||
fprintf(esSpiceF, "%g", l * scale * esScale
|
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);
|
* plist->parm_scale * 1E-6);
|
||||||
|
else
|
||||||
|
fprintf(esSpiceF, "%gu", l * scale * esScale);
|
||||||
|
}
|
||||||
else
|
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;
|
break;
|
||||||
|
|
||||||
case 'w':
|
case 'w':
|
||||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||||
if (esScale < 0)
|
if (esScale < 0)
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,9 @@ struct transRec
|
||||||
int tr_termlen[MAXSD]; /* Length of each diff terminal edge,
|
int tr_termlen[MAXSD]; /* Length of each diff terminal edge,
|
||||||
* used for computing L/W for the fet.
|
* 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
|
Point tr_termvector[MAXSD]; /* Perimeter traversal vector, used to
|
||||||
* find and calculate correct parameters
|
* find and calculate correct parameters
|
||||||
* for annular (ring) devices and other
|
* for annular (ring) devices and other
|
||||||
|
|
@ -1058,7 +1061,7 @@ ExtSortTerminals(tran, ll)
|
||||||
TermTilePos *p1, *p2;
|
TermTilePos *p1, *p2;
|
||||||
NodeRegion *tmp_node;
|
NodeRegion *tmp_node;
|
||||||
TermTilePos tmp_pos;
|
TermTilePos tmp_pos;
|
||||||
int tmp_len;
|
int tmp_len, tmp_depth;
|
||||||
LabelList *lp;
|
LabelList *lp;
|
||||||
|
|
||||||
do
|
do
|
||||||
|
|
@ -1086,14 +1089,17 @@ ExtSortTerminals(tran, ll)
|
||||||
tmp_node = tran->tr_termnode[nsd];
|
tmp_node = tran->tr_termnode[nsd];
|
||||||
tmp_pos = tran->tr_termpos[nsd];
|
tmp_pos = tran->tr_termpos[nsd];
|
||||||
tmp_len = tran->tr_termlen[nsd];
|
tmp_len = tran->tr_termlen[nsd];
|
||||||
|
tmp_depth = tran->tr_termdepth[nsd];
|
||||||
|
|
||||||
tran->tr_termnode[nsd] = tran->tr_termnode[nsd+1];
|
tran->tr_termnode[nsd] = tran->tr_termnode[nsd+1];
|
||||||
tran->tr_termpos[nsd] = tran->tr_termpos[nsd+1];
|
tran->tr_termpos[nsd] = tran->tr_termpos[nsd+1];
|
||||||
tran->tr_termlen[nsd] = tran->tr_termlen[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_termnode[nsd+1] = tmp_node;
|
||||||
tran->tr_termpos[nsd+1] = tmp_pos;
|
tran->tr_termpos[nsd+1] = tmp_pos;
|
||||||
tran->tr_termlen[nsd+1] = tmp_len;
|
tran->tr_termlen[nsd+1] = tmp_len;
|
||||||
|
tran->tr_termdepth[nsd+1] = tmp_depth;
|
||||||
/* Need to SWAP the indices in the labRegion too.
|
/* Need to SWAP the indices in the labRegion too.
|
||||||
* These for loops within the bubblesort in here are kinda slow
|
* These for loops within the bubblesort in here are kinda slow
|
||||||
* but S,D attributes are not that common so it should not matter
|
* but S,D attributes are not that common so it should not matter
|
||||||
|
|
@ -1684,12 +1690,13 @@ extOutputParameters(def, transList, outFile)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
extOutputDevParams(reg, devptr, outFile, length, width)
|
extOutputDevParams(reg, devptr, outFile, length, width, depthvec)
|
||||||
TransRegion *reg;
|
TransRegion *reg;
|
||||||
ExtDevice *devptr;
|
ExtDevice *devptr;
|
||||||
FILE *outFile;
|
FILE *outFile;
|
||||||
int length;
|
int length;
|
||||||
int width;
|
int width;
|
||||||
|
int *depthvec;
|
||||||
{
|
{
|
||||||
ParamList *chkParam;
|
ParamList *chkParam;
|
||||||
|
|
||||||
|
|
@ -1711,8 +1718,18 @@ extOutputDevParams(reg, devptr, outFile, length, width)
|
||||||
extTransRec.tr_perim);
|
extTransRec.tr_perim);
|
||||||
break;
|
break;
|
||||||
case 'l':
|
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);
|
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;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
fprintf(outFile, " %c=%d", chkParam->pl_param[0],
|
fprintf(outFile, " %c=%d", chkParam->pl_param[0],
|
||||||
|
|
@ -1936,6 +1953,7 @@ extOutputDevices(def, transList, outFile)
|
||||||
while (extTransRec.tr_nterm < nsd)
|
while (extTransRec.tr_nterm < nsd)
|
||||||
{
|
{
|
||||||
extTransRec.tr_termlen[extTransRec.tr_nterm] = 0;
|
extTransRec.tr_termlen[extTransRec.tr_nterm] = 0;
|
||||||
|
extTransRec.tr_termdepth[extTransRec.tr_nterm] = 0;
|
||||||
extTransRec.tr_termnode[extTransRec.tr_nterm++] = node;
|
extTransRec.tr_termnode[extTransRec.tr_nterm++] = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2158,7 +2176,8 @@ extOutputDevices(def, transList, outFile)
|
||||||
fprintf(outFile, " %d %d", length, width);
|
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) ?
|
fprintf(outFile, " \"%s\"", (subsName == NULL) ?
|
||||||
"None" : subsName);
|
"None" : subsName);
|
||||||
|
|
@ -2167,7 +2186,8 @@ extOutputDevices(def, transList, outFile)
|
||||||
case DEV_DIODE: /* Only handle the optional substrate node */
|
case DEV_DIODE: /* Only handle the optional substrate node */
|
||||||
case DEV_NDIODE:
|
case DEV_NDIODE:
|
||||||
case DEV_PDIODE:
|
case DEV_PDIODE:
|
||||||
extOutputDevParams(reg, devptr, outFile, length, width);
|
extOutputDevParams(reg, devptr, outFile, length, width,
|
||||||
|
extTransRec.tr_termdepth);
|
||||||
if (subsName != NULL)
|
if (subsName != NULL)
|
||||||
fprintf(outFile, " \"%s\"", subsName);
|
fprintf(outFile, " \"%s\"", subsName);
|
||||||
break;
|
break;
|
||||||
|
|
@ -2294,7 +2314,8 @@ extOutputDevices(def, transList, outFile)
|
||||||
else /* regular resistor */
|
else /* regular resistor */
|
||||||
fprintf(outFile, " %g", dres / 1000.0); /* mOhms -> Ohms */
|
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)
|
if (devptr->exts_deviceClass == DEV_RSUBCKT)
|
||||||
{
|
{
|
||||||
|
|
@ -2384,7 +2405,8 @@ extOutputDevices(def, transList, outFile)
|
||||||
fprintf(outFile, " \"%s\"", subsName);
|
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)
|
if (devptr->exts_deviceClass == DEV_CSUBCKT)
|
||||||
{
|
{
|
||||||
|
|
@ -2853,7 +2875,7 @@ extTransPerimFunc(bp)
|
||||||
Tile *tile;
|
Tile *tile;
|
||||||
NodeRegion *diffNode = (NodeRegion *) extGetRegion(bp->b_outside);
|
NodeRegion *diffNode = (NodeRegion *) extGetRegion(bp->b_outside);
|
||||||
ExtDevice *devptr, *deventry;
|
ExtDevice *devptr, *deventry;
|
||||||
int i, len = BoundaryLength(bp);
|
int i, depth, len = BoundaryLength(bp);
|
||||||
int thisterm;
|
int thisterm;
|
||||||
LabelList *ll;
|
LabelList *ll;
|
||||||
Label *lab;
|
Label *lab;
|
||||||
|
|
@ -2871,6 +2893,17 @@ extTransPerimFunc(bp)
|
||||||
else
|
else
|
||||||
toutside = TiGetTypeExact(bp->b_outside);
|
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)
|
if (extTransRec.tr_devrec != NULL)
|
||||||
devptr = extTransRec.tr_devrec;
|
devptr = extTransRec.tr_devrec;
|
||||||
else
|
else
|
||||||
|
|
@ -2910,6 +2943,7 @@ extTransPerimFunc(bp)
|
||||||
extTransRec.tr_nterm++;
|
extTransRec.tr_nterm++;
|
||||||
extTransRec.tr_termnode[thisterm] = diffNode;
|
extTransRec.tr_termnode[thisterm] = diffNode;
|
||||||
extTransRec.tr_termlen[thisterm] = 0;
|
extTransRec.tr_termlen[thisterm] = 0;
|
||||||
|
extTransRec.tr_termdepth[thisterm] = 0;
|
||||||
extTransRec.tr_termvector[thisterm].p_x = 0;
|
extTransRec.tr_termvector[thisterm].p_x = 0;
|
||||||
extTransRec.tr_termvector[thisterm].p_y = 0;
|
extTransRec.tr_termvector[thisterm].p_y = 0;
|
||||||
extTransRec.tr_termpos[thisterm].pnum = DBPlane(toutside);
|
extTransRec.tr_termpos[thisterm].pnum = DBPlane(toutside);
|
||||||
|
|
@ -2952,6 +2986,10 @@ extTransPerimFunc(bp)
|
||||||
/* Add the length to this terminal's perimeter */
|
/* Add the length to this terminal's perimeter */
|
||||||
extTransRec.tr_termlen[thisterm] += len;
|
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 */
|
/* Update the boundary traversal vector */
|
||||||
switch(bp->b_direction) {
|
switch(bp->b_direction) {
|
||||||
case BD_LEFT:
|
case BD_LEFT:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue