diff --git a/VERSION b/VERSION index 3411c173..a42b25a5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.410 +8.3.411 diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index a1b4fa57..c85b2d04 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -89,8 +89,9 @@ typedef struct /* Position of each terminal (below) tile position */ /* Field definitions for tr_devmatch */ #define MATCH_ID 0x01 /* Device matches identifier in devrec */ -#define MATCH_SUB 0x02 /* Device matches substrate type in devrec */ -#define MATCH_TERM 0x04 /* Device matches terminal in devrec */ +#define MATCH_PARAM 0x02 /* Device is compatible with parameter range */ +#define MATCH_SUB 0x04 /* Device matches substrate type in devrec */ +#define MATCH_TERM 0x08 /* Device matches terminal in devrec */ /* (additional fields: bit shifts up by 1 for each defined device terminal) */ struct transRec @@ -1647,16 +1648,30 @@ extOutputParameters(def, transList, outFile) for (devptr = ExtCurStyle->exts_device[t]; devptr; devptr = devptr->exts_next) { + bool has_output = FALSE; + /* Do not output parameters for ignored devices */ if (!strcmp(devptr->exts_deviceName, "Ignore")) continue; + /* Do a quick first pass to determine if there is anything + * to output (only entries with non-NULL pl_name get output). + */ plist = devptr->exts_deviceParams; - if (plist != (ParamList *)NULL) + for (; plist != NULL; plist = plist->pl_next) + if (plist->pl_name != NULL) + { + has_output = TRUE; + break; + } + + if (has_output) { fprintf(outFile, "parameters %s", devptr->exts_deviceName); + plist = devptr->exts_deviceParams; for (; plist != NULL; plist = plist->pl_next) { - if (plist->pl_param[1] != '\0') + if (plist->pl_name == NULL) continue; + else if (plist->pl_param[1] != '\0') { if (plist->pl_scale != 1.0) fprintf(outFile, " %c%c=%s*%g", @@ -1725,6 +1740,7 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec) for (chkParam = devptr->exts_deviceParams; chkParam != NULL; chkParam = chkParam->pl_next) { + if (chkParam->pl_name == NULL) continue; switch(tolower(chkParam->pl_param[0])) { case 'a': @@ -1796,6 +1812,161 @@ typedef struct _extareaperimdata { ExtNodeList *eapd_shared; } ExtAreaPerimData; +/* + * ---------------------------------------------------------------------------- + * + * extDevFindParamMatch -- + * + * Routine which checks parameter values of a device against parameter + * ranges specified for the device model. If the parameters of the + * current device do not match the ranges, then another device record + * with matching parameters will be sought, and returned if found. + * If no device with matching parameters is found, then the original + * device record is returned, and a warning about parameter mismatch + * is printed. + * + * When looking for alternate parameter ranges, all other parameter + * record values must be the same as the current one. A record with + * no range (min > max) always matches. + * + * Return value: + * Pointer to a device record. + * + * ---------------------------------------------------------------------------- + */ + +ExtDevice * +extDevFindParamMatch(devptr, length, width) + ExtDevice *devptr; + int length; /* Computed effective length of device */ + int width; /* Computed effective width of device */ +{ + ExtDevice *newdevptr, *nextdev; + int i; + + while (TRUE) + { + ParamList *chkParam; + bool out_of_bounds = FALSE; + + newdevptr = devptr; + nextdev = devptr->exts_next; + + for (chkParam = devptr->exts_deviceParams; chkParam != NULL; + chkParam = chkParam->pl_next) + { + if (chkParam->pl_minimum > chkParam->pl_maximum) continue; + + switch (tolower(chkParam->pl_param[0])) + { + case 'a': + if (chkParam->pl_param[1] == '\0' || + chkParam->pl_param[1] == '0') + { + int area = length * width; + if (area < chkParam->pl_minimum) out_of_bounds = TRUE; + if (area > chkParam->pl_maximum) out_of_bounds = TRUE; + } + else + { + int tidx = chkParam->pl_param[1] - '1'; + int area = extTransRec.tr_termarea[tidx]; + if (area < chkParam->pl_minimum) out_of_bounds = TRUE; + if (area > chkParam->pl_maximum) out_of_bounds = TRUE; + } + break; + case 'p': + if (chkParam->pl_param[1] == '\0' || + chkParam->pl_param[1] == '0') + { + int perim = 2 * (length + width); + if (perim < chkParam->pl_minimum) out_of_bounds = TRUE; + if (perim > chkParam->pl_maximum) out_of_bounds = TRUE; + } + else + { + int tidx = chkParam->pl_param[1] - '1'; + int perim = extTransRec.tr_termperim[tidx]; + if (perim < chkParam->pl_minimum) out_of_bounds = TRUE; + if (perim > chkParam->pl_maximum) out_of_bounds = TRUE; + } + break; + case 'l': + if (chkParam->pl_param[1] == '\0' || + chkParam->pl_param[1] == '0') + { + if (length < chkParam->pl_minimum) out_of_bounds = TRUE; + if (length > chkParam->pl_maximum) out_of_bounds = TRUE; + } + else if (chkParam->pl_param[1] > '0' && chkParam->pl_param[1] <= '9') + { + int tidx = chkParam->pl_param[1] - '1'; + int len = extTransRec.tr_termlen[tidx]; + if (len < chkParam->pl_minimum) out_of_bounds = TRUE; + if (len > chkParam->pl_maximum) out_of_bounds = TRUE; + } + break; + case 'w': + if (width < chkParam->pl_minimum) out_of_bounds = TRUE; + if (width > chkParam->pl_maximum) out_of_bounds = TRUE; + break; + default: + /* Do nothing; these parameters cannot be used for + * differentiating device models. + */ + break; + } + if (out_of_bounds) break; + } + if (chkParam == NULL) break; + + /* Check that the next device record is compatible in all values + * except for parameters and name. + */ + if (nextdev != NULL) + { + if (nextdev->exts_deviceClass != devptr->exts_deviceClass) + nextdev = NULL; + else if (nextdev->exts_deviceSDCount != devptr->exts_deviceSDCount) + nextdev = NULL; + } + + if (nextdev != NULL) + { + for (i = 0; i < nextdev->exts_deviceSDCount; i++) + { + if (!TTMaskEqual(&nextdev->exts_deviceSDTypes[i], + &devptr->exts_deviceSDTypes[i])) + { + nextdev = NULL; + break; + } + } + } + + if (nextdev != NULL) + if (!TTMaskEqual(&nextdev->exts_deviceSubstrateTypes, + &devptr->exts_deviceSubstrateTypes)) + nextdev = NULL; + + if (nextdev != NULL) + if (!TTMaskEqual(&nextdev->exts_deviceIdentifierTypes, + &devptr->exts_deviceIdentifierTypes)) + nextdev = NULL; + + if (nextdev == NULL) + { + newdevptr = devptr; /* Return to original entry */ + TxError("Device parameters do not match any extraction model.\n"); + break; + } + else + devptr = nextdev; + } + + return newdevptr; +} + /* * ---------------------------------------------------------------------------- * @@ -2032,7 +2203,7 @@ extOutputDevices(def, transList, outFile) else { DBSrPaintArea((Tile *)NULL, def->cd_planes[DBPlane(tt)], - &r, &tmask, extTransFindTermArea, (ClientData)&eapd); + &r, tmask, extTransFindTermArea, (ClientData)&eapd); extTransRec.tr_termarea[termcount] = eapd.eapd_area; extTransRec.tr_termperim[termcount] = eapd.eapd_perim; } @@ -2173,27 +2344,23 @@ extOutputDevices(def, transList, outFile) if (devptr->exts_deviceClass != DEV_FET) fprintf(outFile, "device "); - fprintf(outFile, "%s %s", - extDevTable[devptr->exts_deviceClass], - devptr->exts_deviceName); - - fprintf(outFile, " %d %d %d %d", - reg->treg_ll.p_x, reg->treg_ll.p_y, - reg->treg_ll.p_x + 1, reg->treg_ll.p_y + 1); - - /* NOTE: The following code makes unreasonable simplifying */ - /* assumptions about how to calculate device length and width. */ - /* However, it is the same as was always used by ext2sim and */ - /* ext2spice. By putting it here, where all the tile */ - /* information exists, it is at least theoretically possible to */ - /* write better routines that can deal with bends in resistors */ - /* and transistors, annular devices, multiple-drain devices, */ - /* etc., etc. */ - /* Tim, 2/20/03 */ + /* NOTE: The code for the old FET device makes unreasonable */ + /* simplifying assumptions about how to calculate device length */ + /* and width. The newer MOSFET and MSUBCKT and other devices */ + /* compute proper length and width, including but not limited */ + /* to dealing with bends and annular shapes. */ switch (devptr->exts_deviceClass) { case DEV_FET: /* old style, perimeter & area */ + fprintf(outFile, "%s %s", + extDevTable[devptr->exts_deviceClass], + devptr->exts_deviceName); + + fprintf(outFile, " %d %d %d %d", + reg->treg_ll.p_x, reg->treg_ll.p_y, + reg->treg_ll.p_x + 1, reg->treg_ll.p_y + 1); + fprintf(outFile, " %d %d \"%s\"", reg->treg_area, extTransRec.tr_perim, (subsName == NULL) ? "None" : subsName); @@ -2320,6 +2487,15 @@ extOutputDevices(def, transList, outFile) } + devptr = extDevFindParamMatch(devptr, length, width); + fprintf(outFile, "%s %s", + extDevTable[devptr->exts_deviceClass], + devptr->exts_deviceName); + + fprintf(outFile, " %d %d %d %d", + reg->treg_ll.p_x, reg->treg_ll.p_y, + reg->treg_ll.p_x + 1, reg->treg_ll.p_y + 1); + if (devptr->exts_deviceClass == DEV_MOSFET || devptr->exts_deviceClass == DEV_ASYMMETRIC || devptr->exts_deviceClass == DEV_BJT) @@ -2337,6 +2513,15 @@ extOutputDevices(def, transList, outFile) case DEV_DIODE: /* Only handle the optional substrate node */ case DEV_NDIODE: case DEV_PDIODE: + devptr = extDevFindParamMatch(devptr, length, width); + fprintf(outFile, "%s %s", + extDevTable[devptr->exts_deviceClass], + devptr->exts_deviceName); + + fprintf(outFile, " %d %d %d %d", + reg->treg_ll.p_x, reg->treg_ll.p_y, + reg->treg_ll.p_x + 1, reg->treg_ll.p_y + 1); + extOutputDevParams(reg, devptr, outFile, length, width, extTransRec.tr_termarea); if (subsName != NULL) @@ -2452,6 +2637,16 @@ extOutputDevices(def, transList, outFile) "Resistor has zero width"); } + devptr = extDevFindParamMatch(devptr, length, width); + + fprintf(outFile, "%s %s", + extDevTable[devptr->exts_deviceClass], + devptr->exts_deviceName); + + fprintf(outFile, " %d %d %d %d", + reg->treg_ll.p_x, reg->treg_ll.p_y, + reg->treg_ll.p_x + 1, reg->treg_ll.p_y + 1); + if (devptr->exts_deviceClass == DEV_RSUBCKT) { /* (Nothing) */ @@ -2478,6 +2673,14 @@ extOutputDevices(def, transList, outFile) case DEV_CAP: case DEV_CAPREV: case DEV_CSUBCKT: + fprintf(outFile, "%s %s", + extDevTable[devptr->exts_deviceClass], + devptr->exts_deviceName); + + fprintf(outFile, " %d %d %d %d", + reg->treg_ll.p_x, reg->treg_ll.p_y, + reg->treg_ll.p_x + 1, reg->treg_ll.p_y + 1); + hasModel = strcmp(devptr->exts_deviceName, "None"); if (hasModel) { @@ -2781,6 +2984,10 @@ extDevFindMatch(deventry, t) if (!TTMaskEqual(&devptr->exts_deviceSubstrateTypes, &deventry->exts_deviceSubstrateTypes)) continue; + if (matchflags & MATCH_PARAM) /* Must have compatible parameter range */ + /* To be completed */ + ; + j = MATCH_TERM; i = 0; match = TRUE; diff --git a/extract/ExtTech.c b/extract/ExtTech.c index 7af7c2e6..217db7d9 100644 --- a/extract/ExtTech.c +++ b/extract/ExtTech.c @@ -888,7 +888,8 @@ extTechStyleInit(style) } else { - freeMagic(devptr->exts_deviceParams->pl_name); + if (devptr->exts_deviceParams->pl_name != NULL) + freeMagic(devptr->exts_deviceParams->pl_name); freeMagic(devptr->exts_deviceParams); devptr->exts_deviceParams = devptr->exts_deviceParams->pl_next; } @@ -2366,11 +2367,19 @@ ExtTechLine(sectionName, argc, argv) { char *mult, *offset; + /* Ignore ">=" and "<=", which are handled below */ + if (paramName > argv[argc - 1]) + if ((*(paramName - 1) == '>') || (*(paramName - 1) == '<')) + break; + paramName++; newParam = (ParamList *)mallocMagic(sizeof(ParamList)); newParam->pl_count = 0; newParam->pl_param[0] = *argv[argc - 1]; newParam->pl_param[1] = '\0'; + newParam->pl_maximum = -1; + newParam->pl_minimum = 0; + newParam->pl_offset = 0.0; if (paramName - argv[argc - 1] == 3) newParam->pl_param[1] = *(argv[argc - 1] + 1); @@ -2421,6 +2430,102 @@ ExtTechLine(sectionName, argc, argv) argc--; } + /* Check for parameter range limits in one of these forms: */ + /* x>y, x=y, x<=y. */ + + while (TRUE) + { + ParamList *chkParam; + char *limitstr; + char cond; + bool equal = FALSE; + double dval; + int ival; + + limitstr = strchr(argv[argc - 1], '<'); + if (limitstr == NULL) + limitstr = strchr(argv[argc - 1], '>'); + if (limitstr == NULL) break; + + cond = *limitstr; + *limitstr = '\0'; + + /* If the parameter exists, then modify its min/max values. + * If not, then create a parameter and fill in only the + * min/max values. + */ + + if (limitstr - argv[argc - 1] > 3) + { + TechError("Parameter name %s can be no more than" + "two characters.\n", argv[argc - 1]); + break; + } + + for (chkParam = subcktParams; chkParam; chkParam = + chkParam->pl_next) + if ((chkParam->pl_param[0] == argv[argc - 1][0]) && + (chkParam->pl_param[1] == argv[argc - 1][1])) + break; + + /* If there is no defined parameter with the given name + * to be output, then create the parameter for checking + * limits only. + */ + + if (chkParam == NULL) + { + newParam = (ParamList *)mallocMagic(sizeof(ParamList)); + newParam->pl_count = 0; + newParam->pl_param[0] = argv[argc - 1][0]; + newParam->pl_param[1] = argv[argc - 1][1]; + newParam->pl_maximum = -1; + newParam->pl_minimum = 0; + newParam->pl_name = NULL; + newParam->pl_scale = 1.0; + newParam->pl_offset = 0.0; + + newParam->pl_next = subcktParams; + subcktParams = newParam; + chkParam = newParam; + } + + /* Change limit */ + + limitstr++; + if (*limitstr == '=') + { + equal = TRUE; + limitstr++; + } + if (sscanf(limitstr, "%lg", &dval) == 0) + { + TxError("Non-numeric limit \"%s\" for parameter \"%c%s\".\n", + limitstr, cond, argv[argc - 1]); + break; + } + + /* Convert dval to internal (integer) units. Scale up by */ + /* 1000 so the value can be converted if it's in microns */ + /* without losing precision. */ + ival = (int)(0.5 + (dval * 1000)); + + /* Make adjustment for greater than or less than */ + if (cond == '>') + { + if (!equal) ival++; + chkParam->pl_minimum = ival; + } + else + { + if (!equal) ival--; + chkParam->pl_maximum = ival; + } + + /* Move to next argument */ + argc--; + } + /* If the last entry before any parameters starts with '+', */ /* then use it to set the identity marker. Otherwise, the */ /* identity marker is NULL. */ @@ -2453,7 +2558,8 @@ ExtTechLine(sectionName, argc, argv) { while (subcktParams != NULL) { - freeMagic(subcktParams->pl_name); + if (subcktParams->pl_name != NULL) + freeMagic(subcktParams->pl_name); freeMagic(subcktParams); subcktParams = subcktParams->pl_next; } @@ -3578,9 +3684,27 @@ zinit: ExtDevice *devptr; for (devptr = style->exts_device[r]; devptr; devptr = devptr->exts_next) - { + { + ParamList *chkParam; + devptr->exts_deviceSDCap *= sqfac; devptr->exts_deviceGateCap *= sqfac; + + for (chkParam = devptr->exts_deviceParams; chkParam; + chkParam = chkParam->pl_next) + { + if (chkParam->pl_minimum > chkParam->pl_maximum) continue; + else if (chkParam->pl_param[0] == 'a') + { + chkParam->pl_maximum /= dsq; + chkParam->pl_minimum /= dsq; + } + else + { + chkParam->pl_maximum /= dscale; + chkParam->pl_minimum /= dscale; + } + } } style->exts_areaCap[r] *= sqfac; @@ -3645,6 +3769,24 @@ zinit: /* needed, so normalize it back to lambda units. */ style->exts_sideCoupleHalo /= 1000; + + /* Ditto for the parameter maximum/minimum limits */ + for (r = 0; r < DBNumTypes; r++) + { + ExtDevice *devptr; + ParamList *chkParam; + + for (devptr = style->exts_device[r]; devptr; devptr = devptr->exts_next) + { + for (chkParam = devptr->exts_deviceParams; chkParam; + chkParam = chkParam->pl_next) + { + if (chkParam->pl_minimum > chkParam->pl_maximum) continue; + chkParam->pl_maximum /= 1000; + chkParam->pl_minimum /= 1000; + } + } + } } /* @@ -3678,6 +3820,7 @@ ExtTechScale(scalen, scaled) for (i = 0; i < DBNumTypes; i++) { ExtDevice *devptr; + ParamList *chkParam; style->exts_areaCap[i] *= sqn; style->exts_areaCap[i] /= sqd; @@ -3688,6 +3831,26 @@ ExtTechScale(scalen, scaled) devptr->exts_deviceSDCap /= sqd; devptr->exts_deviceGateCap *= sqn; devptr->exts_deviceGateCap /= sqd; + + for (chkParam = devptr->exts_deviceParams; chkParam; + chkParam = chkParam->pl_next) + { + if (chkParam->pl_minimum > chkParam->pl_maximum) continue; + else if (chkParam->pl_param[0] == 'a') + { + chkParam->pl_maximum *= sqd; + chkParam->pl_maximum /= sqn; + chkParam->pl_minimum *= sqd; + chkParam->pl_minimum /= sqn; + } + else + { + chkParam->pl_maximum *= scaled; + chkParam->pl_maximum /= scalen; + chkParam->pl_minimum *= scaled; + chkParam->pl_minimum /= scalen; + } + } } style->exts_height[i] *= scaled; diff --git a/extract/extractInt.h b/extract/extractInt.h index 840de0e6..45293692 100644 --- a/extract/extractInt.h +++ b/extract/extractInt.h @@ -79,6 +79,8 @@ typedef struct pl char *pl_name; /* Full name for parameter */ double pl_scale; /* Scaling of parameter, if specified */ double pl_offset; /* Offset of parameter, if specified */ + int pl_maximum; /* Maximum value for this device model */ + int pl_minimum; /* Minimum value for this device model */ struct pl *pl_next; /* Next parameter in list */ } ParamList;