Implemented a new CIF/GDS generation operator option for

"bloat-all" which is "bloat-all types1 types2 distance" where the
"distance" value is a maximum amount to grow.  It is not (that I
know of) particularly useful for generating output GDS, but it is
very useful for generating temporary layers for DRC checks,
especially things like determining tap distance for latch-up
rules.  The alternative (used in the sky130 tech file) is a
tedious step-by-step "grow" followed by "and-not".  This rule
option is much cleaner to implement and computes faster (although
it is still a boolean operator and is much slower than an edge
rule).
This commit is contained in:
Tim Edwards 2024-12-25 20:46:25 -05:00
parent 89b6f4f92b
commit 48abe30ea4
3 changed files with 143 additions and 42 deletions

View File

@ -1 +1 @@
8.3.507
8.3.508

View File

@ -1225,6 +1225,32 @@ cifProcessResetFunc(tile, clientData)
return 0;
}
/*
*-------------------------------------------------------
*
* cifProcessSelectiveResetFunc --
*
* Unmark tiles which are partially or wholly outside
* the clip area (passed as client data).
*
* Results: Return 0 to keep the search going.
*
*-------------------------------------------------------
*/
int
cifProcessSelectiveResetFunc(tile, clipArea)
Tile *tile;
Rect *clipArea;
{
Rect area;
TiToRect(tile, &area);
if (!GEO_SURROUND(&area, clipArea))
tile->ti_client = (ClientData) CIF_UNPROCESSED;
return 0;
}
/*
*-------------------------------------------------------
*
@ -1280,9 +1306,9 @@ cifBloatAllFunc(tile, bls)
Tile *tile; /* The tile to be processed. */
BloatStruct *bls;
{
Rect area;
Rect area, clipArea;
TileTypeBitMask *connect;
Tile *t, *tp;
Tile *t, *tp, *firstTile = NULL;
TileType type, ttype;
BloatData *bloats;
int i, locScale;
@ -1291,6 +1317,7 @@ cifBloatAllFunc(tile, bls)
CellDef *def;
Plane **temps;
static Stack *BloatStack = (Stack *)NULL;
static Stack *ResetStack = (Stack *)NULL;
op = bls->op;
def = bls->def;
@ -1302,6 +1329,8 @@ cifBloatAllFunc(tile, bls)
if (BloatStack == (Stack *)NULL)
BloatStack = StackNew(64);
if (ResetStack == (Stack *)NULL)
ResetStack = StackNew(64);
/* If the type of the tile to be processed is not in the same plane */
/* as the bloat type(s), then find any tile under the tile to be */
@ -1310,6 +1339,7 @@ cifBloatAllFunc(tile, bls)
t = tile;
type = TiGetType(tile);
if (type == CIF_SOLIDTYPE)
{
pmask = 0;
@ -1324,6 +1354,8 @@ cifBloatAllFunc(tile, bls)
area.r_xtop /= locScale;
area.r_ybot /= locScale;
area.r_ytop /= locScale;
if (op->co_distance > 0) clipArea = area;
}
else
{
@ -1339,6 +1371,7 @@ cifBloatAllFunc(tile, bls)
CoincidentPlanes(connect, PlaneNumToMaskBit(pNum));
}
if (pmask == 0) TiToRect(tile, &area);
if (bloats->bl_plane < 0)
{
/* Get the tile into CIF database coordinates if it's in magic coords */
@ -1347,14 +1380,18 @@ cifBloatAllFunc(tile, bls)
area.r_ybot *= cifScale;
area.r_ytop *= cifScale;
locScale = 1;
if (op->co_distance > 0) clipArea = area;
}
else
{
locScale = cifScale;
if (op->co_distance > 0) TiToRect(tile, &clipArea);
}
}
if (pmask == 0)
{
Rect foundArea;
if (bloats->bl_plane < 0) /* Bloat types are CIF types */
{
/* This expands the area to the OR of all temp layers specified */
@ -1365,13 +1402,54 @@ cifBloatAllFunc(tile, bls)
if (bloats->bl_distance[ttype] > 0)
(void) DBSrPaintArea((Tile *)NULL, *temps, &area,
&CIFSolidBits, cifFoundFunc, (ClientData)(&BloatStack));
/* Get clip area from intersection of found tile and t */
if (op->co_distance > 0)
{
if (!StackEmpty(BloatStack))
{
firstTile = (Tile *)StackLook(BloatStack);
TiToRect(firstTile, &foundArea);
GeoClip(&clipArea, &foundArea);
}
}
}
else
{
DBSrPaintArea((Tile *)NULL, def->cd_planes[bloats->bl_plane], &area,
connect, cifFoundFunc, (ClientData)(&BloatStack));
/* Get clip area from intersection of found tile and t */
if (op->co_distance > 0)
{
if (!StackEmpty(BloatStack))
{
firstTile = (Tile *)StackLook(BloatStack);
TiToRect(firstTile, &foundArea);
GeoClip(&clipArea, &foundArea);
}
}
}
}
else
{
PUSHTILE(t, BloatStack);
firstTile = t;
}
/* Note: if op->co_distance is 0 then bloat distance is arbitrarily large */
if (op->co_distance > 0)
{
clipArea.r_xbot *= locScale;
clipArea.r_ybot *= locScale;
clipArea.r_xtop *= locScale;
clipArea.r_ytop *= locScale;
clipArea.r_xtop += op->co_distance;
clipArea.r_xbot -= op->co_distance;
clipArea.r_ytop += op->co_distance;
clipArea.r_ybot -= op->co_distance;
}
while (!StackEmpty(BloatStack))
{
@ -1387,6 +1465,17 @@ cifBloatAllFunc(tile, bls)
area.r_xtop *= locScale;
area.r_ytop *= locScale;
if (op->co_distance > 0)
{
if (!GEO_SURROUND(&clipArea, &area))
{
STACKPUSH(t, ResetStack);
}
GeoClip(&area, &clipArea);
if (GEO_RECTNULL(&area))
continue;
}
/* Diagonal: If expanding across the edge of a diagonal, */
/* then just fill the whole tile. */
@ -1425,50 +1514,47 @@ cifBloatAllFunc(tile, bls)
for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
if (TTMaskHasType(connect, TiGetLeftType(tp)))
PUSHTILE(tp, BloatStack);
}
/* Clear the tiles that were processed */
/* Clear self */
tile->ti_client = (ClientData)CIF_UNPROCESSED;
STACKPUSH(tile, BloatStack);
while (!StackEmpty(BloatStack))
/* NOTE: Tiles must be cleared after the bloat-all function has
* completed. However, for bloat-all with a limiting distance,
* it is necessary to clear tiles after each tile processed,
* because a processed tile that was partially or wholly outside
* of the clip area may be inside another tile's clip area.
* Those tiles that were not fully inside the clip area have all
* been pushed to the ResetStack.
*/
while (!StackEmpty(ResetStack))
{
t = (Tile *) STACKPOP(BloatStack);
/* Top */
for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
{
tp->ti_client = (ClientData)CIF_UNPROCESSED;
STACKPUSH(tp, BloatStack);
}
/* Left */
for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
{
tp->ti_client = (ClientData)CIF_UNPROCESSED;
STACKPUSH(tp, BloatStack);
}
/* Bottom */
for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
{
tp->ti_client = (ClientData)CIF_UNPROCESSED;
STACKPUSH(tp, BloatStack);
}
/* Right */
for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
{
tp->ti_client = (ClientData)CIF_UNPROCESSED;
STACKPUSH(tp, BloatStack);
}
t = (Tile *)STACKPOP(ResetStack);
t->ti_client = (ClientData) CIF_UNPROCESSED;
}
#if 0
if ((firstTile != NULL) && (op->co_distance > 0))
{
if (bloats->bl_plane < 0)
{
/* This would be a lot more efficient if the plane number of
* firstTile were pushed to the stack along with firstTile
*/
temps = bls->temps;
for (ttype = 0; ttype < TT_MAXTYPES; ttype++, temps++)
if (bloats->bl_distance[ttype] > 0)
(void) DBSrPaintArea((Tile *)NULL, *temps, &clipArea,
&CIFSolidBits, cifProcessSelectiveResetFunc,
&clipArea);
}
else
DBSrPaintArea((Tile *)firstTile, def->cd_planes[bloats->bl_plane],
&clipArea, connect, cifProcessSelectiveResetFunc, &clipArea);
}
#endif
return 0; /* Keep the search alive. . . */
}

View File

@ -1163,7 +1163,7 @@ CIFTechLine(sectionName, argc, argv)
break;
case CIFOP_BLOATALL:
if (argc != 3) goto wrongNumArgs;
if (argc != 3 && argc != 4) goto wrongNumArgs;
cifParseLayers(argv[1], CIFCurStyle, &newOp->co_paintMask,
&newOp->co_cifMask, FALSE);
bloats = (BloatData *)mallocMagic(sizeof(BloatData));
@ -1179,6 +1179,21 @@ CIFTechLine(sectionName, argc, argv)
if (!TTMaskIsZero(&mask) && !TTMaskIsZero(&cifMask))
TechError("Can't mix CIF and magic layers in bloat statement.\n");
if (argc == 4)
{
/* 12/23/2024: Allow an additional argument, which is a
* maximum halo distance to bloat (i.e., clip mask)
*/
newOp->co_distance = atoi(argv[3]);
if (newOp->co_distance <= 0)
{
TechError("Bloat distance must be greater than zero.\n");
goto errorReturn;
}
}
else
newOp->co_distance = 0;
/* 10/15/2019: Lifting restriction that the types that */
/* trigger the bloating must be in the same plane as the */
/* types that are bloated into. */