From 51522d6889bf0f80695d6e2948a7a12d172eb1c7 Mon Sep 17 00:00:00 2001 From: "R. Timothy Edwards" Date: Sun, 2 Aug 2026 11:10:37 -0400 Subject: [PATCH] Multiple changes: (1) Corrections to the R-C extraction code to better handle nodes which have the recorded position at the corner of a split tile. (2) Corrected "select area label" to prevent accidentally selecting unexpanded instances in the area. Also corrects an issue with not being able to select labels that are attached to "space". (3) Changed the way that magic interprets the "sidewall" coefficient so that it is entered into the tech file as the actual sidewall coefficient instead of being half the value to correct for magic's double counting of edges. The correction is instead done when parsing the tech file. This measure was taken because the open PDK values generated by "capiche" were not halving the value, so I either change magic or I change all the tech files. --- VERSION | 2 +- extract/ExtCouple.c | 16 ++++++--- extract/ExtTech.c | 12 +++++++ resis/ResMain.c | 87 +++++++++++++++++++++++++++++++++++---------- resis/ResUtils.c | 17 +++++++-- select/selCreate.c | 11 ++++-- 6 files changed, 116 insertions(+), 29 deletions(-) diff --git a/VERSION b/VERSION index d5c5d3b5..10ef81d4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.678 +8.3.679 diff --git a/extract/ExtCouple.c b/extract/ExtCouple.c index fd0f7223..53217cb2 100644 --- a/extract/ExtCouple.c +++ b/extract/ExtCouple.c @@ -3057,6 +3057,13 @@ extSideBottom(tpfar, bp, esws) * amount of capacitance for an edge with tpnear on the close side * and tpfar on the remote side. * + * Important! The sidewall coeffient is correct for the coupling between + * edges, but both edges will be checked, causing a double-count, so each + * edge should contribute half of the total. For a long time the sidewall + * coefficient was claimed to need to be half the value, but the offset + * makes it incorrect to halve the coefficient, and it is necessary to + * halve the total sidewall capacitance when doing the calculations. + * * Results: * Returns 0 always. * @@ -3080,7 +3087,7 @@ extSideCommon(rinside, rfar, tpnear, tpfar, bdir, overlap, sep, extCoupleList) HashEntry *he; EdgeCap *e; CoupleKey ck; - CapValue cap; + CapValue cap, swcap; /* Get the tile types of tpnear and tpfar */ extGetBoundaryTypes2(bdir, tpnear, tpfar, &near, &far); @@ -3092,11 +3099,10 @@ extSideCommon(rinside, rfar, tpnear, tpfar, bdir, overlap, sep, extCoupleList) cap = extGetCapValue(he); for (e = extCoupleList; e; e = e->ec_next) if (TTMaskHasType(&e->ec_near, near) && TTMaskHasType(&e->ec_far, far)) { - cap += (e->ec_cap * overlap) / (sep + e->ec_offset); + swcap = 0.5 * (e->ec_cap * overlap) / (sep + e->ec_offset); + cap += swcap; if (CAP_DEBUG) - extAdjustCouple(he, - (e->ec_cap * overlap) / (sep + e->ec_offset), - "sidewall"); + extAdjustCouple(he, swcap, "sidewall"); } extSetCapValue(he, cap); } diff --git a/extract/ExtTech.c b/extract/ExtTech.c index 3de00911..112087e6 100644 --- a/extract/ExtTech.c +++ b/extract/ExtTech.c @@ -3291,6 +3291,18 @@ ExtTechLine(sectionName, argc, argv) return (TRUE); break; case SIDEWALL: + + /* NOTE: Originally, the sidewall capacitance coefficient was + * supposed to be the value that is appropriate to compute + * half the total sidewall on each edge. The addition of "offset" + * requires that the coefficient (and offset) should be values + * yielding the total sidewall between two edges. Because each + * edge is computed separately, the total capacitance is halved + * when doing the calculation (see ExtCouple.c). Sidewall values + * are correct for the open PDKs and presumably incorrect for the + * original SCMOS tech files. + */ + DBTechNoisyNameMask(argv[2], &types2); TTMaskSetMask(allExtractTypes, &types2); DBTechNoisyNameMask(argv[3], &near); diff --git a/resis/ResMain.c b/resis/ResMain.c index 5c71b2a2..b5a3268a 100644 --- a/resis/ResMain.c +++ b/resis/ResMain.c @@ -911,19 +911,56 @@ resMakeDevFunc(tile, dinfo, cx) Rect devArea; TileType ttype; - /* To simplify processing, if a split tile does not have TT_SPACE - * on either side, then only the left side is processed. - */ - if (IsSplit(tile)) - if (TiGetLeftType(tile) != TT_SPACE && TiGetRightType(tile) != TT_SPACE) - if (dinfo & TT_SIDE) - return 0; - TiToRect(tile, &devArea); GeoTransRect(&cx->tc_scx->scx_trans, &devArea, &thisDev->area); + /* + * NOTE: The .ext file may record devices on a split tile when the lower + * left corner is not the device. Because the location is only one unit + * square, the area of the device will not be searched. Check for this + * case and handle accordingly. + */ if (IsSplit(tile)) - ttype = ((dinfo & TT_SIDE)) ? SplitRightType(tile) : SplitLeftType(tile); + { + TileType lefttype, righttype; + bool devleft, devright; + + lefttype = TiGetLeftType(tile); + devleft = TTMaskHasType(&ExtCurStyle->exts_deviceMask, lefttype); + if (!devleft) + { + righttype = TiGetRightType(tile); + devright = TTMaskHasType(&ExtCurStyle->exts_deviceMask, righttype); + if (devright) + { + int hheight, hwidth; + + /* Find the tile half width and half height. If the width + * or height is not an even integer, round up. + */ + hheight = (TOP(tile) - BOTTOM(tile)); + hwidth = (RIGHT(tile) - LEFT(tile)); + if (hheight & 1) hheight++; + if (hwidth & 1) hwidth++; + hheight >>= 1; + hwidth >>= 1; + + /* Use the type of the tile's right side */ + ttype = SplitRightType(tile); + + /* Move the device area into the actual device location */ + thisDev->area.r_ll.p_x += hwidth; + if (TiGetTypeExact(tile) & TT_DIRECTION) + thisDev->area.r_ll.p_y += hheight; + else + thisDev->area.r_ur.p_y -= hheight; + } + else + ttype = ((dinfo & TT_SIDE)) ? righttype : lefttype; + } + else + ttype = ((dinfo & TT_SIDE)) ? righttype : lefttype; + } else ttype = TiGetType(tile); @@ -985,14 +1022,6 @@ resExpandDevFunc(tile, dinfo, cx) int pNum; Rect area; - /* To simplify processing, if a split tile does not have TT_SPACE - * on either side, then only the left side is processed. - */ - if (IsSplit(tile)) - if (TiGetLeftType(tile) != TT_SPACE && TiGetRightType(tile) != TT_SPACE) - if (dinfo & TT_SIDE) - return 0; - pNum = DBPlane(thisDev->type); if (devExtentsStack == NULL) devExtentsStack = StackNew(8); @@ -1013,8 +1042,25 @@ resExpandDevFunc(tile, dinfo, cx) if (IsSplit(tp)) { + TileType leftType; + bool isDevType; + dinfo = TiGetTypeExact(tp); - if (TiGetLeftType(tp) == TT_SPACE) + + /* For split tiles, determine which side is the device. + * Since some devices (e.g., diodes, MiM caps) may have contact + * types that are part of the device, make sure to compare the + * residue mask of the type, not the type itself. + */ + + leftType = TiGetLeftType(tp); + if (DBIsContact(leftType)) + isDevType = (TTMaskHasType(DBResidueMask(leftType), thisDev->type)) ? + TRUE : FALSE; + else + isDevType = (leftType == thisDev->type) ? TRUE : FALSE; + + if (!isDevType) { dinfo |= TT_SIDE; /* Look at tile right side */ sides |= IGNORE_LEFT; @@ -1387,6 +1433,11 @@ ResExtractNet(node, resisdata, cellname) thisDev->nextDev = DevTiles; DevTiles = thisDev; + /* Because resMakeDevFunc() may adjust the area to contain the + * device, copy thisDev->area back into scx.scx_area + */ + scx.scx_area = thisDev->area; + /* Paint the entire device into ResUse */ TTMaskSetOnlyType(&tMask, thisDev->type); DBTreeSrTiles(&scx, &tMask, 0, resExpandDevFunc, (ClientData)thisDev); diff --git a/resis/ResUtils.c b/resis/ResUtils.c index a0a70922..e8d9004a 100644 --- a/resis/ResUtils.c +++ b/resis/ResUtils.c @@ -895,6 +895,7 @@ ResPreProcessDevices(TileList, DeviceList, Def, devNodeTable) resInfo *tstruct; TileType tt, residue; int pNum; + bool isdev; while (TileList != (ResDevTile *)NULL) { @@ -925,12 +926,24 @@ ResPreProcessDevices(TileList, DeviceList, Def, devNodeTable) GOTOPOINT(tile, &(TileList->area.r_ll)); PlaneSetHint(Def->cd_planes[pNum], tile); - tt = TiGetType(tile); + tt = TiGetLeftType(tile); + isdev = TTMaskHasType(&ExtCurStyle->exts_deviceMask, tt); + + if (IsSplit(tile) && !isdev) + { + /* Check the other side */ + tt = TiGetRightType(tile); + isdev = TTMaskHasType(&ExtCurStyle->exts_deviceMask, tt); + } + + /* Warning: Will probably need to deal with resInfo structs on split + * tiles when both sides of the split tile are not TT_SPACE! + */ tstruct = (resInfo *) TiGetClientPTR(tile); if ((tstruct == (resInfo *)CLIENTDEFAULT) || (tstruct->deviceList == NULL) || - !TTMaskHasType(&ExtCurStyle->exts_deviceMask, tt)) + (!isdev)) { TxError("Bad Device Location at %d,%d\n", TileList->area.r_ll.p_x, diff --git a/select/selCreate.c b/select/selCreate.c index d7f40ba3..88b07082 100644 --- a/select/selCreate.c +++ b/select/selCreate.c @@ -470,14 +470,19 @@ SelectArea(scx, types, xMask, globmatch) if (TTMaskHasType(types, L_LABEL)) { + TileTypeBitMask *maskptr; + TTMaskClearType(types, L_LABEL); - if (TTMaskIsZero(types)) types = &DBAllButSpaceAndDRCBits; + if (TTMaskIsZero(types)) + maskptr = &DBAllTypeBits; + else + maskptr = types; if (globmatch != NULL) - DBCellCopyGlobLabels(scx, types, xMask, SelectUse, &labelArea, + DBCellCopyGlobLabels(scx, maskptr, xMask, SelectUse, &labelArea, globmatch); else - DBCellCopyAllLabels(scx, types, xMask, SelectUse, &labelArea); + DBCellCopyAllLabels(scx, maskptr, xMask, SelectUse, &labelArea); } /* Select cell uses. */