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:
Tim Edwards 2023-02-16 11:59:13 -05:00
parent 87702ac98a
commit c7f11d2169
12 changed files with 698 additions and 244 deletions

View File

@ -1 +1 @@
8.3.366
8.3.367

View File

@ -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.

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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')

View File

@ -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;
/*

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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':