From 39ab59e7ecf1e1f98c846928624b398854ff93a7 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 18 Oct 2019 14:12:52 -0400 Subject: [PATCH 1/2] Corrected error causing a crash when parasitic extraction is invoked on a layout with an array of instances. Also, continued implementation of antenna violation checking (not done yet). --- ext2spice/ext2hier.c | 2 +- extflat/Depend | 3 +- extflat/EFantenna.c | 237 +++++++++++++++++++++++++++++++++++++++---- extflat/EFbuild.c | 4 +- extflat/EFflat.c | 6 +- extflat/EFint.h | 2 +- extflat/extflat.h | 4 +- extract/ExtTech.c | 12 ++- extract/extractInt.h | 3 + 9 files changed, 243 insertions(+), 30 deletions(-) diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index fd06a376..7d3df37f 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -1686,7 +1686,7 @@ esMakePorts(hc, cdata) // Find the cell for the instance portdef = NULL; - he = HashFind(&updef->def_uses, portname); + he = HashLookOnly(&updef->def_uses, portname); if (he != NULL) { use = (Use *)HashGetValue(he); diff --git a/extflat/Depend b/extflat/Depend index a48cf3b8..c2c89681 100644 --- a/extflat/Depend +++ b/extflat/Depend @@ -32,4 +32,5 @@ 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 ../utils/malloc.h + ../extract/extract.h ../extract/extractInt.h ../extract/extDebugInt.h \ + ../utils/malloc.h diff --git a/extflat/EFantenna.c b/extflat/EFantenna.c index 0048b3f9..4bbbd1c4 100644 --- a/extflat/EFantenna.c +++ b/extflat/EFantenna.c @@ -29,7 +29,8 @@ #include "textio/txcommands.h" #endif #include "extflat/extflat.h" -#include "extract/extract.h" /* for extDevTable */ +#include "extract/extract.h" +#include "extract/extractInt.h" #include "utils/malloc.h" /* Forward declarations */ @@ -103,6 +104,8 @@ CmdAntennaCheck(w, cmd) char *subname; int idx; + CellUse *editUse; + static char *cmdAntennaCheckOption[] = { "[run] [options] run antennacheck on current cell\n" " use \"run -help\" to get standard options", @@ -134,6 +137,13 @@ usage: runantennacheck: + if (ExtCurStyle->exts_planeOrderStatus == noPlaneOrder) + { + TxError("No planeorder specified for this process: " + "Cannot run antenna checks!\n"); + return; + } + EFInit(); EFCapThreshold = INFINITY; EFResistThreshold = INFINITY; @@ -162,6 +172,7 @@ runantennacheck: } inName = ((CellUse *) w->w_surfaceID)->cu_def->cd_name; } + editUse = (CellUse *)w->w_surfaceID; /* * Initializations specific to this program. @@ -178,7 +189,7 @@ runantennacheck: flatFlags = EF_FLATNODES; EFFlatBuild(inName, flatFlags); - EFVisitDevs(antennacheckVisit, (ClientData)NULL); + EFVisitDevs(antennacheckVisit, (ClientData)editUse); EFFlatDone(); EFDone(); @@ -234,9 +245,30 @@ usage: TxError("Usage: antennacheck\n"); return 1; } - - +/* + * ---------------------------------------------------------------------------- + * + * AntennaGetNode -- + * + * function to find a node given its hierarchical prefix and suffix + * + * Results: + * a pointer to the node struct or NULL + * + * ---------------------------------------------------------------------------- + */ +EFNode * +AntennaGetNode(prefix, suffix) +HierName *prefix; +HierName *suffix; +{ + HashEntry *he; + + he = EFHNConcatLook(prefix, suffix, "output"); + return(((EFNodeName *) HashGetValue(he))->efnn_node); +} + /* * ---------------------------------------------------------------------------- * @@ -256,15 +288,30 @@ usage: */ int -antennacheckVisit(dev, hierName, scale, trans) +antennacheckVisit(dev, hierName, scale, trans, editUse) Dev *dev; /* Device being output */ HierName *hierName; /* Hierarchical path down to this device */ float scale; /* Scale transform for output */ Transform *trans; /* Coordinate transform */ + CellUse *editUse; /* ClientData is edit cell use */ { - DevTerm *gate, *source, *drain; - int l, w; + DevTerm *gate; + int pos, pNum, pNum2, pmax, p, i, j, gatearea, diffarea, total; + double difftotal; + int *antennaarea; Rect r; + EFNode *gnode; + SearchContext scx; + TileTypeBitMask gatemask; + + extern CellDef *extPathDef; /* see extract/ExtLength.c */ + extern CellUse *extPathUse; /* see extract/ExtLength.c */ + + extern int areaAccumFunc(), antennaAccumFunc(); + + antennaarea = (int *)mallocMagic(DBNumTypes * sizeof(int)); + + for (i = 0; i < DBNumTypes; i++) antennaarea[i] = 0; switch(dev->dev_class) { @@ -274,24 +321,176 @@ antennacheckVisit(dev, hierName, scale, trans) /* Procedure: * - * 1. If device is marked visited, return. - * 2. Mark device visited - * 3. Mark all connected devices visited - * 4. For each plane from metal1 up (determined by planeorder): - * a. Run SimTreeCopyConnect() + * 1. If device gate node is marked visited, return. + * 2. Mark device gate node visited + * 3. For each plane from metal1 up (determined by planeorder): + * a. Run DBTreeCopyConnect() * b. Accumulate gate area of connected devices - * c. Accumulate metal area of connected devices - * d. Check against antenna ratio - * e. Generate feedback if in violation of antenna rule + * c. Accumulate diffusion area of connected devices + * d. Accumulate metal area of connected devices + * e. Check against antenna ratio(s) + * f. Generate feedback if in violation of antenna rule * - * NOTE: SimTreeCopyConnect() is used cumulatively, so that + * NOTE: DBTreeCopyConnect() is used cumulatively, so that * additional searching only needs to be done for the additional - * layer being searched. This is the reason for using - * SimTreeCopyConnect() instead of DBTreeCopyConnect(). + * layer being searched. */ - /* To be completed */ + gate = &dev->dev_terms[0]; + + gnode = AntennaGetNode(hierName, gate->dterm_node->efnode_name->efnn_hier); + if (beenVisited((nodeClient *)gnode->efnode_client, 0)) + return 0; + else + markVisited((nodeClient *)gnode->efnode_client, 0); + + /* Find the plane of the gate type */ + pNum = DBPlane(dev->dev_type); + pos = ExtCurStyle->exts_planeOrder[pNum]; + pmax = ++pos; + + /* Find the highest plane in the technology */ + for (p = PL_TECHDEPBASE; p < DBNumPlanes; p++) + if (ExtCurStyle->exts_planeOrder[p] > pmax) + pmax = ExtCurStyle->exts_planeOrder[p]; + + /* Use the cellDef reserved for extraction */ + DBCellClearDef(extPathDef); + scx.scx_use = editUse; + scx.scx_trans = GeoIdentityTransform; + + /* gatemask is a mask of all gate types for MOSFET devices */ + + TTMaskZero(&gatemask); + for (i = 0; i < DBNumTypes; i++) + { + ExtDevice *ed; + char devclass; + + if (ExtCurStyle->exts_device[i] != NULL) + { + for (ed = ExtCurStyle->exts_device[i]; ed; ed = ed->exts_next) + { + devclass = ed->exts_deviceClass; + switch (devclass) + { + case DEV_MOSFET: + case DEV_FET: + case DEV_ASYMMETRIC: + case DEV_MSUBCKT: + TTMaskSetType(&gatemask, i); + break; + } + } + } + } + + for (; pos <= pmax; pos++) + { + /* Modify DBConnectTbl to limit connectivity to the plane */ + /* of the antenna check and below */ + + /* To be completed */ + + DBTreeCopyConnect(&scx, &DBConnectTbl[dev->dev_type], 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 */ + for (p = 0; p < DBNumPlanes; p++) + DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p], + &TiPlaneRect, &ExtCurStyle->exts_antennaTieTypes, + areaAccumFunc, (ClientData)&diffarea); + + /* Search metal planes and accumulate all (new) antenna areas */ + for (p = 0; p < DBNumPlanes; p++) + { + if (ExtCurStyle->exts_planeOrder[p] == pos) + { + pNum2 = p; + } + if (ExtCurStyle->exts_planeOrder[p] <= pos) + DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p], + &TiPlaneRect, &DBAllButSpaceAndDRCBits, + antennaAccumFunc, (ClientData)&antennaarea); + } + + /* To be elaborated. . . this encodes only one of several */ + /* methods of calculating antenna violations. */ + + if (diffarea == 0) + { + difftotal = 0.0; + for (i = 0; i < DBNumTypes; i++) + difftotal += antennaarea[i] / ExtCurStyle->exts_antennaRatio[i]; + + if (difftotal > gatearea) + TxError("Antenna violation detected at plane %s " + "(violation to be elaborated)", + DBPlaneLongNameTbl[pNum2]); + } + } } return 0; } +/* + * ---------------------------------------------------------------------------- + * + * areaAccumFunc -- + * + * Accumulate the total tile area searched + * + * ---------------------------------------------------------------------------- + */ + +int +areaAccumFunc(tile, totalarea) + Tile *tile; + int *totalarea; +{ + Rect rect; + int area; + + TiToRect(tile, &rect); + + area += (rect.r_xtop - rect.r_xbot) * (rect.r_ytop - rect.r_ybot); + + *totalarea += area; + + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * + * antennaAccumFunc -- + * + * Accumulate the total tile area searched, keeping an individual + * count for each tile type. + * + * ---------------------------------------------------------------------------- + */ + +int +antennaAccumFunc(tile, typeareas) + Tile *tile; + int **typeareas; +{ + Rect rect; + int area; + int type; + + type = TiGetType(tile); + + TiToRect(tile, &rect); + + area += (rect.r_xtop - rect.r_xbot) * (rect.r_ytop - rect.r_ybot); + + *typeareas[type] += area; + + return 0; +} diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index a7631a26..dd2c700e 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -172,7 +172,7 @@ efBuildNode(def, isSubsnode, nodeName, nodeCap, x, y, layerName, av, ac) HashSetValue(he, (char *) newname); /* New node itself */ - size = sizeof (EFNode) + (efNumResistClasses - 1) * sizeof (PerimArea); + size = sizeof (EFNode) + (efNumResistClasses - 1) * sizeof (EFPerimArea); newnode = (EFNode *) mallocMagic((unsigned)(size)); newnode->efnode_flags = (isSubsnode == TRUE) ? EF_SUBS_NODE : 0; newnode->efnode_cap = nodeCap; @@ -1182,7 +1182,7 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac) int n; Connection *conn; unsigned size = sizeof (Connection) - + (efNumResistClasses - 1) * sizeof (PerimArea); + + (efNumResistClasses - 1) * sizeof (EFPerimArea); conn = (Connection *) mallocMagic((unsigned)(size)); diff --git a/extflat/EFflat.c b/extflat/EFflat.c index 27e8d4e3..9725def9 100644 --- a/extflat/EFflat.c +++ b/extflat/EFflat.c @@ -430,7 +430,7 @@ efAddNodes(hc, stdcell) bool is_subcircuit = (def->def_flags & DEF_SUBCIRCUIT) ? TRUE : FALSE; scale = def->def_scale; - size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (PerimArea); + size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea); for (node = (EFNode *) def->def_firstn.efnode_next; node != &def->def_firstn; @@ -467,10 +467,10 @@ efAddNodes(hc, stdcell) newnode->efnode_type = node->efnode_type; if (!stdcell) bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa, - efNumResistClasses * sizeof (PerimArea)); + efNumResistClasses * sizeof (EFPerimArea)); else bzero((char *) newnode->efnode_pa, - efNumResistClasses * sizeof (PerimArea)); + efNumResistClasses * sizeof (EFPerimArea)); GeoTransRect(&hc->hc_trans, &node->efnode_loc, &newnode->efnode_loc); /* Scale the result by "scale" --- hopefully we end up with an integer */ diff --git a/extflat/EFint.h b/extflat/EFint.h index 6ec90eca..9c380528 100644 --- a/extflat/EFint.h +++ b/extflat/EFint.h @@ -133,7 +133,7 @@ typedef struct conn } conn_value; struct conn *conn_next; /* Next connection in list */ - PerimArea conn_pa[1]; /* Dummy; each connection actually has + EFPerimArea conn_pa[1]; /* Dummy; each connection actually has * efNumResistClasses array elements * allocated to it. */ diff --git a/extflat/extflat.h b/extflat/extflat.h index f249e37c..d7dec156 100644 --- a/extflat/extflat.h +++ b/extflat/extflat.h @@ -142,7 +142,7 @@ typedef struct { int pa_area; int pa_perim; -} PerimArea; +} EFPerimArea; typedef struct efnhdr { @@ -219,7 +219,7 @@ typedef struct efnode */ EFAttr *efnode_attrs; /* Node attribute list */ ClientData efnode_client; /* For hire */ - PerimArea efnode_pa[1]; /* Dummy; each node actually has + EFPerimArea efnode_pa[1]; /* Dummy; each node actually has * efNumResistClasses array elements * allocated to it. */ diff --git a/extract/ExtTech.c b/extract/ExtTech.c index 21ff4ce3..94b74c79 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, LAMBDA, OVERC, + DEVICE, FET, FETRESIST, HEIGHT, ANTENNA, TIEDOWN, LAMBDA, OVERC, PERIMC, PLANEORDER, NOPLANEORDER, RESIST, RSCALE, SIDEHALO, SIDEOVERLAP, SIDEWALL, STEP, STYLE, SUBSTRATE, UNITS, VARIANT } Key; @@ -125,6 +125,9 @@ static keydesc keyTable[] = { "antenna", ANTENNA, 3, 3, "type antenna-ratio", + "tiedown", TIEDOWN, 2, 2, +"types", + "lambda", LAMBDA, 2, 2, "units-per-lambda", @@ -665,14 +668,17 @@ extTechStyleInit(style) style->exts_numResistClasses = 0; style->exts_planeOrderStatus = needPlaneOrder ; + TTMaskZero(&style->exts_antennaTieTypes); for (r = 0; r < DBNumTypes; r++) { + style->exts_antennaRatio[r] = 0; style->exts_resistByResistClass[r] = 0; TTMaskZero(&style->exts_typesByResistClass[r]); style->exts_typesResistChanged[r] = DBAllButSpaceAndDRCBits; TTMaskSetType(&style->exts_typesResistChanged[r], TT_SPACE); style->exts_typeToResistClass[r] = -1; + } doConvert = FALSE; @@ -1789,6 +1795,7 @@ ExtTechLine(sectionName, argc, argv) case FETRESIST: case HEIGHT: case ANTENNA: + case TIEDOWN: case OVERC: case PERIMC: case RESIST: @@ -2325,6 +2332,9 @@ ExtTechLine(sectionName, argc, argv) } } break; + case TIEDOWN: + TTMaskSetMask(&ExtCurStyle->exts_antennaTieTypes, &types1); + break; case UNITS: if (!strcmp(argv[1], "microns")) doConvert = TRUE; diff --git a/extract/extractInt.h b/extract/extractInt.h index bb30c425..44b7f7e0 100644 --- a/extract/extractInt.h +++ b/extract/extractInt.h @@ -659,6 +659,9 @@ typedef struct extstyle /* Antenna area ratio for each layer */ float exts_antennaRatio[NT]; + /* Mask of types that tie down antennas */ + TileTypeBitMask exts_antennaTieTypes; + /* * Capacitance to substrate for each tile type, in units of * attofarads per square lambda. From b8c34cb10b703efdbce1bf29dcab47812176487c Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 18 Oct 2019 14:25:28 -0400 Subject: [PATCH 2/2] Fixed an additional call to HashFind() that should have been HashLookOnly() and can potentially cause a crash. --- ext2spice/ext2hier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index 7d3df37f..07143cb0 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -1596,7 +1596,7 @@ esMakePorts(hc, cdata) // Find the cell for the instance portdef = NULL; - he = HashFind(&updef->def_uses, portname); + he = HashLookOnly(&updef->def_uses, portname); if (he != NULL) { use = (Use *)HashGetValue(he);