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:
parent
89b6f4f92b
commit
48abe30ea4
154
cif/CIFgen.c
154
cif/CIFgen.c
|
|
@ -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. . . */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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. */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue