Skip to content

Commit

Permalink
Implemented a new CIF/GDS generation operator option for
Browse files Browse the repository at this point in the history
"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).
  • Loading branch information
RTimothyEdwards committed Dec 26, 2024
1 parent 89b6f4f commit 48abe30
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 40 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8.3.507
8.3.508
162 changes: 124 additions & 38 deletions cif/CIFgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/*
*-------------------------------------------------------
*
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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 */
Expand All @@ -1310,6 +1339,7 @@ cifBloatAllFunc(tile, bls)

t = tile;
type = TiGetType(tile);

if (type == CIF_SOLIDTYPE)
{
pmask = 0;
Expand All @@ -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
{
Expand All @@ -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 */
Expand All @@ -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 */
Expand All @@ -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))
{
Expand All @@ -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. */

Expand Down Expand Up @@ -1425,49 +1514,46 @@ 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))
{
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);
}
/* 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.
*/

/* 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);
}
while (!StackEmpty(ResetStack))
{
t = (Tile *)STACKPOP(ResetStack);
t->ti_client = (ClientData) CIF_UNPROCESSED;
}

/* 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);
}
#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. . . */
}
Expand Down
17 changes: 16 additions & 1 deletion cif/CIFtech.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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. */
Expand Down

0 comments on commit 48abe30

Please sign in to comment.