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.
This commit is contained in:
R. Timothy Edwards 2026-08-02 11:10:37 -04:00
parent 73620475d7
commit 51522d6889
6 changed files with 116 additions and 29 deletions

View File

@ -1 +1 @@
8.3.678
8.3.679

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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. */