mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-22 14:17:43 +02:00
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:
+114
-6
@@ -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)
|
||||
{
|
||||
|
||||
+45
-12
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user