From 77e8ff437b58942fa680791eae39d6f3205c8751 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 20 Oct 2019 22:12:02 -0400 Subject: [PATCH] Finished first cut at an implementation of antenna rule violation checks. Added new command "antennacheck" and a routine that adds feedback entries where violations are found. Extended the syntax of the extraction section of the techfile to support the antenna ratios and antenna calculation methods. --- extflat/Depend | 10 +- extflat/EFantenna.c | 452 ++++++++++++++++++++++++++++++++++++++----- extract/ExtTech.c | 83 +++++++- extract/extract.h | 1 + extract/extractInt.h | 16 +- 5 files changed, 498 insertions(+), 64 deletions(-) diff --git a/extflat/Depend b/extflat/Depend index c2c89681..f4e40584 100644 --- a/extflat/Depend +++ b/extflat/Depend @@ -29,8 +29,8 @@ EFvisit.o: EFvisit.c ../utils/magic.h ../utils/geometry.h \ ../utils/geofast.h ../utils/hash.h ../utils/malloc.h ../utils/utils.h \ ../extflat/extflat.h ../extflat/EFint.h ../extract/extract.h EFantenna.o: EFantenna.c ../tcltk/tclmagic.h ../utils/magic.h \ - ../utils/geometry.h ../utils/hash.h ../utils/utils.h ../tiles/tile.h \ - ../database/database.h ../windows/windows.h ../textio/textio.h \ - ../dbwind/dbwind.h ../textio/txcommands.h ../extflat/extflat.h \ - ../extract/extract.h ../extract/extractInt.h ../extract/extDebugInt.h \ - ../utils/malloc.h + ../utils/geometry.h ../utils/hash.h ../utils/utils.h ../utils/styles.h \ + ../tiles/tile.h ../database/database.h ../windows/windows.h \ + ../textio/textio.h ../dbwind/dbwind.h ../textio/txcommands.h \ + ../extflat/extflat.h ../extract/extract.h ../extract/extractInt.h \ + ../extract/extDebugInt.h ../utils/malloc.h diff --git a/extflat/EFantenna.c b/extflat/EFantenna.c index 4bbbd1c4..470edfe8 100644 --- a/extflat/EFantenna.c +++ b/extflat/EFantenna.c @@ -14,18 +14,20 @@ #include /* for atof() */ #include #include +#include /* for INFINITY */ #include "tcltk/tclmagic.h" #include "utils/magic.h" #include "utils/geometry.h" #include "utils/hash.h" #include "utils/utils.h" +#include "utils/styles.h" #include "tiles/tile.h" #ifdef MAGIC_WRAPPER #include "database/database.h" #include "windows/windows.h" #include "textio/textio.h" -#include "dbwind/dbwind.h" /* for DBWclientID */ +#include "dbwind/dbwind.h" #include "textio/txcommands.h" #endif #include "extflat/extflat.h" @@ -70,6 +72,34 @@ typedef struct { ((nodeClientHier *) (node)->efnode_client)->visitMask = (long) 0; \ } +/* Diagnostic */ +int efGates; +static int efAntennaDebug = FALSE; + +/* The extract file is designed to be independent of the magic database, */ +/* but that means that the device types do not match magic database types. */ +/* A lookup table is needed to cross-reference the device types. */ + +TileType *EFDeviceTypes; + +typedef struct _aas { + int *accum; /* Pointer to array of accumulated areas per type */ + int pNum; /* Plane of check */ + Rect r; /* Holds any one visited rectangle */ + CellDef *def; /* CellDef for adding feedback */ +} AntennaAccumStruct; + +typedef struct _gdas { + int accum; /* Accumulated area of all gates/diff */ + Rect r; /* Holds any one visited rectangle */ + CellDef *def; /* CellDef for adding feedback */ +} GateDiffAccumStruct; + +typedef struct _ams { + int pNum; /* Plane of check */ + CellDef *def; /* CellDef for adding feedback */ +} AntennaMarkStruct; + /* * ---------------------------------------------------------------------------- @@ -80,16 +110,18 @@ typedef struct { */ #define ANTENNACHECK_RUN 0 -#define ANTENNACHECK_HELP 1 +#define ANTENNACHECK_DEBUG 1 +#define ANTENNACHECK_HELP 2 void CmdAntennaCheck(w, cmd) MagWindow *w; TxCommand *cmd; { - int i,flatFlags; + int i, flatFlags; char *inName; FILE *f; + TileType t; int option = ANTENNACHECK_RUN; int value; @@ -109,6 +141,7 @@ CmdAntennaCheck(w, cmd) static char *cmdAntennaCheckOption[] = { "[run] [options] run antennacheck on current cell\n" " use \"run -help\" to get standard options", + "debug print detailed information about each error", "help print help information", NULL }; @@ -125,6 +158,9 @@ CmdAntennaCheck(w, cmd) case ANTENNACHECK_RUN: goto runantennacheck; break; + case ANTENNACHECK_DEBUG: + efAntennaDebug = TRUE; + break; case ANTENNACHECK_HELP: usage: for (msg = &(cmdAntennaCheckOption[0]); *msg != NULL; msg++) @@ -179,6 +215,7 @@ runantennacheck: */ /* Read the hierarchical description of the input circuit */ + TxPrintf("Reading extract file.\n"); if (EFReadFile(inName, FALSE, FALSE, FALSE) == FALSE) { EFDone(); @@ -187,13 +224,24 @@ runantennacheck: /* Convert the hierarchical description to a flat one */ flatFlags = EF_FLATNODES; + TxPrintf("Building flattened netlist.\n"); EFFlatBuild(inName, flatFlags); + /* Build device lookup table */ + EFDeviceTypes = (TileType *)mallocMagic(MAXDEVTYPES * sizeof(TileType)); + for (i = 0; i < MAXDEVTYPES; i++) + if (EFDevTypes[i]) + EFDeviceTypes[i] = extGetDevType(EFDevTypes[i]); + + efGates = 0; + TxPrintf("Running antenna checks.\n"); EFVisitDevs(antennacheckVisit, (ClientData)editUse); EFFlatDone(); EFDone(); TxPrintf("antennacheck finished.\n"); + freeMagic(EFDeviceTypes); + efAntennaDebug = FALSE; } @@ -296,28 +344,30 @@ antennacheckVisit(dev, hierName, scale, trans, editUse) CellUse *editUse; /* ClientData is edit cell use */ { DevTerm *gate; + TileType t, conType; int pos, pNum, pNum2, pmax, p, i, j, gatearea, diffarea, total; - double difftotal; + double anttotal; + float saveRatio; int *antennaarea; - Rect r; + Rect r, gaterect; EFNode *gnode; SearchContext scx; - TileTypeBitMask gatemask; + TileTypeBitMask gatemask, saveConMask; + bool antennaError; extern CellDef *extPathDef; /* see extract/ExtLength.c */ extern CellUse *extPathUse; /* see extract/ExtLength.c */ - extern int areaAccumFunc(), antennaAccumFunc(); + extern int areaAccumFunc(), antennaAccumFunc(), areaMarkFunc(); antennaarea = (int *)mallocMagic(DBNumTypes * sizeof(int)); - for (i = 0; i < DBNumTypes; i++) antennaarea[i] = 0; - switch(dev->dev_class) { case DEV_FET: case DEV_MOSFET: - GeoTransRect(trans, &dev->dev_rect, &r); + case DEV_MSUBCKT: + case DEV_ASYMMETRIC: /* Procedure: * @@ -336,16 +386,23 @@ antennacheckVisit(dev, hierName, scale, trans, editUse) * layer being searched. */ + GeoTransRect(trans, &dev->dev_rect, &r); gate = &dev->dev_terms[0]; - gnode = AntennaGetNode(hierName, gate->dterm_node->efnode_name->efnn_hier); + if (gnode->efnode_client == (ClientData) NULL) + initNodeClient(gnode); if (beenVisited((nodeClient *)gnode->efnode_client, 0)) return 0; else markVisited((nodeClient *)gnode->efnode_client, 0); + /* Diagnostic stuff */ + efGates++; + if (efGates % 100 == 0) TxPrintf(" %d gates analyzed.\n", efGates); + /* Find the plane of the gate type */ - pNum = DBPlane(dev->dev_type); + t = EFDeviceTypes[dev->dev_type]; + pNum = DBPlane(t); pos = ExtCurStyle->exts_planeOrder[pNum]; pmax = ++pos; @@ -354,10 +411,15 @@ antennacheckVisit(dev, hierName, scale, trans, editUse) if (ExtCurStyle->exts_planeOrder[p] > pmax) pmax = ExtCurStyle->exts_planeOrder[p]; + /* Create the yank cell if it doesn't already exist */ + if (extPathDef == (CellDef *) NULL) + DBNewYank("__PATHYANK__", &extPathUse, &extPathDef); + /* Use the cellDef reserved for extraction */ - DBCellClearDef(extPathDef); + /* DBCellClearDef(extPathDef); */ /* See below */ scx.scx_use = editUse; scx.scx_trans = GeoIdentityTransform; + scx.scx_area = r; /* gatemask is a mask of all gate types for MOSFET devices */ @@ -387,53 +449,203 @@ antennacheckVisit(dev, hierName, scale, trans, editUse) for (; pos <= pmax; pos++) { + GateDiffAccumStruct gdas; + AntennaAccumStruct aas; + AntennaMarkStruct ams; + + /* Find the plane of pos */ + + for (p = 0; p < DBNumPlanes; p++) + if (ExtCurStyle->exts_planeOrder[p] == pos) + pNum2 = p; + + /* Find the tiletype which is a contact and whose base is pNum2 */ + /* (NOTE: Need to extend to all such contacts, as there may be */ + /* more than one.) (Also should find these types up top, not */ + /* within the loop.) */ + /* Modify DBConnectTbl to limit connectivity to the plane */ /* of the antenna check and below */ - /* To be completed */ + conType = -1; + for (i = 0; i < DBNumTypes; i++) + if (DBIsContact(i) && DBPlane(i) == pNum2) + { + conType = i; + TTMaskZero(&saveConMask); + TTMaskSetMask(&saveConMask, &DBConnectTbl[i]); + TTMaskZero(&DBConnectTbl[i]); + for (j = 0; j < DBNumTypes; j++) + if (TTMaskHasType(&saveConMask, j) && + (DBPlane(j) <= pNum2)) + TTMaskSetType(&DBConnectTbl[i], j); + break; + } - DBTreeCopyConnect(&scx, &DBConnectTbl[dev->dev_type], 0, + for (i = 0; i < DBNumTypes; i++) antennaarea[i] = 0; + gatearea = 0; + diffarea = 0; + + /* Note: Ideally, the addition of material in the next */ + /* metal plane is additive. But that requires enumerating */ + /* all the vias and using those as starting points for the */ + /* next connectivity search, which needs to be coded. */ + + DBCellClearDef(extPathDef); + + /* To do: Mark tiles so area count can be progressive */ + + DBTreeCopyConnect(&scx, &DBConnectTbl[t], 0, DBConnectTbl, &TiPlaneRect, extPathUse); - /* Search plane of gate type and accumulate all (new) gate area */ - DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum], - &TiPlaneRect, &gatemask, areaAccumFunc, (ClientData)&gatearea); - - /* Search planes of tie type and accumulate all (new) tiedown areas */ + /* Search planes of tie types and accumulate all tiedown areas */ + gdas.accum = 0; for (p = 0; p < DBNumPlanes; p++) DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p], &TiPlaneRect, &ExtCurStyle->exts_antennaTieTypes, - areaAccumFunc, (ClientData)&diffarea); + areaAccumFunc, (ClientData)&gdas); + diffarea = gdas.accum; - /* Search metal planes and accumulate all (new) antenna areas */ + /* Search plane of gate type and accumulate all gate area */ + gdas.accum = 0; + DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum], + &TiPlaneRect, &gatemask, areaAccumFunc, (ClientData)&gdas); + gatearea = gdas.accum; + + /* Search metal planes and accumulate all antenna areas */ for (p = 0; p < DBNumPlanes; p++) { - if (ExtCurStyle->exts_planeOrder[p] == pos) - { - pNum2 = p; - } + if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL) + if (p != pNum2) continue; + + aas.pNum = p; + aas.accum = &antennaarea[0]; if (ExtCurStyle->exts_planeOrder[p] <= pos) DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p], &TiPlaneRect, &DBAllButSpaceAndDRCBits, - antennaAccumFunc, (ClientData)&antennaarea); + antennaAccumFunc, (ClientData)&aas); } - /* To be elaborated. . . this encodes only one of several */ - /* methods of calculating antenna violations. */ - + antennaError = FALSE; if (diffarea == 0) { - difftotal = 0.0; + anttotal = 0.0; + saveRatio = 0.0; for (i = 0; i < DBNumTypes; i++) - difftotal += antennaarea[i] / ExtCurStyle->exts_antennaRatio[i]; + { + if (ExtCurStyle->exts_antennaRatio[i].ratioGate > 0) + { + anttotal += (double)antennaarea[i] / + (double)ExtCurStyle->exts_antennaRatio[i].ratioGate; + } + if (ExtCurStyle->exts_antennaRatio[i].ratioGate > saveRatio) + saveRatio = ExtCurStyle->exts_antennaRatio[i].ratioGate; + } - if (difftotal > gatearea) - TxError("Antenna violation detected at plane %s " - "(violation to be elaborated)", - DBPlaneLongNameTbl[pNum2]); + if (anttotal > (double)gatearea) + { + antennaError = TRUE; + if (efAntennaDebug == TRUE) + { + TxError("Antenna violation detected at plane %s\n", + DBPlaneLongNameTbl[pNum2]); + TxError("Effective antenna ratio %g > limit %g\n", + saveRatio * (float)anttotal / (float)gatearea, + saveRatio); + TxError("Gate rect (%d %d) to (%d %d)\n", + gdas.r.r_xbot, gdas.r.r_ybot, + gdas.r.r_xtop, gdas.r.r_ytop); + TxError("Antenna rect (%d %d) to (%d %d)\n", + aas.r.r_xbot, aas.r.r_ybot, + aas.r.r_xtop, aas.r.r_ytop); + } + } } + else + { + anttotal = 0.0; + saveRatio = 0.0; + for (i = 0; i < DBNumTypes; i++) + if (ExtCurStyle->exts_antennaRatio[i].ratioDiff != INFINITY) + { + if (ExtCurStyle->exts_antennaRatio[i].ratioDiff > 0) + anttotal += (double)antennaarea[i] / + (double)ExtCurStyle->exts_antennaRatio[i].ratioDiff; + if (ExtCurStyle->exts_antennaRatio[i].ratioDiff > saveRatio) + saveRatio = ExtCurStyle->exts_antennaRatio[i].ratioDiff; + } + + if (anttotal > (double)gatearea) + { + antennaError = TRUE; + if (efAntennaDebug == TRUE) + { + TxError("Antenna violation detected at plane %s\n", + DBPlaneLongNameTbl[pNum2]); + TxError("Effective antenna ratio %g > limit %g\n", + saveRatio * (float)anttotal / (float)gatearea, + saveRatio); + TxError("Gate rect (%d %d) to (%d %d)\n", + gdas.r.r_xbot, gdas.r.r_ybot, + gdas.r.r_xtop, gdas.r.r_ytop); + TxError("Antenna rect (%d %d) to (%d %d)\n", + aas.r.r_xbot, aas.r.r_ybot, + aas.r.r_xtop, aas.r.r_ytop); + } + } + } + + if (antennaError) + { + /* Search plane of gate type and mark all gate areas */ + ams.def = editUse->cu_def; + ams.pNum = pNum2; + DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum], + &TiPlaneRect, &gatemask, areaMarkFunc, (ClientData)&ams); + + /* Search metal planes and accumulate all antenna areas */ + for (p = 0; p < DBNumPlanes; p++) + { + if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL) + if (p != pNum2) continue; + + if (ExtCurStyle->exts_planeOrder[p] <= pos) + DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p], + &TiPlaneRect, &DBAllButSpaceAndDRCBits, + areaMarkFunc, (ClientData)&ams); + } + } + + /* Put the connect table back the way it was */ + if (conType >= 0) + TTMaskSetMask(&DBConnectTbl[conType], &saveConMask); } } + freeMagic(antennaarea); + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * + * areaMarkFunc -- + * + * Mark the tile areas searched with feedback entries + * + * ---------------------------------------------------------------------------- + */ + +int +areaMarkFunc(tile, ams) + Tile *tile; + AntennaMarkStruct *ams; +{ + Rect rect; + char msg[200]; + + TiToRect(tile, &rect); + sprintf(msg, "Antenna error at plane %s\n", DBPlaneLongNameTbl[ams->pNum]); + DBWFeedbackAdd(&rect, msg, ams->def, 1, STYLE_PALEHIGHLIGHTS); return 0; } @@ -448,19 +660,16 @@ antennacheckVisit(dev, hierName, scale, trans, editUse) */ int -areaAccumFunc(tile, totalarea) +areaAccumFunc(tile, gdas) Tile *tile; - int *totalarea; + GateDiffAccumStruct *gdas; { - Rect rect; - int area; - - TiToRect(tile, &rect); - - area += (rect.r_xtop - rect.r_xbot) * (rect.r_ytop - rect.r_ybot); - - *totalarea += area; + Rect *rect = &(gdas->r); + int area, type; + TiToRect(tile, rect); + area = (rect->r_xtop - rect->r_xbot) * (rect->r_ytop - rect->r_ybot); + gdas->accum += area; return 0; } @@ -470,27 +679,164 @@ areaAccumFunc(tile, totalarea) * antennaAccumFunc -- * * Accumulate the total tile area searched, keeping an individual - * count for each tile type. + * count for each tile type. If the antenna model is SIDEWALL, then + * calculate the area of the tile sidewall (tile perimeter * layer + * thickness), rather than the drawn tile area. * * ---------------------------------------------------------------------------- */ int -antennaAccumFunc(tile, typeareas) +antennaAccumFunc(tile, aaptr) Tile *tile; - int **typeareas; + AntennaAccumStruct *aaptr; { - Rect rect; + Rect *rect = &(aaptr->r); int area; int type; + int *typeareas = aaptr->accum; + int plane = aaptr->pNum; + float thick; type = TiGetType(tile); - TiToRect(tile, &rect); + TiToRect(tile, rect); - area += (rect.r_xtop - rect.r_xbot) * (rect.r_ytop - rect.r_ybot); + if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_SIDEWALL) + { + /* Accumulate perimeter of tile where tile abuts space */ - *typeareas[type] += area; + Tile *tp; + int perimeter = 0, pmax, pmin; + /* Top */ + for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp)) + { + if (TiGetBottomType(tp) == TT_SPACE) + { + pmin = MAX(LEFT(tile), LEFT(tp)); + pmax = MIN(RIGHT(tile), RIGHT(tp)); + perimeter += (pmax - pmin); + } + } + /* Bottom */ + for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) + { + if (TiGetTopType(tp) == TT_SPACE) + { + pmin = MAX(LEFT(tile), LEFT(tp)); + pmax = MIN(RIGHT(tile), RIGHT(tp)); + perimeter += (pmax - pmin); + } + } + /* Left */ + for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) + { + if (TiGetRightType(tp) == TT_SPACE) + { + pmin = MAX(BOTTOM(tile), BOTTOM(tp)); + pmax = MIN(TOP(tile), TOP(tp)); + perimeter += (pmax - pmin); + } + } + /* Right */ + for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) + { + if (TiGetLeftType(tp) == TT_SPACE) + { + pmin = MAX(BOTTOM(tile), BOTTOM(tp)); + pmax = MIN(TOP(tile), TOP(tp)); + perimeter += (pmax - pmin); + } + } + + if (DBIsContact(type)) + { + int cperim; + TileType ttype; + TileTypeBitMask sMask; + float thick; + + cperim = ((rect->r_xtop - rect->r_xbot) + (rect->r_ytop - rect->r_ybot)) << 1; + + /* For contacts, add the area of the perimeter to the */ + /* residue (metal) type on the plane being searched. */ + /* Then, if the plane is the same as the base type of */ + /* the contact, add the entire perimeter area of the */ + /* tile to the total for the contact type itself. */ + + DBFullResidueMask(type, &sMask); + for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++) + if (TTMaskHasType(&sMask, ttype)) + if (DBTypeOnPlane(ttype, plane)) + { + thick = ExtCurStyle->exts_thick[ttype]; + typeareas[ttype] += (int)((float)perimeter * thick); + } + + if (type >= DBNumUserLayers) + { + DBResidueMask(type, &sMask); + for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++) + if (TTMaskHasType(&sMask, ttype)) + if (DBTypeOnPlane(ttype, plane)) + { + thick = ExtCurStyle->exts_thick[ttype]; + typeareas[ttype] += (int)((float)perimeter * thick); + break; + } + } + else + { + thick = ExtCurStyle->exts_thick[type]; + typeareas[type] += (int)((float)perimeter * thick); + } + } + else + { + /* Area is perimeter times layer thickness */ + thick = ExtCurStyle->exts_thick[type]; + typeareas[type] += (int)((float)perimeter * thick); + } + } + else + { + /* Simple tile area calculation */ + area = (rect->r_xtop - rect->r_xbot) * (rect->r_ytop - rect->r_ybot); + + /* If type is a contact, then add area to both residues as well */ + /* as the contact type. */ + + /* NOTE: Restrict area counts per plane so areas of contacts */ + /* are not double-counted. */ + + if (DBIsContact(type)) + { + TileType ttype; + TileTypeBitMask sMask; + + DBFullResidueMask(type, &sMask); + for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++) + if (TTMaskHasType(&sMask, ttype)) + if (DBTypeOnPlane(ttype, plane)) + typeareas[ttype] += area; + + if (type >= DBNumUserLayers) + { + DBResidueMask(type, &sMask); + for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++) + if (TTMaskHasType(&sMask, ttype)) + if (DBTypeOnPlane(ttype, plane)) + { + typeareas[ttype] += area; + break; + } + } + else + typeareas[type] += area; + } + else + typeareas[type] += area; + } return 0; } diff --git a/extract/ExtTech.c b/extract/ExtTech.c index 94b74c79..96e3d4c7 100644 --- a/extract/ExtTech.c +++ b/extract/ExtTech.c @@ -71,7 +71,7 @@ typedef enum AREAC, CONTACT, CSCALE, DEFAULTAREACAP, DEFAULTOVERLAP, DEFAULTPERIMETER, DEFAULTSIDEOVERLAP, DEFAULTSIDEWALL, - DEVICE, FET, FETRESIST, HEIGHT, ANTENNA, TIEDOWN, LAMBDA, OVERC, + DEVICE, FET, FETRESIST, HEIGHT, ANTENNA, MODEL, TIEDOWN, LAMBDA, OVERC, PERIMC, PLANEORDER, NOPLANEORDER, RESIST, RSCALE, SIDEHALO, SIDEOVERLAP, SIDEWALL, STEP, STYLE, SUBSTRATE, UNITS, VARIANT } Key; @@ -122,9 +122,12 @@ static keydesc keyTable[] = { "height", HEIGHT, 4, 4, "type height-above-subtrate thickness", - "antenna", ANTENNA, 3, 3, + "antenna", ANTENNA, 4, 4, "type antenna-ratio", + "model", MODEL, 3, 3, +"partial-cumulative area-sidewall", + "tiedown", TIEDOWN, 2, 2, "types", @@ -376,6 +379,35 @@ ExtGetDevInfo(idx, devnameptr, sd_rclassptr, sub_rclassptr, subnameptr) #endif /* MAGIC_WRAPPER */ +/* + * ---------------------------------------------------------------------------- + * + * extGetDevType -- + * + * Given an extraction model device name (devname), return the associated + * magic tiletype for the device. + * + * Results: + * Tile type that represents the device "devname" in the magic database. + * + * ---------------------------------------------------------------------------- + */ + +TileType +extGetDevType(devname) + char *devname; +{ + TileType t; + ExtDevice *devptr; + + for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) + for (devptr = ExtCurStyle->exts_device[t]; devptr; devptr = devptr->exts_next) + if (!strcmp(devptr->exts_deviceName, devname)) + return t; + + return -1; +} + #ifdef THREE_D /* @@ -672,7 +704,8 @@ extTechStyleInit(style) for (r = 0; r < DBNumTypes; r++) { - style->exts_antennaRatio[r] = 0; + style->exts_antennaRatio[r].ratioGate = 0.0; + style->exts_antennaRatio[r].ratioDiff = 0.0; style->exts_resistByResistClass[r] = 0; TTMaskZero(&style->exts_typesByResistClass[r]); style->exts_typesResistChanged[r] = DBAllButSpaceAndDRCBits; @@ -2321,17 +2354,53 @@ ExtTechLine(sectionName, argc, argv) if (!StrIsNumeric(argv[2])) { - TechError("Layer antenna ratio %s must be numeric\n", argv[2]); + TechError("Gate layer antenna ratio %s must be numeric\n", argv[2]); break; } antennaratio = (float)strtod(argv[2], NULL); for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) if (TTMaskHasType(&types1, t)) { - ExtCurStyle->exts_antennaRatio[t] = antennaratio; + ExtCurStyle->exts_antennaRatio[t].ratioGate = antennaratio; + } + + if (!StrIsNumeric(argv[3])) + { + if (!strcasecmp(argv[3], "none")) + antennaratio = INFINITY; + else + { + TechError("Diff layer antenna ratio %s must be numeric\n", argv[3]); + break; + } + } + else + antennaratio = (float)strtod(argv[3], NULL); + for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) + if (TTMaskHasType(&types1, t)) + { + ExtCurStyle->exts_antennaRatio[t].ratioDiff = antennaratio; } } break; + case MODEL: + if (!strcmp(argv[1], "partial")) + ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_PARTIAL; + else if (!strcmp(argv[1], "cumulative")) + ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_CUMULATIVE; + else + TxError("Unknown antenna model \"%s\": Use \"partial\" or " + "\"cumulative\""); + + if (!strcmp(argv[2], "area")) + ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_AREA; + else if (!strcmp(argv[2], "sidewall")) + ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_SIDEWALL; + else + TxError("Unknown antenna model \"%s\": Use \"area\" or " + "\"sidewall\""); + break; + case TIEDOWN: TTMaskSetMask(&ExtCurStyle->exts_antennaTieTypes, &types1); break; @@ -2973,6 +3042,10 @@ zinit: ec = ec->ec_next) ec->ec_cap *= 0.5; } + + /* Layer thickness and height are in microns, but are floating-point */ + style->exts_thick[r] /= dscale; + style->exts_height[r] /= dscale; } /* side halo and step size are also in microns */ diff --git a/extract/extract.h b/extract/extract.h index b63c4acc..82e143d5 100644 --- a/extract/extract.h +++ b/extract/extract.h @@ -76,6 +76,7 @@ extern void ExtSetStyle(); extern void ExtPrintStyle(); extern void ExtCell(); + #ifdef MAGIC_WRAPPER extern bool ExtGetDevInfo(); extern bool ExtCompareStyle(); diff --git a/extract/extractInt.h b/extract/extractInt.h index 44b7f7e0..7e9c7a2e 100644 --- a/extract/extractInt.h +++ b/extract/extractInt.h @@ -48,6 +48,17 @@ typedef int ResValue; /* Warning: in some places resistances are stored * as ints. This is here for documentation only. */ +typedef struct { + float ratioGate; + float ratioDiff; +} RatioValues; + +/* Antenna models */ +#define ANTENNAMODEL_PARTIAL 0x01 +#define ANTENNAMODEL_CUMULATIVE 0x02 +#define ANTENNAMODEL_AREA 0x04 +#define ANTENNAMODEL_SIDEWALL 0x08 + /* ------------------------ Parameter lists --------------------------- */ /* These lists keep track of what parameter names subcircuit definitions @@ -656,8 +667,10 @@ typedef struct extstyle float exts_height[NT]; float exts_thick[NT]; + char exts_antennaModel; + /* Antenna area ratio for each layer */ - float exts_antennaRatio[NT]; + RatioValues exts_antennaRatio[NT]; /* Mask of types that tie down antennas */ TileTypeBitMask exts_antennaTieTypes; @@ -1060,6 +1073,7 @@ extern NodeRegion *extBasic(); extern NodeRegion *extFindNodes(); extern ExtTree *extHierNewOne(); extern int extNbrPushFunc(); +extern TileType extGetDevType(); /* --------------------- Miscellaneous globals ------------------------ */