A number of changes:
1) Corrected spurious error messages about cells already existing in GDS when using "flatten" or "flatglob". 2) Fixed handling of resistance as a subcircuit parameter 3) Added area and perimeter resistance for a device; this is done through the "devresist" statement in the tech file, which is an extension of the original "fetresist" statement. Where "fetresist" only supported type "linear", "devresist" supports types "area" and "perimeter". 4) Support for CDL syntax, including generating subcircuit-like parameters for components starting with SPICE-standard prefixes like M, R, C, etc., adding "/" between pins and subcircuit name, and saving the file as ".cdl" instead of ".spice". 5) Estimated L and W for devices whose geometry is complex and do not reduce to a simple rectangle. L and W are estimated as the square root of the area. 6) Changed the method of extracting L and W for diodes to use the same method as capacitors. Note that diodes are not usually specified by L and W, but if they are, this will produce the right result. 7) Corrected the reported filename and line number when printing error messages related to errors inside a technology file, when the technology file uses "include" to combine multiple files.
This commit is contained in:
parent
b1c7b52ed2
commit
78f7d22796
|
|
@ -387,6 +387,15 @@ calmaParseStructure(
|
|||
he = HashFind(&calmaDefInitHash, strname);
|
||||
if ((def = (CellDef *)HashGetValue(he)) != NULL)
|
||||
{
|
||||
if (def->cd_flags & CDPRELOADED)
|
||||
{
|
||||
/* Cell definition was read ahead due to option "flatten" */
|
||||
/* or "flatglob". Do not complain about seeing it again. */
|
||||
def->cd_flags &= ~CDPRELOADED;
|
||||
calmaNextCell();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (def->cd_flags & CDPROCESSEDGDS)
|
||||
{
|
||||
/* If cell definition was marked as processed, then skip */
|
||||
|
|
@ -396,6 +405,7 @@ calmaParseStructure(
|
|||
|
||||
if (!CalmaPostOrder && !CalmaRewound)
|
||||
{
|
||||
cifReadCellDef = def;
|
||||
CalmaReadError("Cell \"%s\" was already defined in this file.\n",
|
||||
strname);
|
||||
CalmaReadError("Ignoring duplicate definition\n");
|
||||
|
|
@ -407,6 +417,7 @@ calmaParseStructure(
|
|||
{
|
||||
char *newname;
|
||||
|
||||
cifReadCellDef = def;
|
||||
CalmaReadError("Cell \"%s\" was already defined in this file.\n",
|
||||
strname);
|
||||
newname = (char *)mallocMagic(strlen(strname) + 20);
|
||||
|
|
@ -773,6 +784,7 @@ calmaElementSref(
|
|||
bool madeinst = FALSE;
|
||||
char *sname = NULL;
|
||||
bool isArray = FALSE;
|
||||
bool dolookahead = FALSE;
|
||||
Transform trans, tinv;
|
||||
Point refarray[3], refunscaled[3], p;
|
||||
CellUse *use;
|
||||
|
|
@ -798,7 +810,38 @@ calmaElementSref(
|
|||
*/
|
||||
|
||||
def = calmaLookCell(sname);
|
||||
if (!def && (CalmaPostOrder || CalmaFlattenUses || (CalmaFlattenUsesByName != NULL)))
|
||||
|
||||
/*
|
||||
* If the "flatten" option is set, then we always have to seek
|
||||
* ahead and read the structure in order to determine if it
|
||||
* meets the requirement of being flattened or not. If the
|
||||
* "flatglob" option is set, then we need to read ahead and
|
||||
* read the cell definition so that it can be flatten. This
|
||||
* requires pattern-matching the cell def.
|
||||
*/
|
||||
|
||||
dolookahead = (CalmaPostOrder || CalmaFlattenUses) ? TRUE : FALSE;
|
||||
if ((!dolookahead) && (CalmaFlattenUsesByName != NULL))
|
||||
{
|
||||
char *pattern;
|
||||
|
||||
i = 0;
|
||||
while (TRUE)
|
||||
{
|
||||
pattern = CalmaFlattenUsesByName[i];
|
||||
if (pattern == NULL) break;
|
||||
i++;
|
||||
|
||||
/* Check pattern against strname */
|
||||
if (Match(pattern, sname))
|
||||
{
|
||||
dolookahead = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!def && dolookahead)
|
||||
{
|
||||
/* Force the GDS parser to read the cell definition in
|
||||
* post-order. If cellname "sname" is not defined before
|
||||
|
|
@ -832,6 +875,7 @@ calmaElementSref(
|
|||
FSEEK(calmaInputFile, originalFilePos, SEEK_SET);
|
||||
cifReadCellDef = calmaLookCell(currentSname);
|
||||
def = calmaLookCell(sname);
|
||||
def->cd_flags |= CDPRELOADED;
|
||||
cifCurReadPlanes = savePlanes;
|
||||
calmaLayerHash = OrigCalmaLayerHash;
|
||||
if (crsMultiplier != cifCurReadStyle->crs_multiplier)
|
||||
|
|
|
|||
|
|
@ -403,6 +403,9 @@ typedef struct celldef
|
|||
* is added to the magic database. The flag is used to identify
|
||||
* whether the cell has been processed when forcing the GDS
|
||||
* stream data to be read in post-order.
|
||||
* CDPRELOADED is similar to CDPROCESSEDGDS but is used in cases
|
||||
* other than forced post-order reading, such as flattening
|
||||
* or flatten-by-name.
|
||||
* CDVENDORGDS indicates that the cell was read from a GDS stream
|
||||
* with the option "gds readonly true".
|
||||
* CDVISITED indicates that at least one instance of the cell was
|
||||
|
|
@ -434,12 +437,13 @@ typedef struct celldef
|
|||
#define CDFLATGDS 0x00400
|
||||
#define CDFLATTENED 0x00800
|
||||
#define CDPROCESSEDGDS 0x01000
|
||||
#define CDVENDORGDS 0x02000
|
||||
#define CDVISITED 0x04000
|
||||
#define CDDEREFERENCE 0x08000
|
||||
#define CDFIXEDSTAMP 0x10000
|
||||
#define CDNOEXTRACT 0x20000
|
||||
#define CDDONTUSE 0x40000
|
||||
#define CDPRELOADED 0x02000
|
||||
#define CDVENDORGDS 0x04000
|
||||
#define CDVISITED 0x08000
|
||||
#define CDDEREFERENCE 0x10000
|
||||
#define CDFIXEDSTAMP 0x20000
|
||||
#define CDNOEXTRACT 0x40000
|
||||
#define CDDONTUSE 0x80000
|
||||
|
||||
#include "database/arrayinfo.h" /* ArrayInfo */
|
||||
|
||||
|
|
|
|||
|
|
@ -371,11 +371,11 @@ spcHierWriteParams(
|
|||
break;
|
||||
case 'r':
|
||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||
fprintf(esSpiceF, "%f", (double)(dev->dev_res));
|
||||
esSIvalue(esSpiceF, (double)(dev->dev_res));
|
||||
break;
|
||||
case 'c':
|
||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||
fprintf(esSpiceF, "%ff", (double)(dev->dev_cap));
|
||||
esSIvalue(esSpiceF, (double)(dev->dev_cap));
|
||||
break;
|
||||
}
|
||||
plist = plist->parm_next;
|
||||
|
|
@ -840,6 +840,8 @@ spcdevHierVisit(
|
|||
subnode->efnode_name->efnn_hier,
|
||||
dev->dev_type, esSpiceF);
|
||||
}
|
||||
/* Support for CDL format */
|
||||
if (esFormat == CDL) fprintf(esSpiceF, " /");
|
||||
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
|
||||
|
||||
/* Write all requested parameters to the subcircuit call. */
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ CmdExtToSpice(
|
|||
static int LocResistThreshold = INFINITE_THRESHOLD;
|
||||
|
||||
static const char * const spiceFormats[] = {
|
||||
"SPICE2", "SPICE3", "HSPICE", "NGSPICE", NULL
|
||||
"SPICE2", "SPICE3", "HSPICE", "NGSPICE", "CDL", NULL
|
||||
};
|
||||
|
||||
static const char * const cmdExtToSpcOption[] = {
|
||||
|
|
@ -330,6 +330,7 @@ CmdExtToSpice(
|
|||
"spice3",
|
||||
"hspice",
|
||||
"ngspice",
|
||||
"cdl",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -663,10 +664,10 @@ CmdExtToSpice(
|
|||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetResult(magicinterp, "Bad format type. Formats are:"
|
||||
"spice2, spice3, hspice, and ngspice.", NULL);
|
||||
"spice2, spice3, hspice, ngspice, and cdl.", NULL);
|
||||
#else
|
||||
TxError("Bad format type. Formats are:"
|
||||
"spice2, spice3, hspice, and ngspice.");
|
||||
"spice2, spice3, hspice, ngspice, and cdl.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
@ -876,7 +877,12 @@ runexttospice:
|
|||
*/
|
||||
|
||||
if (spcesOutName == spcesDefaultOut)
|
||||
sprintf(spcesDefaultOut, "%s.spice", inName);
|
||||
{
|
||||
if (esFormat == CDL)
|
||||
sprintf(spcesDefaultOut, "%s.cdl", inName);
|
||||
else
|
||||
sprintf(spcesDefaultOut, "%s.spice", inName);
|
||||
}
|
||||
|
||||
/* Read the hierarchical description of the input circuit */
|
||||
if (EFReadFile(inName, esDoHierarchy, esDoExtResis, FALSE, TRUE)
|
||||
|
|
@ -963,8 +969,11 @@ runexttospice:
|
|||
|
||||
locsubname = StrDup(NULL, subname);
|
||||
|
||||
bangptr = locsubname + strlen(locsubname) - 1;
|
||||
if (*bangptr == '!') *bangptr = '\0';
|
||||
if (esFormat != CDL)
|
||||
{
|
||||
bangptr = locsubname + strlen(locsubname) - 1;
|
||||
if (*bangptr == '!') *bangptr = '\0';
|
||||
}
|
||||
|
||||
// Ad-hoc check: Global names with "Error", "err", etc.
|
||||
// should be rejected from the list. Also node name
|
||||
|
|
@ -993,6 +1002,42 @@ runexttospice:
|
|||
}
|
||||
}
|
||||
|
||||
if (esFormat == CDL)
|
||||
{
|
||||
/* In CDL format, if the global substrate ends with "!" then
|
||||
* add it to the list of globals; likewise for VDD and GND.
|
||||
*/
|
||||
char *glbstr;
|
||||
globalList *glptr;
|
||||
|
||||
glbstr = (char *)Tcl_GetVar(magicinterp, "SUB", TCL_GLOBAL_ONLY);
|
||||
if ((glbstr != NULL) && (*(glbstr + strlen(glbstr) - 1) == '!'))
|
||||
{
|
||||
glptr = (globalList *)mallocMagic(sizeof(globalList));
|
||||
glptr->gll_name = StrDup((char **)NULL, glbstr);
|
||||
glptr->gll_next = glist;
|
||||
glist = glptr;
|
||||
}
|
||||
|
||||
glbstr = (char *)Tcl_GetVar(magicinterp, "VDD", TCL_GLOBAL_ONLY);
|
||||
if ((glbstr != NULL) && (*(glbstr + strlen(glbstr) - 1) == '!'))
|
||||
{
|
||||
glptr = (globalList *)mallocMagic(sizeof(globalList));
|
||||
glptr->gll_name = StrDup((char **)NULL, glbstr);
|
||||
glptr->gll_next = glist;
|
||||
glist = glptr;
|
||||
}
|
||||
|
||||
glbstr = (char *)Tcl_GetVar(magicinterp, "GND", TCL_GLOBAL_ONLY);
|
||||
if ((glbstr != NULL) && (*(glbstr + strlen(glbstr) - 1) == '!'))
|
||||
{
|
||||
glptr = (globalList *)mallocMagic(sizeof(globalList));
|
||||
glptr->gll_name = StrDup((char **)NULL, glbstr);
|
||||
glptr->gll_next = glist;
|
||||
glist = glptr;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (EFCompat == TRUE)
|
||||
{
|
||||
|
|
@ -1027,6 +1072,8 @@ runexttospice:
|
|||
if (IS_FINITE_F(EFCapThreshold)) flatFlags |= EF_FLATCAPS;
|
||||
if (esFormat == HSPICE)
|
||||
EFOutputFlags |= EF_TRIMLOCAL;
|
||||
if (esFormat == CDL)
|
||||
EFOutputFlags &= ~EF_TRIMGLOB;
|
||||
|
||||
/* Write globals under a ".global" card */
|
||||
|
||||
|
|
@ -1226,7 +1273,13 @@ main(
|
|||
*/
|
||||
|
||||
if (spcesOutName == spcesDefaultOut)
|
||||
sprintf(spcesDefaultOut, "%s.spice", inName);
|
||||
{
|
||||
if (esFormat == CDL)
|
||||
sprintf(spcesDefaultOut, "%s.cdl", inName);
|
||||
else
|
||||
sprintf(spcesDefaultOut, "%s.spice", inName);
|
||||
}
|
||||
|
||||
|
||||
if ((esSpiceF = fopen(spcesOutName, "w")) == NULL)
|
||||
{
|
||||
|
|
@ -1363,7 +1416,7 @@ spcParseArgs(
|
|||
|
||||
const char usage_text[] = "Usage: ext2spice "
|
||||
"[-B] [-o spicefile] [-M|-m] [-J flat|hier]\n"
|
||||
"[-f spice2|spice3|hspice|ngspice] [-M] [-m] "
|
||||
"[-f spice2|spice3|hspice|ngspice|cdl] [-M] [-m] "
|
||||
"[file]\n";
|
||||
|
||||
switch (argv[0][1])
|
||||
|
|
@ -1407,6 +1460,8 @@ spcParseArgs(
|
|||
}
|
||||
else if (strcasecmp(ftmp, "NGSPICE") == 0)
|
||||
esFormat = NGSPICE;
|
||||
else if (strcasecmp(ftmp, "CDL") == 0)
|
||||
esFormat = CDL;
|
||||
else goto usage;
|
||||
break;
|
||||
|
||||
|
|
@ -1677,6 +1732,7 @@ subcktVisit(
|
|||
}
|
||||
|
||||
if (tchars > 80) fprintf(esSpiceF, "\n+");
|
||||
if (esFormat == CDL) fprintf(esSpiceF, " /");
|
||||
fprintf(esSpiceF, " %s", subcktname); /* subcircuit model name */
|
||||
|
||||
// Check for a "device parameter" defined with the name of the cell.
|
||||
|
|
@ -2256,11 +2312,11 @@ spcWriteParams(
|
|||
break;
|
||||
case 'r':
|
||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||
fprintf(esSpiceF, "%f", (double)(dev->dev_res));
|
||||
esSIvalue(esSpiceF, (double)dev->dev_res);
|
||||
break;
|
||||
case 'c':
|
||||
fprintf(esSpiceF, " %s=", plist->parm_name);
|
||||
fprintf(esSpiceF, "%ff", (double)(dev->dev_cap));
|
||||
esSIvalue(esSpiceF, (double)dev->dev_cap);
|
||||
break;
|
||||
}
|
||||
plist = plist->parm_next;
|
||||
|
|
@ -2777,6 +2833,9 @@ spcdevVisit(
|
|||
subnode->efnode_name->efnn_hier,
|
||||
dev->dev_type, esSpiceF);
|
||||
}
|
||||
|
||||
/* CDL format support: Output a slash followed by a space. */
|
||||
if (esFormat == CDL) fprintf(esSpiceF, " /");
|
||||
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
|
||||
|
||||
/* Write all requested parameters to the subcircuit call. */
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ typedef struct {
|
|||
#define SPICE3 1
|
||||
#define HSPICE 2
|
||||
#define NGSPICE 3
|
||||
#define CDL 4
|
||||
|
||||
#define AUTO 2 /* TRUE | FALSE | AUTO for esDoSubckt */
|
||||
|
||||
|
|
|
|||
|
|
@ -1152,7 +1152,7 @@ ExtSortTerminals(tran, ll)
|
|||
* one terminal.
|
||||
*
|
||||
* Results:
|
||||
* None
|
||||
* TRUE if L and W were computed, FALSE if not.
|
||||
*
|
||||
* Side Effects:
|
||||
* Puts effective length and width into the pointers
|
||||
|
|
@ -1160,7 +1160,7 @@ ExtSortTerminals(tran, ll)
|
|||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bool
|
||||
extComputeCapLW(rlengthptr, rwidthptr)
|
||||
int *rlengthptr, *rwidthptr;
|
||||
{
|
||||
|
|
@ -1174,7 +1174,7 @@ extComputeCapLW(rlengthptr, rwidthptr)
|
|||
if (lb == NULL)
|
||||
{
|
||||
TxError("extract: Can't get capacitor L and W\n");
|
||||
return; /* error condition */
|
||||
return FALSE; /* error condition */
|
||||
}
|
||||
bbox = lb->r;
|
||||
for (lb = extSpecialBounds[0]; lb != NULL; lb = lb->b_next)
|
||||
|
|
@ -1182,6 +1182,7 @@ extComputeCapLW(rlengthptr, rwidthptr)
|
|||
|
||||
*rwidthptr = bbox.r_xtop - bbox.r_xbot;
|
||||
*rlengthptr = bbox.r_ytop - bbox.r_ybot;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1789,6 +1790,8 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
|
|||
int *perimvec;
|
||||
{
|
||||
ParamList *chkParam;
|
||||
HashEntry *he;
|
||||
ResValue resvalue;
|
||||
|
||||
for (chkParam = devptr->exts_deviceParams; chkParam
|
||||
!= NULL; chkParam = chkParam->pl_next)
|
||||
|
|
@ -1863,6 +1866,39 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
|
|||
(extTransRec.tr_devrec->exts_deviceSDCap
|
||||
* extTransRec.tr_perim));
|
||||
break;
|
||||
case 'r':
|
||||
/* If the device has an "area" resistance specified
|
||||
* by "devresist" in the tech file, use that. If
|
||||
* it has a "perimeter" resistance specified, use
|
||||
* that as well. If neither, then find the sheet
|
||||
* resistance of the device identifier layer and
|
||||
* use that.
|
||||
*/
|
||||
resvalue = (ResValue)0.0;
|
||||
he = HashLookOnly(&extTransRec.tr_devrec->exts_deviceResist, "area");
|
||||
if (he != NULL)
|
||||
{
|
||||
resvalue = (ResValue)(pointertype)HashGetValue(he);
|
||||
resvalue /= (ResValue)reg->treg_area;
|
||||
|
||||
he = HashLookOnly(&extTransRec.tr_devrec->exts_deviceResist,
|
||||
"perimeter");
|
||||
if (he != NULL)
|
||||
{
|
||||
ResValue perimr;
|
||||
perimr = (ResValue)(pointertype)HashGetValue(he);
|
||||
perimr /= (ResValue)extTransRec.tr_perim;
|
||||
resvalue += perimr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resvalue = ExtCurStyle->exts_sheetResist[reg->treg_type]
|
||||
* (double)length / (double)width;
|
||||
}
|
||||
|
||||
fprintf(outFile, " %c=%g", chkParam->pl_param[0], (float)resvalue);
|
||||
break;
|
||||
case 's':
|
||||
case 'x':
|
||||
case 'y':
|
||||
|
|
@ -2143,10 +2179,11 @@ extOutputDevices(def, transList, outFile)
|
|||
NodeRegion *node, *subsNode;
|
||||
TransRegion *reg;
|
||||
ExtDevice *devptr, *deventry;
|
||||
char *subsName;
|
||||
ParamList *chkParam;
|
||||
FindRegion arg;
|
||||
LabelList *ll;
|
||||
TileType t;
|
||||
char *subsName;
|
||||
int nsd, length, width, n, i, ntiles, corners, tn, rc, termcount;
|
||||
double dres, dcap;
|
||||
char mesg[256];
|
||||
|
|
@ -2668,7 +2705,70 @@ extOutputDevices(def, transList, outFile)
|
|||
case DEV_DIODE: /* Only handle the optional substrate node */
|
||||
case DEV_NDIODE:
|
||||
case DEV_PDIODE:
|
||||
/* Diode length and width are computed like capacitor */
|
||||
/* length and width. This operation is expensive, so */
|
||||
/* do this ONLY if length and width are specified as */
|
||||
/* parameters. */
|
||||
|
||||
devptr = extDevFindParamMatch(devptr, length, width);
|
||||
for (chkParam = devptr->exts_deviceParams; chkParam != NULL;
|
||||
chkParam = chkParam->pl_next)
|
||||
{
|
||||
char param0;
|
||||
|
||||
if (chkParam->pl_name == NULL) continue;
|
||||
param0 = tolower(chkParam->pl_param[0]);
|
||||
if (param0 == 'l' || param0 == 'w') break;
|
||||
}
|
||||
|
||||
if (chkParam != NULL)
|
||||
{
|
||||
for (n = 0; n < extTransRec.tr_nterm &&
|
||||
extTransRec.tr_termnode[n] != NULL; n++);
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
LinkedBoundary *lb;
|
||||
|
||||
extSpecialBounds = (LinkedBoundary **)mallocMagic(n *
|
||||
sizeof(LinkedBoundary *));
|
||||
|
||||
for (i = 0; i < n; i++) extSpecialBounds[i] = NULL;
|
||||
|
||||
/* Mark with reg and process each perimeter segment */
|
||||
|
||||
arg.fra_uninit = (ClientData) extTransRec.tr_gatenode;
|
||||
arg.fra_region = (ExtRegion *) reg;
|
||||
arg.fra_each = extAnnularTileFunc;
|
||||
(void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
|
||||
|
||||
if (extComputeCapLW(&length, &width) == FALSE)
|
||||
{
|
||||
/* May be a complex area; fall back on
|
||||
* computing an equivalent square area.
|
||||
*/
|
||||
length = (int)(sqrt((double)extTransRec.tr_termarea[0])
|
||||
+ 0.5);
|
||||
width = length;
|
||||
}
|
||||
|
||||
/* Free the lists */
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
for (lb = extSpecialBounds[i]; lb != NULL; lb = lb->b_next)
|
||||
freeMagic((char *)lb);
|
||||
freeMagic((char *)extSpecialBounds);
|
||||
|
||||
/* Put the region list back the way we found it: */
|
||||
/* Re-mark with extTransRec.tr_gatenode */
|
||||
|
||||
arg.fra_uninit = (ClientData) reg;
|
||||
arg.fra_region = (ExtRegion *) extTransRec.tr_gatenode;
|
||||
arg.fra_each = (int (*)()) NULL;
|
||||
(void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(outFile, "%s %s",
|
||||
extDevTable[(unsigned char)devptr->exts_deviceClass],
|
||||
devptr->exts_deviceName);
|
||||
|
|
@ -2885,7 +2985,15 @@ extOutputDevices(def, transList, outFile)
|
|||
arg.fra_each = extAnnularTileFunc;
|
||||
(void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
|
||||
|
||||
extComputeCapLW(&length, &width);
|
||||
if (extComputeCapLW(&length, &width) == FALSE)
|
||||
{
|
||||
/* May be a complex area; fall back on
|
||||
* computing an equivalent square area.
|
||||
*/
|
||||
length = (int)(sqrt((double)extTransRec.tr_termarea[0])
|
||||
+ 0.5);
|
||||
width = length;
|
||||
}
|
||||
|
||||
/* Free the lists */
|
||||
|
||||
|
|
@ -2907,7 +3015,7 @@ extOutputDevices(def, transList, outFile)
|
|||
{
|
||||
/* (Nothing) */
|
||||
}
|
||||
else /* SPICE semiconductor resistor */
|
||||
else /* SPICE semiconductor capacitor */
|
||||
{
|
||||
if ((length * width) > reg->treg_area)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ typedef enum
|
|||
AREAC, CONTACT, CSCALE,
|
||||
DEFAULTAREACAP, DEFAULTOVERLAP, DEFAULTPERIMETER, DEFAULTSIDEOVERLAP,
|
||||
DEFAULTSIDEWALL,
|
||||
DEVICE, FET, FETRESIST, FRINGESHIELDHALO,
|
||||
DEVICE, DEVRESIST, FET, FETRESIST, FRINGESHIELDHALO,
|
||||
HEIGHT, ANTENNA, MODEL, TIEDOWN, LAMBDA, OVERC,
|
||||
PERIMC, PLANEORDER, NOPLANEORDER, RESIST, RSCALE, SIDEHALO, SIDEOVERLAP,
|
||||
SIDEWALL, STEP, STYLE, SUBSTRATE, UNITS, VARIANT
|
||||
|
|
@ -122,7 +122,10 @@ static const keydesc keyTable[] = {
|
|||
"types plane capacitance [offset]"},
|
||||
|
||||
{"device", DEVICE, 4, 10,
|
||||
"device dev-type types options..."},
|
||||
"dev-type dev-name types options..."},
|
||||
|
||||
{"devresist", DEVRESIST, 4, 4,
|
||||
"type region ohms-per-square"},
|
||||
|
||||
{"fet", FET, 8, 9,
|
||||
"types terminal-types min-#-terminals name [subs-types] subs-node gscap gate-chan-cap"},
|
||||
|
|
@ -1958,7 +1961,6 @@ ExtTechLine(sectionName, argc, argv)
|
|||
char *subsName, *transName, *cp, *endptr, *paramName;
|
||||
TileType s, t, r, o;
|
||||
const keydesc *kp, *dv;
|
||||
bool isLinear;
|
||||
HashEntry *he;
|
||||
EdgeCap *cnew;
|
||||
ExtKeep *es, *newStyle;
|
||||
|
|
@ -2183,6 +2185,7 @@ ExtTechLine(sectionName, argc, argv)
|
|||
case CONTACT:
|
||||
case FET:
|
||||
case FETRESIST:
|
||||
case DEVRESIST:
|
||||
case HEIGHT:
|
||||
case ANTENNA:
|
||||
case TIEDOWN:
|
||||
|
|
@ -2545,11 +2548,17 @@ ExtTechLine(sectionName, argc, argv)
|
|||
argc--;
|
||||
}
|
||||
|
||||
class = dv->k_key;
|
||||
|
||||
/* Note: This check has been removed. Parameters for non- */
|
||||
/* subcircuit devices are allowed for support of CDL */
|
||||
/* netlists, which uses arbitrary subcircuit-like */
|
||||
/* parameters combined with a SPICE-like device prefix. */
|
||||
#if 0
|
||||
/* Check the number of arguments after splitting out */
|
||||
/* parameter entries. There is no limit on arguments in */
|
||||
/* DEV_SUBCKT, DEV_MSUBCKT, and DEV_VERILOGA. */
|
||||
|
||||
class = dv->k_key;
|
||||
switch (class)
|
||||
{
|
||||
case DEV_SUBCKT:
|
||||
|
|
@ -2575,6 +2584,7 @@ ExtTechLine(sectionName, argc, argv)
|
|||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
gscap = (CapValue) 0;
|
||||
gccap = (CapValue) 0;
|
||||
|
|
@ -2765,14 +2775,16 @@ ExtTechLine(sectionName, argc, argv)
|
|||
TTMaskSetMask(allExtractTypes, &termtypes[0]);
|
||||
termtypes[1] = DBZeroTypeBits;
|
||||
|
||||
if ((argc > 5) && strcmp(argv[5], "None"))
|
||||
if ((argc > 5) && strcmp(argv[5], "None") &&
|
||||
(strchr(argv[5], '=') == NULL))
|
||||
{
|
||||
DBTechNoisyNameMask(argv[5], &subsTypes); /* substrate */
|
||||
TTMaskSetMask(allExtractTypes, &subsTypes);
|
||||
}
|
||||
else
|
||||
subsTypes = DBZeroTypeBits;
|
||||
if (argc > 6) subsName = argv[6];
|
||||
if ((argc > 6) && (strchr(argv[6], '=') == NULL))
|
||||
subsName = argv[6];
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2812,7 +2824,6 @@ ExtTechLine(sectionName, argc, argv)
|
|||
}
|
||||
devptr->exts_deviceResist.ht_table = (HashEntry **) NULL;
|
||||
HashInit(&devptr->exts_deviceResist, 8, HT_STRINGKEYS);
|
||||
devptr->exts_linearResist = 0;
|
||||
|
||||
devptr->exts_next = ExtCurStyle->exts_device[t];
|
||||
ExtCurStyle->exts_device[t] = devptr;
|
||||
|
|
@ -2834,14 +2845,14 @@ ExtTechLine(sectionName, argc, argv)
|
|||
}
|
||||
break;
|
||||
|
||||
case DEVRESIST:
|
||||
case FETRESIST:
|
||||
if (!StrIsInt(argv[3]))
|
||||
if (!StrIsNumeric(argv[3]))
|
||||
{
|
||||
TechError("Fet resistivity %s must be numeric\n", argv[3]);
|
||||
TechError("Device resistivity %s must be numeric\n", argv[3]);
|
||||
break;
|
||||
}
|
||||
resVal = aToRes(argv[3]);
|
||||
isLinear = (strcmp(argv[2], "linear") == 0);
|
||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||
{
|
||||
ExtDevice *devptr;
|
||||
|
|
@ -2851,8 +2862,6 @@ ExtTechLine(sectionName, argc, argv)
|
|||
{
|
||||
he = HashFind(&devptr->exts_deviceResist, argv[2]);
|
||||
HashSetValue(he, (spointertype)resVal);
|
||||
if (isLinear)
|
||||
devptr->exts_linearResist = resVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3696,6 +3705,8 @@ zinit:
|
|||
for (devptr = style->exts_device[r]; devptr; devptr = devptr->exts_next)
|
||||
{
|
||||
ParamList *chkParam;
|
||||
HashEntry *he;
|
||||
ResValue res;
|
||||
|
||||
devptr->exts_deviceSDCap *= sqfac;
|
||||
devptr->exts_deviceGateCap *= sqfac;
|
||||
|
|
@ -3723,6 +3734,28 @@ zinit:
|
|||
chkParam->pl_minimum /= dscale;
|
||||
}
|
||||
}
|
||||
|
||||
he = HashLookOnly(&devptr->exts_deviceResist, "area");
|
||||
if (he != NULL)
|
||||
{
|
||||
res = (ResValue)(spointertype)(HashGetValue(he));
|
||||
res /= dsq;
|
||||
HashSetValue(he, (spointertype)res);
|
||||
}
|
||||
he = HashLookOnly(&devptr->exts_deviceResist, "perimeter");
|
||||
if (he != NULL)
|
||||
{
|
||||
res = (ResValue)(spointertype)(HashGetValue(he));
|
||||
res /= dscale;
|
||||
HashSetValue(he, (spointertype)res);
|
||||
}
|
||||
he = HashLookOnly(&devptr->exts_deviceResist, "linear");
|
||||
if (he != NULL)
|
||||
{
|
||||
res = (ResValue)(spointertype)(HashGetValue(he));
|
||||
res /= dscale;
|
||||
HashSetValue(he, (spointertype)res);
|
||||
}
|
||||
}
|
||||
|
||||
style->exts_areaCap[r] *= sqfac;
|
||||
|
|
|
|||
|
|
@ -506,7 +506,6 @@ typedef struct extDevice
|
|||
*/
|
||||
|
||||
HashTable exts_deviceResist;
|
||||
ResValue exts_linearResist;
|
||||
|
||||
/*
|
||||
* Mask of the types of tiles that connect to the channel terminals
|
||||
|
|
|
|||
|
|
@ -211,9 +211,14 @@ ResReadSim(simfile, fetproc, capproc, resproc, attrproc, mergeproc, subproc)
|
|||
{
|
||||
float sheetr;
|
||||
ExtDevice *devptr;
|
||||
HashEntry *he;
|
||||
|
||||
devptr = ExtCurStyle->exts_device[fettype];
|
||||
sheetr = (float)devptr->exts_linearResist;
|
||||
he = HashLookOnly(&devptr->exts_deviceResist, "linear");
|
||||
if (he != NULL)
|
||||
sheetr = (ResValue)(spointertype)HashGetValue(he);
|
||||
else
|
||||
sheetr = (ResValue)0.0;
|
||||
result = (*fetproc)(line, sheetr, devptr);
|
||||
}
|
||||
if (result != 0)
|
||||
|
|
@ -441,9 +446,14 @@ ResSimSubckt(line)
|
|||
|
||||
if (lptr != NULL && wptr != NULL)
|
||||
{
|
||||
HashEntry *he;
|
||||
float rpersquare;
|
||||
|
||||
rpersquare =(float)devptr->exts_linearResist;
|
||||
he = HashLookOnly(&devptr->exts_deviceResist, "linear");
|
||||
if (he != NULL)
|
||||
rpersquare = (ResValue)(spointertype)HashGetValue(he);
|
||||
else
|
||||
rpersquare = (ResValue)0.0;
|
||||
/* Subcircuit types may not have a length or width value, in which */
|
||||
/* case it is zero. Don't induce a divide-by-zero error. */
|
||||
if (MagAtof(wptr) == 0)
|
||||
|
|
|
|||
24
utils/tech.c
24
utils/tech.c
|
|
@ -66,7 +66,9 @@ global bool TechOverridesDefault;
|
|||
typedef struct FStack /* Linked FILE * pointers */
|
||||
{
|
||||
FILE *file;
|
||||
struct FStack *next; /* Pointer to another linked rectangle */
|
||||
char *filename; /* Keep file name of parent file */
|
||||
int linenum; /* Keep line number count at the include line */
|
||||
struct FStack *next; /* Pointer to another linked rectangle */
|
||||
} filestack;
|
||||
|
||||
int techLineNumber;
|
||||
|
|
@ -537,6 +539,8 @@ TechLoad(filename, initmask)
|
|||
}
|
||||
|
||||
topfile.file = tf;
|
||||
topfile.filename = NULL;
|
||||
topfile.linenum = 0;
|
||||
topfile.next = NULL;
|
||||
fstack = &topfile;
|
||||
|
||||
|
|
@ -602,15 +606,19 @@ TechLoad(filename, initmask)
|
|||
/* Check for file inclusions (can be nested) */
|
||||
if ((argc > 1) && (!strcmp(argv[0], "include")))
|
||||
{
|
||||
char *sptr;
|
||||
char *sptr, *increalname;
|
||||
|
||||
tf = PaOpen(argv[1], "r", suffix, ".", SysLibPath, NULL);
|
||||
tf = PaOpen(argv[1], "r", suffix, ".", SysLibPath, &increalname);
|
||||
if (tf != NULL)
|
||||
{
|
||||
newstack = (filestack *)mallocMagic(sizeof(filestack));
|
||||
newstack->file = tf;
|
||||
newstack->filename = TechFileName;
|
||||
newstack->linenum = techLineNumber;
|
||||
newstack->next = fstack;
|
||||
fstack = newstack;
|
||||
techLineNumber = 0;
|
||||
TechFileName = StrDup((char **)NULL, increalname);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -620,14 +628,18 @@ TechLoad(filename, initmask)
|
|||
if ((sptr = strrchr(TechFileName, '/')) != NULL)
|
||||
{
|
||||
*sptr = '\0';
|
||||
tf = PaOpen(argv[1], "r", suffix, TechFileName, NULL, NULL);
|
||||
tf = PaOpen(argv[1], "r", suffix, TechFileName, NULL, &increalname);
|
||||
*sptr = '/';
|
||||
if (tf != NULL)
|
||||
{
|
||||
newstack = (filestack *)mallocMagic(sizeof(filestack));
|
||||
newstack->file = tf;
|
||||
newstack->filename = TechFileName;
|
||||
newstack->linenum = techLineNumber;
|
||||
newstack->next = fstack;
|
||||
fstack = newstack;
|
||||
techLineNumber = 0;
|
||||
TechFileName = StrDup((char **)NULL, increalname);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -747,6 +759,7 @@ skipsection:
|
|||
while ((fstack != NULL) && (fstack != &topfile))
|
||||
{
|
||||
fclose(fstack->file);
|
||||
freeMagic(fstack->filename);
|
||||
freeMagic(fstack);
|
||||
fstack = fstack->next;
|
||||
}
|
||||
|
|
@ -968,6 +981,9 @@ start:
|
|||
if ((*fstack)->next != NULL)
|
||||
{
|
||||
fclose((*fstack)->file);
|
||||
freeMagic(TechFileName);
|
||||
TechFileName = (*fstack)->filename;
|
||||
techLineNumber = (*fstack)->linenum;
|
||||
*fstack = (*fstack)->next;
|
||||
file = (*fstack)->file;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue