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; 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. */ Tile *tile; /* The tile to be processed. */
BloatStruct *bls; BloatStruct *bls;
{ {
Rect area; Rect area, clipArea;
TileTypeBitMask *connect; TileTypeBitMask *connect;
Tile *t, *tp; Tile *t, *tp, *firstTile = NULL;
TileType type, ttype; TileType type, ttype;
BloatData *bloats; BloatData *bloats;
int i, locScale; int i, locScale;
@ -1291,6 +1317,7 @@ cifBloatAllFunc(tile, bls)
CellDef *def; CellDef *def;
Plane **temps; Plane **temps;
static Stack *BloatStack = (Stack *)NULL; static Stack *BloatStack = (Stack *)NULL;
static Stack *ResetStack = (Stack *)NULL;
op = bls->op; op = bls->op;
def = bls->def; def = bls->def;
@ -1302,6 +1329,8 @@ cifBloatAllFunc(tile, bls)
if (BloatStack == (Stack *)NULL) if (BloatStack == (Stack *)NULL)
BloatStack = StackNew(64); 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 */ /* 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 */ /* as the bloat type(s), then find any tile under the tile to be */
@ -1310,6 +1339,7 @@ cifBloatAllFunc(tile, bls)
t = tile; t = tile;
type = TiGetType(tile); type = TiGetType(tile);
if (type == CIF_SOLIDTYPE) if (type == CIF_SOLIDTYPE)
{ {
pmask = 0; pmask = 0;
@ -1324,6 +1354,8 @@ cifBloatAllFunc(tile, bls)
area.r_xtop /= locScale; area.r_xtop /= locScale;
area.r_ybot /= locScale; area.r_ybot /= locScale;
area.r_ytop /= locScale; area.r_ytop /= locScale;
if (op->co_distance > 0) clipArea = area;
} }
else else
{ {
@ -1339,6 +1371,7 @@ cifBloatAllFunc(tile, bls)
CoincidentPlanes(connect, PlaneNumToMaskBit(pNum)); CoincidentPlanes(connect, PlaneNumToMaskBit(pNum));
} }
if (pmask == 0) TiToRect(tile, &area); if (pmask == 0) TiToRect(tile, &area);
if (bloats->bl_plane < 0) if (bloats->bl_plane < 0)
{ {
/* Get the tile into CIF database coordinates if it's in magic coords */ /* 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_ybot *= cifScale;
area.r_ytop *= cifScale; area.r_ytop *= cifScale;
locScale = 1; locScale = 1;
if (op->co_distance > 0) clipArea = area;
} }
else else
{ {
locScale = cifScale; locScale = cifScale;
if (op->co_distance > 0) TiToRect(tile, &clipArea);
} }
} }
if (pmask == 0) if (pmask == 0)
{ {
Rect foundArea;
if (bloats->bl_plane < 0) /* Bloat types are CIF types */ if (bloats->bl_plane < 0) /* Bloat types are CIF types */
{ {
/* This expands the area to the OR of all temp layers specified */ /* 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) if (bloats->bl_distance[ttype] > 0)
(void) DBSrPaintArea((Tile *)NULL, *temps, &area, (void) DBSrPaintArea((Tile *)NULL, *temps, &area,
&CIFSolidBits, cifFoundFunc, (ClientData)(&BloatStack)); &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 else
{
DBSrPaintArea((Tile *)NULL, def->cd_planes[bloats->bl_plane], &area, DBSrPaintArea((Tile *)NULL, def->cd_planes[bloats->bl_plane], &area,
connect, cifFoundFunc, (ClientData)(&BloatStack)); 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 else
{
PUSHTILE(t, BloatStack); 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)) while (!StackEmpty(BloatStack))
{ {
@ -1387,6 +1465,17 @@ cifBloatAllFunc(tile, bls)
area.r_xtop *= locScale; area.r_xtop *= locScale;
area.r_ytop *= 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, */ /* Diagonal: If expanding across the edge of a diagonal, */
/* then just fill the whole tile. */ /* then just fill the whole tile. */
@ -1425,49 +1514,46 @@ cifBloatAllFunc(tile, bls)
for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp)) for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
if (TTMaskHasType(connect, TiGetLeftType(tp))) if (TTMaskHasType(connect, TiGetLeftType(tp)))
PUSHTILE(tp, BloatStack); PUSHTILE(tp, BloatStack);
} }
/* Clear the tiles that were processed */ /* Clear self */
tile->ti_client = (ClientData)CIF_UNPROCESSED; tile->ti_client = (ClientData)CIF_UNPROCESSED;
STACKPUSH(tile, BloatStack);
while (!StackEmpty(BloatStack))
{
t = (Tile *) STACKPOP(BloatStack);
/* Top */ /* NOTE: Tiles must be cleared after the bloat-all function has
for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp)) * completed. However, for bloat-all with a limiting distance,
if (tp->ti_client != (ClientData)CIF_UNPROCESSED) * 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))
{ {
tp->ti_client = (ClientData)CIF_UNPROCESSED; t = (Tile *)STACKPOP(ResetStack);
STACKPUSH(tp, BloatStack); t->ti_client = (ClientData) CIF_UNPROCESSED;
} }
/* Left */ #if 0
for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp)) if ((firstTile != NULL) && (op->co_distance > 0))
if (tp->ti_client != (ClientData)CIF_UNPROCESSED)
{ {
tp->ti_client = (ClientData)CIF_UNPROCESSED; if (bloats->bl_plane < 0)
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; /* This would be a lot more efficient if the plane number of
STACKPUSH(tp, BloatStack); * firstTile were pushed to the stack along with firstTile
} */
temps = bls->temps;
/* Right */ for (ttype = 0; ttype < TT_MAXTYPES; ttype++, temps++)
for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp)) if (bloats->bl_distance[ttype] > 0)
if (tp->ti_client != (ClientData)CIF_UNPROCESSED) (void) DBSrPaintArea((Tile *)NULL, *temps, &clipArea,
{ &CIFSolidBits, cifProcessSelectiveResetFunc,
tp->ti_client = (ClientData)CIF_UNPROCESSED; &clipArea);
STACKPUSH(tp, BloatStack);
} }
else
DBSrPaintArea((Tile *)firstTile, def->cd_planes[bloats->bl_plane],
&clipArea, connect, cifProcessSelectiveResetFunc, &clipArea);
} }
#endif
return 0; /* Keep the search alive. . . */ return 0; /* Keep the search alive. . . */
} }

View File

@ -1163,7 +1163,7 @@ CIFTechLine(sectionName, argc, argv)
break; break;
case CIFOP_BLOATALL: case CIFOP_BLOATALL:
if (argc != 3) goto wrongNumArgs; if (argc != 3 && argc != 4) goto wrongNumArgs;
cifParseLayers(argv[1], CIFCurStyle, &newOp->co_paintMask, cifParseLayers(argv[1], CIFCurStyle, &newOp->co_paintMask,
&newOp->co_cifMask, FALSE); &newOp->co_cifMask, FALSE);
bloats = (BloatData *)mallocMagic(sizeof(BloatData)); bloats = (BloatData *)mallocMagic(sizeof(BloatData));
@ -1179,6 +1179,21 @@ CIFTechLine(sectionName, argc, argv)
if (!TTMaskIsZero(&mask) && !TTMaskIsZero(&cifMask)) if (!TTMaskIsZero(&mask) && !TTMaskIsZero(&cifMask))
TechError("Can't mix CIF and magic layers in bloat statement.\n"); 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 */ /* 10/15/2019: Lifting restriction that the types that */
/* trigger the bloating must be in the same plane as the */ /* trigger the bloating must be in the same plane as the */
/* types that are bloated into. */ /* types that are bloated into. */