Important update: Reworked the extraction method to properly
isolate the terminal areas of a device (e.g., source and drain) and calculate their area and perimeter individually for the device (in addition to the traditional method of calculating area and perimeter of each resistance class for the entire node). Also: Reworked the SPICE syntax output to generate SI values in the range 1-1000 with the appropriate suffix (e.g., "20u") instead of defaulting to "u" for lengths and "p" for areas. This prevents it from producing weird units like "150000u" when a process definition already includes a scalefactor. Reworked the "extresist" code to use the device terminal area and perimeter. This fixes an error in which "extresist" would lose these values and "ext2spice" with option "extresist on" would generate a new netlist output with zero terminal areas and perimeters.
This commit is contained in:
parent
87702ac98a
commit
c7f11d2169
|
|
@ -129,6 +129,85 @@ DBInvTransformDiagonal(oldtype, trans)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBSrConnectOnePlane --
|
||||
*
|
||||
* Search from a starting tile to find all paint that is electrically
|
||||
* connected to that tile in the same plane.
|
||||
*
|
||||
* Results:
|
||||
* 0 is returned if the search finished normally. 1 is returned
|
||||
* if the search was aborted.
|
||||
*
|
||||
* Side effects:
|
||||
* For every paint tile that is electrically connected to the initial
|
||||
* tile, func is called. Func should have the following form:
|
||||
*
|
||||
* int
|
||||
* func(tile, clientData)
|
||||
* Tile *tile;
|
||||
* ClientData clientData;
|
||||
* {
|
||||
* }
|
||||
*
|
||||
* The clientData passed to func is the same one that was passed
|
||||
* to us. Func returns 0 under normal conditions; if it returns
|
||||
* 1 then the search is aborted.
|
||||
*
|
||||
* *** WARNING ***
|
||||
*
|
||||
* Func should not modify any paint during the search, since this
|
||||
* will mess up pointers kept by these procedures and likely cause
|
||||
* a core-dump.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
DBSrConnectOnePlane(startTile, connect, func, clientData)
|
||||
Tile *startTile; /* Starting tile for search */
|
||||
TileTypeBitMask *connect; /* Pointer to a table indicating what tile
|
||||
* types connect to what other tile types.
|
||||
* Each entry gives a mask of types that
|
||||
* connect to tiles of a given type.
|
||||
*/
|
||||
int (*func)(); /* Function to apply at each connected tile. */
|
||||
ClientData clientData; /* Client data for above function. */
|
||||
|
||||
{
|
||||
struct conSrArg csa;
|
||||
int result;
|
||||
extern int dbSrConnectFunc(); /* Forward declaration. */
|
||||
|
||||
result = 0;
|
||||
csa.csa_def = (CellDef *)NULL;
|
||||
csa.csa_bounds = TiPlaneRect;
|
||||
|
||||
/* Pass 1. During this pass the client function gets called. */
|
||||
|
||||
csa.csa_clientFunc = func;
|
||||
csa.csa_clientData = clientData;
|
||||
csa.csa_clientDefault = startTile->ti_client;
|
||||
csa.csa_clear = FALSE;
|
||||
csa.csa_connect = connect;
|
||||
csa.csa_pNum = -1;
|
||||
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
|
||||
|
||||
/* Pass 2. Don't call any client function, just clear the marks.
|
||||
* Don't allow any interruptions.
|
||||
*/
|
||||
|
||||
SigDisableInterrupts();
|
||||
csa.csa_clientFunc = NULL;
|
||||
csa.csa_clear = TRUE;
|
||||
(void) dbSrConnectFunc(startTile, &csa);
|
||||
SigEnableInterrupts();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -227,6 +306,7 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
|
|||
|
||||
csa.csa_clientFunc = func;
|
||||
csa.csa_clientData = clientData;
|
||||
csa.csa_clientDefault = CLIENTDEFAULT;
|
||||
csa.csa_clear = FALSE;
|
||||
csa.csa_connect = connect;
|
||||
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
|
||||
|
|
@ -316,6 +396,7 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
|
|||
|
||||
csa.csa_clientFunc = func;
|
||||
csa.csa_clientData = clientData;
|
||||
csa.csa_clientDefault = CLIENTDEFAULT;
|
||||
csa.csa_clear = FALSE;
|
||||
csa.csa_connect = connect;
|
||||
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
|
||||
|
|
@ -424,15 +505,15 @@ dbSrConnectFunc(tile, csa)
|
|||
callClient = TRUE;
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (tile->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||||
tile->ti_client = (ClientData) CLIENTDEFAULT;
|
||||
if (tile->ti_client == csa->csa_clientDefault) continue;
|
||||
tile->ti_client = csa->csa_clientDefault;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tile->ti_client == (ClientData) 1) continue;
|
||||
|
||||
/* Allow a process to mark tiles for skipping the client function */
|
||||
if (tile->ti_client != (ClientData) CLIENTDEFAULT)
|
||||
if (tile->ti_client != csa->csa_clientDefault)
|
||||
callClient = FALSE;
|
||||
tile->ti_client = (ClientData) 1;
|
||||
}
|
||||
|
|
@ -480,7 +561,7 @@ dbSrConnectFunc(tile, csa)
|
|||
{
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||||
if (t2->ti_client == csa->csa_clientDefault) continue;
|
||||
}
|
||||
else if (t2->ti_client == (ClientData) 1) continue;
|
||||
if (IsSplit(t2))
|
||||
|
|
@ -508,7 +589,7 @@ bottomside:
|
|||
{
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||||
if (t2->ti_client == csa->csa_clientDefault) continue;
|
||||
}
|
||||
else if (t2->ti_client == (ClientData) 1) continue;
|
||||
if (IsSplit(t2))
|
||||
|
|
@ -542,7 +623,7 @@ rightside:
|
|||
{
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextRight;
|
||||
if (t2->ti_client == csa->csa_clientDefault) goto nextRight;
|
||||
}
|
||||
else if (t2->ti_client == (ClientData) 1) goto nextRight;
|
||||
if (IsSplit(t2))
|
||||
|
|
@ -570,7 +651,7 @@ topside:
|
|||
{
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextTop;
|
||||
if (t2->ti_client == csa->csa_clientDefault) goto nextTop;
|
||||
}
|
||||
else if (t2->ti_client == (ClientData) 1) goto nextTop;
|
||||
if (IsSplit(t2))
|
||||
|
|
@ -589,6 +670,7 @@ topside:
|
|||
}
|
||||
|
||||
donesides:
|
||||
if (pNum < 0) continue; /* Used for single-plane search */
|
||||
|
||||
/* Lastly, check to see if this tile connects to anything on
|
||||
* other planes. If so, search those planes.
|
||||
|
|
|
|||
|
|
@ -691,6 +691,7 @@ struct conSrArg
|
|||
*/
|
||||
int (*csa_clientFunc)(); /* Client function to call. */
|
||||
ClientData csa_clientData; /* Argument for clientFunc. */
|
||||
ClientData csa_clientDefault; /* Value to reset tiles' ClientData to. */
|
||||
bool csa_clear; /* FALSE means pass 1, TRUE
|
||||
* means pass 2.
|
||||
*/
|
||||
|
|
@ -1001,6 +1002,7 @@ extern void DBResetTilePlane();
|
|||
extern void DBNewYank();
|
||||
extern int DBSrPaintClient();
|
||||
extern int DBSrConnect();
|
||||
extern int DBSrConnectOnePlane();
|
||||
extern char *dbFgets();
|
||||
extern void DBAdjustLabelsNew();
|
||||
extern bool DBScaleValue();
|
||||
|
|
|
|||
|
|
@ -1225,6 +1225,12 @@ simdevVisit(dev, hc, scale, trans)
|
|||
}
|
||||
else if (is_subckt)
|
||||
{
|
||||
/* Output source and drain attributes */
|
||||
if (source->dterm_attrs)
|
||||
fprintf(esSimF, " s=%s", source->dterm_attrs);
|
||||
if (drain->dterm_attrs)
|
||||
fprintf(esSimF, " d=%s", drain->dterm_attrs);
|
||||
|
||||
/* Output length, width, and position as attributes */
|
||||
fprintf(esSimF, " l=%g w=%g x=%g y=%g",
|
||||
l * scale, w * scale, r.r_xbot * scale, r.r_ybot * scale);
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
* esScale * esScale * plist->parm_scale
|
||||
* 1E-12);
|
||||
else
|
||||
fprintf(esSpiceF, "%gp", parmval * scale * scale
|
||||
esSIvalue(esSpiceF, 1.0E-12 * parmval * scale * scale
|
||||
* esScale * esScale);
|
||||
}
|
||||
else
|
||||
|
|
@ -194,15 +194,15 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
'p' && plist->parm_next->parm_type[1] ==
|
||||
plist->parm_type[1])
|
||||
{
|
||||
spcnAP(dnode, resclass, scale, plist->parm_name,
|
||||
plist->parm_next->parm_name, sdM,
|
||||
esSpiceF, w);
|
||||
spcnAP(&dev->dev_terms[pn], dnode, resclass, scale,
|
||||
plist->parm_name, plist->parm_next->parm_name,
|
||||
sdM, esSpiceF, w);
|
||||
plist = plist->parm_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
spcnAP(dnode, resclass, scale, plist->parm_name, NULL, sdM,
|
||||
esSpiceF, w);
|
||||
spcnAP(&dev->dev_terms[pn], dnode, resclass, scale,
|
||||
plist->parm_name, NULL, sdM, esSpiceF, w);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +220,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", parmval * scale
|
||||
* esScale * plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", parmval * scale * esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-6 * parmval * scale * esScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -240,14 +240,15 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
'a' && plist->parm_next->parm_type[1] ==
|
||||
plist->parm_type[1])
|
||||
{
|
||||
spcnAP(dnode, resclass, scale, plist->parm_next->parm_name,
|
||||
spcnAP(&dev->dev_terms[pn], dnode, resclass, scale,
|
||||
plist->parm_next->parm_name,
|
||||
plist->parm_name, sdM, esSpiceF, w);
|
||||
plist = plist->parm_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
spcnAP(dnode, resclass, scale, NULL, plist->parm_name, sdM,
|
||||
esSpiceF, w);
|
||||
spcnAP(&dev->dev_terms[pn], dnode, resclass, scale, NULL,
|
||||
plist->parm_name, sdM, esSpiceF, w);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,7 +264,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", l * scale * esScale
|
||||
* plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", l * scale * esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -286,7 +287,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", dval * scale * esScale
|
||||
* plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", dval * scale * esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-6 * dval * scale * esScale);
|
||||
dparam->parm_name[0] = '\0';
|
||||
break;
|
||||
}
|
||||
|
|
@ -303,7 +304,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", w * scale * esScale
|
||||
* plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", w * scale * esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale);
|
||||
break;
|
||||
case 's':
|
||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||
|
|
@ -319,8 +320,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", dev->dev_rect.r_xbot * scale
|
||||
* esScale * plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", dev->dev_rect.r_xbot * scale
|
||||
* esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-6 * dev->dev_rect.r_xbot * scale * esScale);
|
||||
break;
|
||||
case 'y':
|
||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||
|
|
@ -330,8 +330,7 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", dev->dev_rect.r_ybot * scale
|
||||
* esScale * plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", dev->dev_rect.r_ybot * scale
|
||||
* esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-6 * dev->dev_rect.r_ybot * scale * esScale);
|
||||
break;
|
||||
case 'r':
|
||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||
|
|
@ -426,9 +425,10 @@ esOutputHierResistor(hc, dev, scale, term1, term2, has_model, l, w, dscale)
|
|||
}
|
||||
else
|
||||
{
|
||||
fprintf(esSpiceF, " w=%gu l=%gu",
|
||||
(float)w * scale * esScale,
|
||||
(float)((l * scale * esScale) / dscale));
|
||||
fprintf(esSpiceF, " w=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * (float)w * scale * esScale);
|
||||
fprintf(esSpiceF, " w=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * (float)((l * scale * esScale) / dscale));
|
||||
}
|
||||
spcHierWriteParams(hc, dev, scale, l, w, sdM);
|
||||
if (sdM != 1.0)
|
||||
|
|
@ -934,9 +934,10 @@ spcdevHierVisit(hc, dev, scale)
|
|||
}
|
||||
else
|
||||
{
|
||||
fprintf(esSpiceF, " w=%gu l=%gu",
|
||||
w * scale * esScale,
|
||||
l * scale * esScale);
|
||||
fprintf(esSpiceF, " w=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale);
|
||||
fprintf(esSpiceF, " l=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
|
||||
}
|
||||
spcHierWriteParams(hc, dev, scale, l, w, sdM);
|
||||
if (sdM != 1.0)
|
||||
|
|
@ -981,9 +982,10 @@ spcdevHierVisit(hc, dev, scale)
|
|||
}
|
||||
else
|
||||
{
|
||||
fprintf(esSpiceF, " w=%gu l=%gu",
|
||||
w * scale * esScale,
|
||||
l * scale * esScale);
|
||||
fprintf(esSpiceF, " w=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale);
|
||||
fprintf(esSpiceF, " l=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
|
||||
}
|
||||
spcHierWriteParams(hc, dev, scale, l, w, sdM);
|
||||
if (sdM != 1.0)
|
||||
|
|
@ -1024,9 +1026,10 @@ spcdevHierVisit(hc, dev, scale)
|
|||
}
|
||||
else
|
||||
{
|
||||
fprintf(esSpiceF, " w=%gu l=%gu",
|
||||
w * scale * esScale,
|
||||
l * scale * esScale);
|
||||
fprintf(esSpiceF, " w=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale);
|
||||
fprintf(esSpiceF, " l=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
|
||||
}
|
||||
spcHierWriteParams(hc, dev, scale, l, w, sdM);
|
||||
if (sdM != 1.0)
|
||||
|
|
@ -1042,10 +1045,10 @@ spcdevHierVisit(hc, dev, scale)
|
|||
|
||||
fprintf(esSpiceF, "\n+ ");
|
||||
dnode = GetHierNode(hc, drain->dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassDrain, scale,
|
||||
spcnAP(drain, dnode, esFetInfo[dev->dev_type].resClassDrain, scale,
|
||||
"ad", "pd", sdM, esSpiceF, w);
|
||||
snode= GetHierNode(hc, source->dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(snode, esFetInfo[dev->dev_type].resClassSource, scale,
|
||||
spcnAP(source, snode, esFetInfo[dev->dev_type].resClassSource, scale,
|
||||
"as", "ps", sdM, esSpiceF, w);
|
||||
if (subAP)
|
||||
{
|
||||
|
|
@ -1057,8 +1060,8 @@ spcdevHierVisit(hc, dev, scale)
|
|||
fprintf(esSpiceF, "asub=0 psub=0");
|
||||
}
|
||||
else if (subnodeFlat)
|
||||
spcnAP(subnodeFlat, esFetInfo[dev->dev_type].resClassSub, scale,
|
||||
"asub", "psub", sdM, esSpiceF, -1);
|
||||
spcnAP(NULL, subnodeFlat, esFetInfo[dev->dev_type].resClassSub,
|
||||
scale, "asub", "psub", sdM, esSpiceF, -1);
|
||||
else
|
||||
fprintf(esSpiceF, "asub=0 psub=0");
|
||||
}
|
||||
|
|
@ -1073,13 +1076,21 @@ spcdevHierVisit(hc, dev, scale)
|
|||
case DEV_MSUBCKT:
|
||||
if (!esNoAttrs)
|
||||
{
|
||||
if (gate->dterm_attrs || source->dterm_attrs || drain->dterm_attrs)
|
||||
bool haveSattr = FALSE;
|
||||
bool haveDattr = FALSE;
|
||||
|
||||
if (source->dterm_attrs && (*source->dterm_attrs))
|
||||
haveSattr = TRUE;
|
||||
if (drain->dterm_attrs && (*drain->dterm_attrs))
|
||||
haveDattr = TRUE;
|
||||
|
||||
if (gate->dterm_attrs || haveSattr || haveDattr)
|
||||
fprintf(esSpiceF,"\n**devattr");
|
||||
if (gate->dterm_attrs)
|
||||
fprintf(esSpiceF, " g=%s", gate->dterm_attrs);
|
||||
if (source->dterm_attrs)
|
||||
if (haveSattr)
|
||||
fprintf(esSpiceF, " s=%s", source->dterm_attrs);
|
||||
if (drain->dterm_attrs)
|
||||
if (haveDattr)
|
||||
fprintf(esSpiceF, " d=%s", drain->dterm_attrs);
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <stdlib.h> /* for atof() */
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h> /* for fabs() */
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
|
|
@ -1002,7 +1003,11 @@ runexttospice:
|
|||
fprintf(esSpiceF, "* %s file created from %s.ext - technology: %s\n\n",
|
||||
spiceFormats[esFormat], inName, EFTech);
|
||||
if (esScale < 0)
|
||||
fprintf(esSpiceF, ".option scale=%gu\n\n", EFScale / 100.0);
|
||||
{
|
||||
fprintf(esSpiceF, ".option scale=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * EFScale / 100.0);
|
||||
fprintf(esSpiceF, "\n\n");
|
||||
}
|
||||
else
|
||||
esScale = EFScale / 100.0;
|
||||
|
||||
|
|
@ -1237,7 +1242,11 @@ main(argc, argv)
|
|||
fprintf(esSpiceF, "* %s file created from %s.ext - technology: %s\n\n",
|
||||
spiceFormats[esFormat], inName, EFTech);
|
||||
if (esScale < 0)
|
||||
fprintf(esSpiceF,".option scale=%gu\n\n", EFScale / 100.0);
|
||||
{
|
||||
fprintf(esSpiceF,".option scale=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * EFScale / 100.0);
|
||||
fprintf(esSpiceF, "\n\n");
|
||||
}
|
||||
else
|
||||
esScale = EFScale / 100.0;
|
||||
|
||||
|
|
@ -2005,7 +2014,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
* esScale * esScale * plist->parm_scale
|
||||
* 1E-12);
|
||||
else
|
||||
fprintf(esSpiceF, "%gp", parmval * scale * scale
|
||||
esSIvalue(esSpiceF, 1.0E-12 * parmval * scale * scale
|
||||
* esScale * esScale);
|
||||
}
|
||||
else
|
||||
|
|
@ -2036,8 +2045,8 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
{
|
||||
dnode = SpiceGetNode(hierName,
|
||||
dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, resclass, scale, plist->parm_name,
|
||||
plist->parm_next->parm_name,
|
||||
spcnAP(&dev->dev_terms[pn], dnode, resclass, scale,
|
||||
plist->parm_name, plist->parm_next->parm_name,
|
||||
sdM, esSpiceF, w);
|
||||
}
|
||||
plist = plist->parm_next;
|
||||
|
|
@ -2052,8 +2061,8 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
{
|
||||
dnode = SpiceGetNode(hierName,
|
||||
dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, resclass, scale, plist->parm_name, NULL,
|
||||
sdM, esSpiceF, w);
|
||||
spcnAP(&dev->dev_terms[pn], dnode, resclass, scale,
|
||||
plist->parm_name, NULL, sdM, esSpiceF, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2071,7 +2080,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", parmval * scale
|
||||
* esScale * plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", parmval * scale * esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-12 * parmval * scale * esScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2100,7 +2109,8 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
{
|
||||
dnode = SpiceGetNode(hierName,
|
||||
dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, resclass, scale, plist->parm_next->parm_name,
|
||||
spcnAP(&dev->dev_terms[pn], dnode, resclass, scale,
|
||||
plist->parm_next->parm_name,
|
||||
plist->parm_name, sdM, esSpiceF, w);
|
||||
}
|
||||
plist = plist->parm_next;
|
||||
|
|
@ -2115,8 +2125,8 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
{
|
||||
dnode = SpiceGetNode(hierName,
|
||||
dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, resclass, scale, NULL, plist->parm_name,
|
||||
sdM, esSpiceF, w);
|
||||
spcnAP(&dev->dev_terms[pn], dnode, resclass, scale,
|
||||
NULL, plist->parm_name, sdM, esSpiceF, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2133,7 +2143,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", l * scale * esScale
|
||||
* plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", l * scale * esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2156,7 +2166,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", dval * scale * esScale
|
||||
* plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", dval * scale * esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-6 * dval * scale * esScale);
|
||||
dparam->parm_name[0] = '\0';
|
||||
break;
|
||||
}
|
||||
|
|
@ -2173,7 +2183,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", w * scale * esScale
|
||||
* plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", w * scale * esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale);
|
||||
break;
|
||||
case 's':
|
||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||
|
|
@ -2189,8 +2199,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", dev->dev_rect.r_xbot * scale
|
||||
* esScale * plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", dev->dev_rect.r_xbot * scale
|
||||
* esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-6 * dev->dev_rect.r_xbot * scale * esScale);
|
||||
break;
|
||||
case 'y':
|
||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||
|
|
@ -2200,8 +2209,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
fprintf(esSpiceF, "%g", dev->dev_rect.r_ybot * scale
|
||||
* esScale * plist->parm_scale * 1E-6);
|
||||
else
|
||||
fprintf(esSpiceF, "%gu", dev->dev_rect.r_ybot * scale
|
||||
* esScale);
|
||||
esSIvalue(esSpiceF, 1.0E-6 * dev->dev_rect.r_ybot * scale * esScale);
|
||||
break;
|
||||
case 'r':
|
||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||
|
|
@ -2283,9 +2291,12 @@ esOutputResistor(dev, hierName, scale, term1, term2, has_model, l, w, dscale)
|
|||
if (esScale < 0)
|
||||
fprintf(esSpiceF, " w=%g l=%g", w * scale, (l * scale) / dscale);
|
||||
else
|
||||
fprintf(esSpiceF, " w=%gu l=%gu",
|
||||
w * scale * esScale,
|
||||
((l * scale * esScale) / dscale));
|
||||
{
|
||||
fprintf(esSpiceF, " w=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale);
|
||||
fprintf(esSpiceF, " l=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * (l * scale * esScale) / dscale);
|
||||
}
|
||||
|
||||
spcWriteParams(dev, hierName, scale, l, w, sdM);
|
||||
if (sdM != 1.0)
|
||||
|
|
@ -2838,9 +2849,12 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
if (esScale < 0)
|
||||
fprintf(esSpiceF, " w=%g l=%g", w*scale, l*scale);
|
||||
else
|
||||
fprintf(esSpiceF, " w=%gu l=%gu",
|
||||
w * scale * esScale,
|
||||
l * scale * esScale);
|
||||
{
|
||||
fprintf(esSpiceF, " w=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale);
|
||||
fprintf(esSpiceF, " l=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
|
||||
}
|
||||
|
||||
spcWriteParams(dev, hierName, scale, l, w, sdM);
|
||||
if (sdM != 1.0)
|
||||
|
|
@ -2879,9 +2893,12 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
if (esScale < 0)
|
||||
fprintf(esSpiceF, " w=%g l=%g", w*scale, l*scale);
|
||||
else
|
||||
fprintf(esSpiceF, " w=%gu l=%gu",
|
||||
w * scale * esScale,
|
||||
l * scale * esScale);
|
||||
{
|
||||
fprintf(esSpiceF, " w=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale);
|
||||
fprintf(esSpiceF, " l=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
|
||||
}
|
||||
|
||||
spcWriteParams(dev, hierName, scale, l, w, sdM);
|
||||
if (sdM != 1.0)
|
||||
|
|
@ -2924,9 +2941,12 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
if (esScale < 0)
|
||||
fprintf(esSpiceF, " w=%g l=%g", w*scale, l*scale);
|
||||
else
|
||||
fprintf(esSpiceF, " w=%gu l=%gu",
|
||||
w * scale * esScale,
|
||||
l * scale * esScale);
|
||||
{
|
||||
fprintf(esSpiceF, " w=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * w * scale * esScale);
|
||||
fprintf(esSpiceF, " l=");
|
||||
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
|
||||
}
|
||||
|
||||
spcWriteParams(dev, hierName, scale, l, w, sdM);
|
||||
if (sdM != 1.0)
|
||||
|
|
@ -2947,7 +2967,7 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
else
|
||||
{
|
||||
dnode = SpiceGetNode(hierName, drain->dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(dnode, esFetInfo[dev->dev_type].resClassDrain, scale,
|
||||
spcnAP(drain, dnode, esFetInfo[dev->dev_type].resClassDrain, scale,
|
||||
"ad", "pd", sdM, esSpiceF, w);
|
||||
}
|
||||
if (hierS)
|
||||
|
|
@ -2955,7 +2975,7 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
scale, "as", "ps", sdM, esSpiceF);
|
||||
else {
|
||||
snode= SpiceGetNode(hierName, source->dterm_node->efnode_name->efnn_hier);
|
||||
spcnAP(snode, esFetInfo[dev->dev_type].resClassSource, scale,
|
||||
spcnAP(source, snode, esFetInfo[dev->dev_type].resClassSource, scale,
|
||||
"as", "ps", sdM, esSpiceF, w);
|
||||
}
|
||||
if (subAP)
|
||||
|
|
@ -2968,8 +2988,8 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
fprintf(esSpiceF, "asub=0 psub=0");
|
||||
}
|
||||
else if (subnodeFlat)
|
||||
spcnAP(subnodeFlat, esFetInfo[dev->dev_type].resClassSub, scale,
|
||||
"asub", "psub", sdM, esSpiceF, -1);
|
||||
spcnAP(NULL, subnodeFlat, esFetInfo[dev->dev_type].resClassSub,
|
||||
scale, "asub", "psub", sdM, esSpiceF, -1);
|
||||
else
|
||||
fprintf(esSpiceF, "asub=0 psub=0");
|
||||
}
|
||||
|
|
@ -2977,13 +2997,21 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
/* Now output attributes, if present */
|
||||
if (!esNoAttrs)
|
||||
{
|
||||
if (gate->dterm_attrs || source->dterm_attrs || drain->dterm_attrs)
|
||||
bool haveSattr = FALSE;
|
||||
bool haveDattr = FALSE;
|
||||
|
||||
if (source->dterm_attrs && (*source->dterm_attrs))
|
||||
haveSattr = TRUE;
|
||||
if (drain->dterm_attrs && (*drain->dterm_attrs))
|
||||
haveDattr = TRUE;
|
||||
|
||||
if (gate->dterm_attrs || haveSattr || haveDattr)
|
||||
fprintf(esSpiceF,"\n**devattr");
|
||||
if (gate->dterm_attrs)
|
||||
fprintf(esSpiceF, " g=%s", gate->dterm_attrs);
|
||||
if (source->dterm_attrs)
|
||||
if (haveSattr)
|
||||
fprintf(esSpiceF, " s=%s", source->dterm_attrs);
|
||||
if (drain->dterm_attrs)
|
||||
if (haveDattr)
|
||||
fprintf(esSpiceF, " d=%s", drain->dterm_attrs);
|
||||
}
|
||||
break;
|
||||
|
|
@ -3054,6 +3082,83 @@ FILE *outf;
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* esSIvalue --
|
||||
*
|
||||
* Print an output in appropriate SI units used by SPICE. e.g., 1.0e-6
|
||||
* will be printed as "1.0u"; 1.0e-12 will be printed as "1.0p", etc.
|
||||
*
|
||||
* Return value:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Generates output to stream "file".
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
esSIvalue(file, value)
|
||||
FILE *file;
|
||||
float value;
|
||||
{
|
||||
char suffix = '\0';
|
||||
float avalue;
|
||||
|
||||
avalue = fabsf(value);
|
||||
|
||||
if (avalue < 1.0E-18)
|
||||
{
|
||||
/* Do nothing---value is probably zero */
|
||||
}
|
||||
else if (avalue < 1.0E-15)
|
||||
{
|
||||
suffix = 'a';
|
||||
value *= 1.0E18;
|
||||
}
|
||||
else if (avalue < 1.0E-12)
|
||||
{
|
||||
suffix = 'f';
|
||||
value *= 1.0E15;
|
||||
}
|
||||
else if (avalue < 1.0E-9)
|
||||
{
|
||||
suffix = 'p';
|
||||
value *= 1.0E12;
|
||||
}
|
||||
else if (avalue < 1.0E-6)
|
||||
{
|
||||
suffix = 'n';
|
||||
value *= 1.0E9;
|
||||
}
|
||||
else if (avalue < 1.0E-3)
|
||||
{
|
||||
suffix = 'u';
|
||||
value *= 1.0E6;
|
||||
}
|
||||
else if (avalue <= 1.0E-3)
|
||||
{
|
||||
suffix = 'm';
|
||||
value *= 1.0E3;
|
||||
}
|
||||
else if (avalue >= 1.0E9)
|
||||
{
|
||||
suffix = 'G';
|
||||
value /= 1.0E9;
|
||||
}
|
||||
else if (avalue >= 1.0E3)
|
||||
{
|
||||
suffix = 'k';
|
||||
value /= 1.0E3;
|
||||
}
|
||||
|
||||
if (suffix == '\0')
|
||||
fprintf(file, "%g", value);
|
||||
else
|
||||
fprintf(file, "%g%c", value, suffix);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
@ -3074,7 +3179,8 @@ FILE *outf;
|
|||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
int spcnAP(node, resClass, scale, asterm, psterm, m, outf, w)
|
||||
int spcnAP(dterm, node, resClass, scale, asterm, psterm, m, outf, w)
|
||||
DevTerm *dterm;
|
||||
EFNode *node;
|
||||
int resClass;
|
||||
float scale, m;
|
||||
|
|
@ -3084,6 +3190,9 @@ int spcnAP(node, resClass, scale, asterm, psterm, m, outf, w)
|
|||
{
|
||||
char afmt[15], pfmt[15];
|
||||
float dsc;
|
||||
int area, perim;
|
||||
char *cptr;
|
||||
bool haveAttrs = FALSE;
|
||||
|
||||
if ((node == NULL) || (node->efnode_client == (ClientData)NULL))
|
||||
{
|
||||
|
|
@ -3091,18 +3200,10 @@ int spcnAP(node, resClass, scale, asterm, psterm, m, outf, w)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (esScale < 0)
|
||||
{
|
||||
if (asterm) sprintf(afmt, " %s=%%g", asterm);
|
||||
if (psterm) sprintf(pfmt, " %s=%%g", psterm);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (asterm) sprintf(afmt, " %s=%%gp", asterm);
|
||||
if (psterm) sprintf(pfmt, " %s=%%gu", psterm);
|
||||
}
|
||||
if (asterm) sprintf(afmt, " %s=", asterm);
|
||||
if (psterm) sprintf(pfmt, " %s=", psterm);
|
||||
|
||||
if (!esDistrJunct || w == -1) goto oldFmt;
|
||||
if (!esDistrJunct || w == -1) goto newFmt;
|
||||
|
||||
if (((nodeClient*)node->efnode_client)->m_w.widths != NULL)
|
||||
dsc = w / ((nodeClient*)node->efnode_client)->m_w.widths[resClass];
|
||||
|
|
@ -3115,52 +3216,96 @@ int spcnAP(node, resClass, scale, asterm, psterm, m, outf, w)
|
|||
if (esScale < 0)
|
||||
{
|
||||
if (asterm)
|
||||
fprintf(outf, afmt,
|
||||
node->efnode_pa[resClass].pa_area * scale * scale * dsc);
|
||||
{
|
||||
fprintf(outf, afmt);
|
||||
esSIvalue(outf, 1.0E-12 * node->efnode_pa[resClass].pa_area
|
||||
* scale * scale * dsc);
|
||||
}
|
||||
if (psterm)
|
||||
fprintf(outf, pfmt,
|
||||
node->efnode_pa[resClass].pa_perim * scale * dsc);
|
||||
{
|
||||
fprintf(outf, pfmt);
|
||||
esSIvalue(outf, 1.0E-6 * node->efnode_pa[resClass].pa_perim * scale * dsc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (asterm)
|
||||
fprintf(outf, afmt,
|
||||
((float)node->efnode_pa[resClass].pa_area * scale * scale)
|
||||
* esScale * esScale * dsc);
|
||||
{
|
||||
fprintf(outf, afmt);
|
||||
esSIvalue(outf, 1.0E-12 * ((float)node->efnode_pa[resClass].pa_area
|
||||
* scale * scale) * esScale * esScale * dsc);
|
||||
}
|
||||
if (psterm)
|
||||
fprintf(outf, pfmt,
|
||||
((float)node->efnode_pa[resClass].pa_perim * scale)
|
||||
* esScale * dsc);
|
||||
{
|
||||
fprintf(outf, pfmt);
|
||||
esSIvalue(outf, 1.0E-6 * ((float)node->efnode_pa[resClass].pa_perim
|
||||
* scale) * esScale * dsc);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
oldFmt:
|
||||
newFmt:
|
||||
/* New format introduced 2/15/2023: Area and perimeter of each terminal
|
||||
* are maintained in the terminal attributes for "fet" or "device mosfet"
|
||||
* type devices (otherwise, for subcircuit device types, this routine is
|
||||
* not used and the same values are found in the device parameters).
|
||||
*
|
||||
* Values are the last two values in a comma-separated list in
|
||||
* dterm_attrs. If not found, then default to the
|
||||
*/
|
||||
|
||||
cptr = (dterm) ? dterm->dterm_attrs : NULL;
|
||||
while (cptr)
|
||||
{
|
||||
if (*cptr == ',') cptr++;
|
||||
if (sscanf(cptr, "%d,%d", &area, &perim) != 2)
|
||||
cptr = strchr(cptr, ',');
|
||||
else
|
||||
{
|
||||
haveAttrs = TRUE;
|
||||
*cptr = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!haveAttrs)
|
||||
{
|
||||
area = node->efnode_pa[resClass].pa_area;
|
||||
perim = node->efnode_pa[resClass].pa_perim;
|
||||
|
||||
if (resClass == NO_RESCLASS ||
|
||||
beenVisited((nodeClient *)node->efnode_client, resClass))
|
||||
scale = 0;
|
||||
else
|
||||
markVisited((nodeClient *)node->efnode_client, resClass);
|
||||
}
|
||||
|
||||
if (esScale < 0)
|
||||
{
|
||||
if (asterm)
|
||||
fprintf(outf, afmt,
|
||||
node->efnode_pa[resClass].pa_area * scale * scale / m);
|
||||
{
|
||||
fprintf(outf, afmt);
|
||||
esSIvalue(outf, 1.0E-12 * area * scale * scale / m);
|
||||
}
|
||||
if (psterm)
|
||||
fprintf(outf, pfmt,
|
||||
node->efnode_pa[resClass].pa_perim * scale / m);
|
||||
{
|
||||
fprintf(outf, pfmt);
|
||||
esSIvalue(outf, 1.0E-6 * perim * scale / m);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (asterm)
|
||||
fprintf(outf, afmt,
|
||||
((float)node->efnode_pa[resClass].pa_area * scale * scale)
|
||||
* esScale * esScale);
|
||||
{
|
||||
fprintf(outf, afmt);
|
||||
esSIvalue(outf, 1.0E-12 * ((float)area * scale * scale) * esScale * esScale);
|
||||
}
|
||||
if (psterm)
|
||||
fprintf(outf, pfmt,
|
||||
((float)node->efnode_pa[resClass].pa_perim * scale)
|
||||
* esScale);
|
||||
{
|
||||
fprintf(outf, pfmt);
|
||||
esSIvalue(outf, 1.0E-6 * ((float)perim * scale) * esScale);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3176,17 +3321,13 @@ int spcnAPHier(dterm, hierName, resClass, scale, asterm, psterm, m, outf)
|
|||
EFNode *node = dterm->dterm_node;
|
||||
nodeClientHier *nc;
|
||||
char afmt[15], pfmt[15];
|
||||
int area, perim;
|
||||
char *cptr;
|
||||
bool haveAttrs = FALSE;
|
||||
|
||||
sprintf(afmt," %s=", asterm);
|
||||
sprintf(pfmt," %s=", psterm);
|
||||
|
||||
if (esScale < 0)
|
||||
{
|
||||
sprintf(afmt," %s=%%g", asterm);
|
||||
sprintf(pfmt," %s=%%g", psterm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(afmt," %s=%%gp", asterm);
|
||||
sprintf(pfmt," %s=%%gu", psterm);
|
||||
}
|
||||
if (node->efnode_client == (ClientData) NULL)
|
||||
initNodeClientHier(node);
|
||||
|
||||
|
|
@ -3196,27 +3337,48 @@ int spcnAPHier(dterm, hierName, resClass, scale, asterm, psterm, m, outf)
|
|||
clearVisited(nc);
|
||||
nc->lastPrefix = hierName;
|
||||
}
|
||||
if (resClass == NO_RESCLASS ||
|
||||
beenVisited((nodeClientHier *)node->efnode_client, resClass) )
|
||||
scale = 0.0;
|
||||
|
||||
/* Check for area and perim values in dterm_attrs */
|
||||
|
||||
cptr = dterm->dterm_attrs;
|
||||
while (cptr)
|
||||
{
|
||||
if (*cptr == ',') cptr++;
|
||||
if (sscanf(cptr, "%d,%d", &area, &perim) != 2)
|
||||
cptr = strchr(cptr, ',');
|
||||
else
|
||||
markVisited((nodeClientHier *)node->efnode_client, resClass);
|
||||
{
|
||||
haveAttrs = TRUE;
|
||||
*cptr = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!haveAttrs)
|
||||
{
|
||||
area = node->efnode_pa[resClass].pa_area;
|
||||
perim = node->efnode_pa[resClass].pa_perim;
|
||||
|
||||
if (resClass == NO_RESCLASS ||
|
||||
beenVisited((nodeClient *)node->efnode_client, resClass))
|
||||
scale = 0;
|
||||
else
|
||||
markVisited((nodeClient *)node->efnode_client, resClass);
|
||||
}
|
||||
|
||||
if (esScale < 0)
|
||||
{
|
||||
fprintf(outf, afmt,
|
||||
node->efnode_pa[resClass].pa_area * scale * scale / m);
|
||||
fprintf(outf, pfmt,
|
||||
node->efnode_pa[resClass].pa_perim * scale / m);
|
||||
fprintf(outf, afmt);
|
||||
esSIvalue(outf, 1.0E-12 * area * scale * scale / m);
|
||||
fprintf(outf, pfmt);
|
||||
esSIvalue(outf, 1.0E-6 * perim * scale / m);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(outf, afmt,
|
||||
((float)node->efnode_pa[resClass].pa_area * scale)
|
||||
* esScale * esScale);
|
||||
fprintf(outf, pfmt,
|
||||
((float)node->efnode_pa[resClass].pa_perim * scale)
|
||||
* esScale);
|
||||
fprintf(outf, afmt);
|
||||
esSIvalue(outf, 1.0E-12 * ((float)area * scale) * esScale * esScale);
|
||||
fprintf(outf, pfmt);
|
||||
esSIvalue(outf, 1.0E-6 * ((float)perim * scale) * esScale);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ extern int devDistJunctHierVisit();
|
|||
extern int spcnAPHier();
|
||||
extern void mergeAttr();
|
||||
extern int update_w();
|
||||
extern void esSIvalue();
|
||||
|
||||
/* Options specific to ext2spice */
|
||||
extern bool esDoExtResis;
|
||||
|
|
|
|||
|
|
@ -1083,8 +1083,6 @@ efBuildDevice(def, class, type, r, argc, argv)
|
|||
term = &newdev->dev_terms[n];
|
||||
term->dterm_node = efBuildDevNode(def, av[TERM_NAME], FALSE);
|
||||
term->dterm_length = atoi(av[TERM_PERIM]);
|
||||
term->dterm_area = 0;
|
||||
term->dterm_perim = 0;
|
||||
|
||||
/* If the attr list is '0', this signifies no attributes */
|
||||
if (av[TERM_ATTRS][0] == '0' && av[TERM_ATTRS][1] == '\0')
|
||||
|
|
|
|||
|
|
@ -255,8 +255,6 @@ typedef struct devterm
|
|||
EFNode *dterm_node; /* Node to which we're connected */
|
||||
char *dterm_attrs; /* Attribute list */
|
||||
int dterm_length; /* Length of terminal connection to gate */
|
||||
int dterm_perim; /* Terminal perimeter if passed as a param */
|
||||
int dterm_area; /* Terminal area if passed as a param */
|
||||
} DevTerm;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -105,9 +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.
|
||||
*/
|
||||
int tr_termarea[MAXSD]; /* Total area of the terminal */
|
||||
int tr_termperim[MAXSD]; /* Total perimeter of the terminal */
|
||||
int tr_termshared[MAXSD]; /* Number of devices sharing this terminal */
|
||||
Point tr_termvector[MAXSD]; /* Perimeter traversal vector, used to
|
||||
* find and calculate correct parameters
|
||||
* for annular (ring) devices and other
|
||||
|
|
@ -1061,7 +1061,7 @@ ExtSortTerminals(tran, ll)
|
|||
TermTilePos *p1, *p2;
|
||||
NodeRegion *tmp_node;
|
||||
TermTilePos tmp_pos;
|
||||
int tmp_len, tmp_depth;
|
||||
int tmp_len, tmp_area, tmp_perim, tmp_shared;
|
||||
LabelList *lp;
|
||||
|
||||
do
|
||||
|
|
@ -1089,21 +1089,29 @@ 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];
|
||||
tmp_area = tran->tr_termarea[nsd];
|
||||
tmp_perim = tran->tr_termperim[nsd];
|
||||
tmp_shared = tran->tr_termshared[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_termperim[nsd] = tran->tr_termperim[nsd+1];
|
||||
tran->tr_termarea[nsd] = tran->tr_termarea[nsd+1];
|
||||
tran->tr_termshared[nsd] = tran->tr_termshared[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;
|
||||
tran->tr_termarea[nsd+1] = tmp_area;
|
||||
tran->tr_termperim[nsd+1] = tmp_perim;
|
||||
tran->tr_termshared[nsd+1] = tmp_shared;
|
||||
|
||||
/* 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
|
||||
* that much -- Stefanos 5/96 */
|
||||
|
||||
for ( lp = ll ; lp ; lp = lp->ll_next )
|
||||
if ( lp->ll_attr == nsd ) lp->ll_attr = LL_SORTATTR ;
|
||||
else if ( lp->ll_attr == nsd+1 ) lp->ll_attr = nsd ;
|
||||
|
|
@ -1690,13 +1698,13 @@ extOutputParameters(def, transList, outFile)
|
|||
*/
|
||||
|
||||
void
|
||||
extOutputDevParams(reg, devptr, outFile, length, width, depthvec)
|
||||
extOutputDevParams(reg, devptr, outFile, length, width, areavec)
|
||||
TransRegion *reg;
|
||||
ExtDevice *devptr;
|
||||
FILE *outFile;
|
||||
int length;
|
||||
int width;
|
||||
int *depthvec;
|
||||
int *areavec;
|
||||
{
|
||||
ParamList *chkParam;
|
||||
|
||||
|
|
@ -1710,12 +1718,14 @@ extOutputDevParams(reg, devptr, outFile, length, width, depthvec)
|
|||
chkParam->pl_param[1] == '0')
|
||||
fprintf(outFile, " %c=%d", chkParam->pl_param[0],
|
||||
reg->treg_area);
|
||||
/* Note: a1, a2, etc., are standard output */
|
||||
break;
|
||||
case 'p':
|
||||
if (chkParam->pl_param[1] == '\0' ||
|
||||
chkParam->pl_param[1] == '0')
|
||||
fprintf(outFile, " %c=%d", chkParam->pl_param[0],
|
||||
extTransRec.tr_perim);
|
||||
/* Note: p1, p2, etc., are standard output */
|
||||
break;
|
||||
case 'l':
|
||||
if (chkParam->pl_param[1] == '\0' ||
|
||||
|
|
@ -1725,10 +1735,12 @@ extOutputDevParams(reg, devptr, outFile, length, width, depthvec)
|
|||
else if (chkParam->pl_param[1] > '0' && chkParam->pl_param[1] <= '9')
|
||||
{
|
||||
int tidx = chkParam->pl_param[1] - '1';
|
||||
/* output depth of terminal */
|
||||
/* output length of terminal, assuming a rectangular
|
||||
* shape, as simplified terminal area / width
|
||||
*/
|
||||
fprintf(outFile, " %c%c=%d", chkParam->pl_param[0],
|
||||
chkParam->pl_param[1],
|
||||
depthvec[tidx]);
|
||||
areavec[tidx] / width);
|
||||
}
|
||||
break;
|
||||
case 'w':
|
||||
|
|
@ -1953,7 +1965,9 @@ 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_termarea[extTransRec.tr_nterm] = 0;
|
||||
extTransRec.tr_termperim[extTransRec.tr_nterm] = 0;
|
||||
extTransRec.tr_termshared[extTransRec.tr_nterm] = 0;
|
||||
extTransRec.tr_termnode[extTransRec.tr_nterm++] = node;
|
||||
}
|
||||
}
|
||||
|
|
@ -2177,7 +2191,7 @@ extOutputDevices(def, transList, outFile)
|
|||
}
|
||||
|
||||
extOutputDevParams(reg, devptr, outFile, length, width,
|
||||
extTransRec.tr_termdepth);
|
||||
extTransRec.tr_termarea);
|
||||
|
||||
fprintf(outFile, " \"%s\"", (subsName == NULL) ?
|
||||
"None" : subsName);
|
||||
|
|
@ -2187,7 +2201,7 @@ extOutputDevices(def, transList, outFile)
|
|||
case DEV_NDIODE:
|
||||
case DEV_PDIODE:
|
||||
extOutputDevParams(reg, devptr, outFile, length, width,
|
||||
extTransRec.tr_termdepth);
|
||||
extTransRec.tr_termarea);
|
||||
if (subsName != NULL)
|
||||
fprintf(outFile, " \"%s\"", subsName);
|
||||
break;
|
||||
|
|
@ -2315,7 +2329,7 @@ extOutputDevices(def, transList, outFile)
|
|||
fprintf(outFile, " %g", dres / 1000.0); /* mOhms -> Ohms */
|
||||
|
||||
extOutputDevParams(reg, devptr, outFile, length, width,
|
||||
extTransRec.tr_termdepth);
|
||||
extTransRec.tr_termarea);
|
||||
|
||||
if (devptr->exts_deviceClass == DEV_RSUBCKT)
|
||||
{
|
||||
|
|
@ -2406,7 +2420,7 @@ extOutputDevices(def, transList, outFile)
|
|||
}
|
||||
|
||||
extOutputDevParams(reg, devptr, outFile, length, width,
|
||||
extTransRec.tr_termdepth);
|
||||
extTransRec.tr_termarea);
|
||||
|
||||
if (devptr->exts_deviceClass == DEV_CSUBCKT)
|
||||
{
|
||||
|
|
@ -2428,7 +2442,7 @@ extOutputDevices(def, transList, outFile)
|
|||
node = (NodeRegion *) extGetRegion(reg->treg_tile);
|
||||
ll = node->nreg_labels;
|
||||
extTransOutTerminal((LabRegion *) node, ll, LL_GATEATTR,
|
||||
extTransRec.tr_gatelen, outFile);
|
||||
extTransRec.tr_gatelen, 0, 0, 0, outFile);
|
||||
|
||||
/* Sort source and drain terminals by position, unless the */
|
||||
/* device is asymmetric, in which case source and drain do not */
|
||||
|
|
@ -2440,7 +2454,10 @@ extOutputDevices(def, transList, outFile)
|
|||
/* each non-gate terminal */
|
||||
for (nsd = 0; nsd < extTransRec.tr_nterm; nsd++)
|
||||
extTransOutTerminal((LabRegion *) extTransRec.tr_termnode[nsd], ll,
|
||||
nsd, extTransRec.tr_termlen[nsd], outFile);
|
||||
nsd, extTransRec.tr_termlen[nsd],
|
||||
extTransRec.tr_termarea[nsd],
|
||||
extTransRec.tr_termperim[nsd],
|
||||
extTransRec.tr_termshared[nsd], outFile);
|
||||
|
||||
(void) fputs("\n", outFile);
|
||||
}
|
||||
|
|
@ -2867,6 +2884,171 @@ extTransTileFunc(tile, pNum, arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Structures used by extTermAPFunc() for storing area and perimeter data */
|
||||
|
||||
typedef struct _nodelist {
|
||||
struct _nodelist *nl_next;
|
||||
NodeRegion *nl_node;
|
||||
} ExtNodeList;
|
||||
|
||||
typedef struct _extareaperimdata {
|
||||
int eapd_area;
|
||||
int eapd_perim;
|
||||
TileTypeBitMask eapd_mask;
|
||||
TileTypeBitMask *eapd_gatemask;
|
||||
NodeRegion *eapd_gatenode;
|
||||
ExtNodeList *eapd_shared;
|
||||
} ExtAreaPerimData;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* extAddSharedDevice --
|
||||
*
|
||||
* Add a node region representing a device to the list of nodes
|
||||
* kept in the structure passed to extTermAPFunc(), to keep track
|
||||
* of how many devices share the same terminal area.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
extAddSharedDevice(eapd, node)
|
||||
ExtAreaPerimData *eapd;
|
||||
NodeRegion *node;
|
||||
{
|
||||
ExtNodeList *nl, *newnl;
|
||||
|
||||
for (nl = eapd->eapd_shared; nl; nl = nl->nl_next)
|
||||
if (nl->nl_node == node) break;
|
||||
|
||||
if (nl == NULL)
|
||||
{
|
||||
newnl = (ExtNodeList *)mallocMagic(sizeof(ExtNodeList));
|
||||
newnl->nl_node = node;
|
||||
newnl->nl_next = eapd->eapd_shared;
|
||||
eapd->eapd_shared = newnl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* extTermAPFunc --
|
||||
*
|
||||
* Callback function used by extTransPerimFunc() to find the largest
|
||||
* area encompassing a device terminal. This is the bounding box of
|
||||
* the area containing terminal types connected to a device tile.
|
||||
*
|
||||
* This routine is redundant with the area and perimeter calculations
|
||||
* in extFindNodes(), but that routine traverses an entire net. This
|
||||
* routine finds the area and perimeter belonging to material on a
|
||||
* single plane extending from a device (e.g., diffusion and contacts
|
||||
* on a FET source or drain).
|
||||
*
|
||||
* Note that this definition is not necessarily accurate for defining
|
||||
* terminal area and perimeter, as the area of terminal types may not
|
||||
* be rectangular, making an approximation using length and width
|
||||
* inappropriate.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
extTermAPFunc(tile, pNum, eapd)
|
||||
Tile *tile; /* Tile extending a device terminal */
|
||||
int pNum; /* Plane of tile (unused, set to -1) */
|
||||
ExtAreaPerimData *eapd; /* Area and perimeter totals for terminal */
|
||||
{
|
||||
TileType type;
|
||||
Tile *tp;
|
||||
Rect r;
|
||||
|
||||
TiToRect(tile, &r);
|
||||
eapd->eapd_area += (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot);
|
||||
|
||||
/* Diagonal */
|
||||
if (IsSplit(tile))
|
||||
{
|
||||
int w, h, l;
|
||||
type = (SplitSide(tile)) ? SplitLeftType(tile): SplitRightType(tile);
|
||||
w = RIGHT(tile) - LEFT(tile);
|
||||
h = TOP(tile) - BOTTOM(tile);
|
||||
l = w * w + h * h;
|
||||
eapd->eapd_perim += (int)sqrt((double)l);
|
||||
}
|
||||
|
||||
/* Top */
|
||||
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
||||
{
|
||||
type = TiGetBottomType(tp);
|
||||
if (TTMaskHasType(&eapd->eapd_mask, type))
|
||||
{
|
||||
eapd->eapd_perim += MIN(RIGHT(tile), RIGHT(tp)) -
|
||||
MAX(LEFT(tile), LEFT(tp));
|
||||
if (TTMaskHasType(eapd->eapd_gatemask, type))
|
||||
if (tp->ti_client != (ClientData)eapd->eapd_gatenode)
|
||||
extAddSharedDevice(eapd, (NodeRegion *)tp->ti_client);
|
||||
}
|
||||
}
|
||||
|
||||
/* Bottom */
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
||||
{
|
||||
type = TiGetTopType(tp);
|
||||
if (TTMaskHasType(&eapd->eapd_mask, type))
|
||||
{
|
||||
eapd->eapd_perim += MIN(RIGHT(tile), RIGHT(tp)) -
|
||||
MAX(LEFT(tile), LEFT(tp));
|
||||
if (TTMaskHasType(eapd->eapd_gatemask, type))
|
||||
if (tp->ti_client != (ClientData)eapd->eapd_gatenode)
|
||||
extAddSharedDevice(eapd, (NodeRegion *)tp->ti_client);
|
||||
}
|
||||
}
|
||||
|
||||
/* Left */
|
||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
||||
{
|
||||
type = TiGetRightType(tp);
|
||||
if (TTMaskHasType(&eapd->eapd_mask, type))
|
||||
{
|
||||
eapd->eapd_perim += MIN(TOP(tile), TOP(tp)) -
|
||||
MAX(BOTTOM(tile), BOTTOM(tp));
|
||||
if (TTMaskHasType(eapd->eapd_gatemask, type))
|
||||
if (tp->ti_client != (ClientData)eapd->eapd_gatenode)
|
||||
extAddSharedDevice(eapd, (NodeRegion *)tp->ti_client);
|
||||
}
|
||||
}
|
||||
|
||||
/* Right */
|
||||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
||||
{
|
||||
type = TiGetLeftType(tp);
|
||||
if (TTMaskHasType(&eapd->eapd_mask, type))
|
||||
{
|
||||
eapd->eapd_perim += MIN(TOP(tile), TOP(tp)) -
|
||||
MAX(BOTTOM(tile), BOTTOM(tp));
|
||||
if (TTMaskHasType(eapd->eapd_gatemask, type))
|
||||
if (tp->ti_client != (ClientData)eapd->eapd_gatenode)
|
||||
extAddSharedDevice(eapd, (NodeRegion *)tp->ti_client);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* extTransPerimFunc --
|
||||
*
|
||||
* Callback function for exploring the perimeter of a device to find
|
||||
* areas connected to the device (e.g., gate) and areas adjacent but
|
||||
* not connected (e.g., source and drain).
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
extTransPerimFunc(bp)
|
||||
Boundary *bp;
|
||||
|
|
@ -2875,11 +3057,10 @@ extTransPerimFunc(bp)
|
|||
Tile *tile;
|
||||
NodeRegion *diffNode = (NodeRegion *) extGetRegion(bp->b_outside);
|
||||
ExtDevice *devptr, *deventry;
|
||||
int i, depth, len = BoundaryLength(bp);
|
||||
int i, area, perim, len = BoundaryLength(bp);
|
||||
int thisterm;
|
||||
LabelList *ll;
|
||||
Label *lab;
|
||||
Rect r;
|
||||
bool SDterm = FALSE;
|
||||
|
||||
tile = bp->b_inside;
|
||||
|
|
@ -2893,17 +3074,6 @@ 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
|
||||
|
|
@ -2943,7 +3113,9 @@ extTransPerimFunc(bp)
|
|||
extTransRec.tr_nterm++;
|
||||
extTransRec.tr_termnode[thisterm] = diffNode;
|
||||
extTransRec.tr_termlen[thisterm] = 0;
|
||||
extTransRec.tr_termdepth[thisterm] = 0;
|
||||
extTransRec.tr_termarea[thisterm] = 0;
|
||||
extTransRec.tr_termperim[thisterm] = 0;
|
||||
extTransRec.tr_termshared[thisterm] = 0;
|
||||
extTransRec.tr_termvector[thisterm].p_x = 0;
|
||||
extTransRec.tr_termvector[thisterm].p_y = 0;
|
||||
extTransRec.tr_termpos[thisterm].pnum = DBPlane(toutside);
|
||||
|
|
@ -2986,9 +3158,39 @@ 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;
|
||||
if (extTransRec.tr_termarea[thisterm] == 0)
|
||||
{
|
||||
/* Find the area and perimeter of the terminal area (connected
|
||||
* area outside the boundary on a single plane). Note that
|
||||
* this does not consider terminal area outside of the cell
|
||||
* or how area or perimeter may be shared or overlap between
|
||||
* devices.
|
||||
*/
|
||||
|
||||
ExtAreaPerimData eapd;
|
||||
int shared;
|
||||
|
||||
eapd.eapd_area = eapd.eapd_perim = 0;
|
||||
TTMaskCom2(&eapd.eapd_mask, &DBConnectTbl[toutside]);
|
||||
eapd.eapd_gatemask = &ExtCurStyle->exts_deviceMask;
|
||||
eapd.eapd_gatenode = (NodeRegion *)extGetRegion(bp->b_inside);
|
||||
eapd.eapd_shared = NULL;
|
||||
|
||||
DBSrConnectOnePlane(bp->b_outside, DBConnectTbl,
|
||||
extTermAPFunc, (ClientData)&eapd);
|
||||
|
||||
shared = 1;
|
||||
while (eapd.eapd_shared)
|
||||
{
|
||||
shared++;
|
||||
freeMagic(eapd.eapd_shared);
|
||||
eapd.eapd_shared = eapd.eapd_shared->nl_next;
|
||||
}
|
||||
|
||||
extTransRec.tr_termarea[thisterm] = eapd.eapd_area;
|
||||
extTransRec.tr_termperim[thisterm] = eapd.eapd_perim;
|
||||
extTransRec.tr_termshared[thisterm] = shared;
|
||||
}
|
||||
|
||||
/* Update the boundary traversal vector */
|
||||
switch(bp->b_direction) {
|
||||
|
|
@ -3435,13 +3637,16 @@ extSpecialPerimFunc(bp, sense)
|
|||
*/
|
||||
|
||||
void
|
||||
extTransOutTerminal(lreg, ll, whichTerm, len, outFile)
|
||||
extTransOutTerminal(lreg, ll, whichTerm, len, area, perim, shared, outFile)
|
||||
LabRegion *lreg; /* Node connected to terminal */
|
||||
LabelList *ll; /* Gate's label list */
|
||||
int whichTerm; /* Which terminal we are processing. The gate
|
||||
* is indicated by LL_GATEATTR.
|
||||
*/
|
||||
int len; /* Length of perimeter along terminal */
|
||||
int area; /* Total area of terminal */
|
||||
int perim; /* Total perimeter of terminal (includes len) */
|
||||
int shared; /* Number of devices sharing the terminal */
|
||||
FILE *outFile; /* Output file */
|
||||
{
|
||||
char *cp;
|
||||
|
|
@ -3463,7 +3668,16 @@ extTransOutTerminal(lreg, ll, whichTerm, len, outFile)
|
|||
fmt = ',';
|
||||
}
|
||||
|
||||
if (fmt == ' ')
|
||||
/* NOTE: The area and perimeter of a terminal are divided equally
|
||||
* among devices that share the same terminal area. This may not
|
||||
* necessarily be the best way to handle shared terminals; in
|
||||
* particular, it is preferable to detect and output fingered
|
||||
* devices separately.
|
||||
*/
|
||||
|
||||
if ((whichTerm != LL_GATEATTR) && (area != 0) && (perim != 0))
|
||||
fprintf(outFile, "%c%d,%d", fmt, (area / shared), (perim / shared));
|
||||
else if (fmt == ' ')
|
||||
fprintf(outFile, " 0");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "textio/txcommands.h"
|
||||
#include "resis/resis.h"
|
||||
|
||||
int resSubDevFunc();
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -440,45 +438,3 @@ ResEachTile(tile, startpoint)
|
|||
|
||||
return(merged);
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* resSubDevFunc -- called when DBSrPaintArea finds a device within
|
||||
* a substrate area.
|
||||
*
|
||||
* Results: always returns 0 to keep search going.
|
||||
*
|
||||
* Side Effects: allocates substrate node.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
resSubDevFunc(tile, tp)
|
||||
Tile *tile, *tp;
|
||||
{
|
||||
tileJunk *junk = (tileJunk *)(tile->ti_client);
|
||||
resNode *resptr;
|
||||
tElement *tcell;
|
||||
int x, y;
|
||||
|
||||
if (junk->deviceList->rd_fet_subs == NULL)
|
||||
{
|
||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||
junk->deviceList->rd_fet_subs = resptr;
|
||||
junk->tj_status |= RES_TILE_DEV;
|
||||
tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
|
||||
tcell->te_thist = junk->deviceList;
|
||||
tcell->te_nextt = NULL;
|
||||
x = (LEFT(tile) + RIGHT(tile)) >> 1;
|
||||
y = (TOP(tile) + BOTTOM(tile)) >> 1;
|
||||
|
||||
InitializeNode(resptr, x, y, RES_NODE_JUNCTION);
|
||||
resptr->rn_te = tcell;
|
||||
ResAddToQueue(resptr, &ResNodeQueue);
|
||||
|
||||
NEWBREAK(resptr, tp, x, y, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -382,8 +382,9 @@ ResSimSubckt(line)
|
|||
if (!strcmp(EFDevTypes[j], line[i]))
|
||||
break;
|
||||
|
||||
/* Read attributes, especially to pick up values for L, W, X, and Y,
|
||||
* that are critical for use by extresist.
|
||||
/* Read attributes, especially to pick up values for L, W, X, and Y;
|
||||
* and source and drain area and perimeter, that are critical for use
|
||||
* by extresist.
|
||||
*/
|
||||
for (k = 1; line[k][0] != '\0'; k++)
|
||||
{
|
||||
|
|
@ -406,6 +407,12 @@ ResSimSubckt(line)
|
|||
case 'y':
|
||||
device->location.p_y = (int)((float)atof(eqptr) / lambda);
|
||||
break;
|
||||
case 's':
|
||||
device->rs_sattr = StrDup((char **)NULL, eqptr);
|
||||
break;
|
||||
case 'd':
|
||||
device->rs_dattr = StrDup((char **)NULL, eqptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -531,30 +538,47 @@ ResSimDevice(line, rpersquare, devptr)
|
|||
|
||||
/* sim attributes look like g=a1,a2 */
|
||||
/* ext attributes are "a1","a2" */
|
||||
/* do conversion from one to the other here */
|
||||
/* Do conversion from one to the other here */
|
||||
/* NOTE: As of version 8.3.366, .ext attributes will end in two */
|
||||
/* integer values, not quoted, for device area and perimeter. Do */
|
||||
/* not quote them. */
|
||||
|
||||
for (i = RDEV_ATTR; i < RDEV_ATTR + RDEV_NUM_ATTR; i++)
|
||||
{
|
||||
char *cptr, *sptr;
|
||||
int d1, d2;
|
||||
|
||||
if (line[i][0] == '\0') break;
|
||||
k = 0;
|
||||
tmpattr[k++] = '"';
|
||||
for (j = 2; line[i][j] != '\0'; j++)
|
||||
|
||||
sptr = &line[i][2]; /* Start after "s=" or "d=" */
|
||||
tmpattr[0] = '\0';
|
||||
while ((cptr = strchr(sptr, ',')) != NULL)
|
||||
{
|
||||
if (line[i][j] == ',')
|
||||
if (sscanf(sptr, "%d,%d", &d1, &d2) == 2)
|
||||
{
|
||||
tmpattr[k++] = '"';
|
||||
tmpattr[k++] = ',';
|
||||
tmpattr[k++] = '"';
|
||||
strcat(tmpattr, sptr);
|
||||
sptr = NULL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpattr[k++] = line[i][j];
|
||||
*cptr = '\0';
|
||||
strcat(tmpattr, "\"");
|
||||
strcat(tmpattr, sptr);
|
||||
strcat(tmpattr, "\",");
|
||||
sptr = cptr + 1;
|
||||
*cptr = ',';
|
||||
}
|
||||
}
|
||||
tmpattr[k++] = '"';
|
||||
tmpattr[k++] = '\0';
|
||||
newattr = (char *)mallocMagic((unsigned)k);
|
||||
strncpy(newattr, tmpattr, k);
|
||||
if (sptr && (strlen(sptr) != 0))
|
||||
{
|
||||
strcat(tmpattr, "\"");
|
||||
strcat(tmpattr, sptr);
|
||||
strcat(tmpattr, "\"");
|
||||
}
|
||||
|
||||
newattr = (char *)mallocMagic(strlen(tmpattr) + 1);
|
||||
strcpy(newattr, tmpattr);
|
||||
switch (line[i][0])
|
||||
{
|
||||
case 'g':
|
||||
|
|
|
|||
Loading…
Reference in New Issue