From 78f7d227966a9118096ad0a95c96788526bfa979 Mon Sep 17 00:00:00 2001 From: "R. Timothy Edwards" Date: Wed, 1 Oct 2025 15:17:49 -0400 Subject: [PATCH] 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. --- VERSION | 2 +- calma/CalmaRdcl.c | 46 +++++++++++++++- database/database.h.in | 16 +++--- ext2spice/ext2hier.c | 6 ++- ext2spice/ext2spice.c | 79 +++++++++++++++++++++++---- ext2spice/ext2spice.h | 1 + extract/ExtBasic.c | 120 ++++++++++++++++++++++++++++++++++++++--- extract/ExtTech.c | 57 +++++++++++++++----- extract/extractInt.h | 1 - resis/ResReadSim.c | 14 ++++- utils/tech.c | 24 +++++++-- 11 files changed, 321 insertions(+), 45 deletions(-) diff --git a/VERSION b/VERSION index df4da1ab..9bbbb99b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.554 +8.3.555 diff --git a/calma/CalmaRdcl.c b/calma/CalmaRdcl.c index 59531c39..06a66590 100644 --- a/calma/CalmaRdcl.c +++ b/calma/CalmaRdcl.c @@ -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) diff --git a/database/database.h.in b/database/database.h.in index 2496263b..96da5cf3 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -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 */ diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index 093ef71d..8d8a7e7e 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -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. */ diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index a32320e5..b5646af7 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -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. */ diff --git a/ext2spice/ext2spice.h b/ext2spice/ext2spice.h index 8eaba2f2..2284bfee 100644 --- a/ext2spice/ext2spice.h +++ b/ext2spice/ext2spice.h @@ -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 */ diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 24ab6f63..3458552d 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -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) { diff --git a/extract/ExtTech.c b/extract/ExtTech.c index bdb512a6..60a906d0 100644 --- a/extract/ExtTech.c +++ b/extract/ExtTech.c @@ -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; diff --git a/extract/extractInt.h b/extract/extractInt.h index 33f2396a..ff4711b7 100644 --- a/extract/extractInt.h +++ b/extract/extractInt.h @@ -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 diff --git a/resis/ResReadSim.c b/resis/ResReadSim.c index 2f61dc88..aabafb04 100644 --- a/resis/ResReadSim.c +++ b/resis/ResReadSim.c @@ -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) diff --git a/utils/tech.c b/utils/tech.c index 9603c368..5b3ce861 100644 --- a/utils/tech.c +++ b/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; }