Two changes to "lef write": (1) Added support for generating output
for geometry on MASTERSLICE layers (which was inadvertantly broken), and (2) Added option "lef write -toplayer", which outputs pin geometry only for the topmost layer belonging to a pin, with connected layers underneath being designated as obstructions.
This commit is contained in:
parent
72b4053774
commit
7a8e6352a3
|
|
@ -902,7 +902,7 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
/* Layer names are taken from the LEF database. */
|
/* Layer names are taken from the LEF database. */
|
||||||
|
|
||||||
lefName = MagicToLefTable[ttype].lefName;
|
lefName = MagicToLefTable[ttype].lefName;
|
||||||
ASSERT(lefName, "Valid ttype");
|
if (lefName == NULL) return 0; /* Do not write types not in LEF definition */
|
||||||
lefType = MagicToLefTable[ttype].lefInfo;
|
lefType = MagicToLefTable[ttype].lefInfo;
|
||||||
|
|
||||||
orient = GEO_EAST;
|
orient = GEO_EAST;
|
||||||
|
|
@ -1393,6 +1393,7 @@ defCountViaFunc(tile, cviadata)
|
||||||
/* Generate a via name from the layer name and tile size */
|
/* Generate a via name from the layer name and tile size */
|
||||||
|
|
||||||
lname = MagicToLefTable[ctype].lefName;
|
lname = MagicToLefTable[ctype].lefName;
|
||||||
|
if (lname == NULL) return 0; /* Do not output undefined LEF layers */
|
||||||
TiToRect(tile, &r);
|
TiToRect(tile, &r);
|
||||||
|
|
||||||
/* Boundary search. WARNING: This code is quite naive. The */
|
/* Boundary search. WARNING: This code is quite naive. The */
|
||||||
|
|
@ -1551,7 +1552,8 @@ defGetType(ttype, lefptr)
|
||||||
while (he = HashNext(&LefInfo, &hs))
|
while (he = HashNext(&LefInfo, &hs))
|
||||||
{
|
{
|
||||||
lefl = (lefLayer *)HashGetValue(he);
|
lefl = (lefLayer *)HashGetValue(he);
|
||||||
if (lefl && (contact == lefl->lefClass))
|
if (lefl && ((contact == lefl->lefClass) ||
|
||||||
|
((contact == CLASS_ROUTE) && (lefl->lefClass == CLASS_MASTER))))
|
||||||
if ((lefl->type == ttype) || (lefl->obsType == ttype))
|
if ((lefl->type == ttype) || (lefl->obsType == ttype))
|
||||||
{
|
{
|
||||||
if (lefptr) *lefptr = lefl;
|
if (lefptr) *lefptr = lefl;
|
||||||
|
|
@ -1560,9 +1562,9 @@ defGetType(ttype, lefptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we got here, there is no entry; use the database name */
|
/* If we got here, there is no entry; return NULL. */
|
||||||
if (lefptr) *lefptr = (lefLayer *)NULL;
|
if (lefptr) *lefptr = (lefLayer *)NULL;
|
||||||
return DBTypeLongNameTbl[ttype];
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
18
lef/lefCmd.c
18
lef/lefCmd.c
|
|
@ -87,6 +87,10 @@ CmdLef(w, cmd)
|
||||||
* the macro other than pin area
|
* the macro other than pin area
|
||||||
* immediately surrounding labels.
|
* immediately surrounding labels.
|
||||||
*/
|
*/
|
||||||
|
bool lefTopLayer = False; /* If TRUE, only output the topmost
|
||||||
|
* layer used by a pin, and make
|
||||||
|
* all layers below it obstructions.
|
||||||
|
*/
|
||||||
bool recurse = FALSE; /* If TRUE, recurse on all subcells
|
bool recurse = FALSE; /* If TRUE, recurse on all subcells
|
||||||
* during "writeall". By default,
|
* during "writeall". By default,
|
||||||
* only the immediate children of the
|
* only the immediate children of the
|
||||||
|
|
@ -208,13 +212,16 @@ CmdLef(w, cmd)
|
||||||
lefTech = TRUE;
|
lefTech = TRUE;
|
||||||
else if (!strncmp(cmd->tx_argv[i], "-hide", 5))
|
else if (!strncmp(cmd->tx_argv[i], "-hide", 5))
|
||||||
lefHide = TRUE;
|
lefHide = TRUE;
|
||||||
|
else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9))
|
||||||
|
lefTopLayer = TRUE;
|
||||||
else if (!strncmp(cmd->tx_argv[i], "-all", 4))
|
else if (!strncmp(cmd->tx_argv[i], "-all", 4))
|
||||||
recurse = TRUE;
|
recurse = TRUE;
|
||||||
else goto wrongNumArgs;
|
else goto wrongNumArgs;
|
||||||
}
|
}
|
||||||
else goto wrongNumArgs;
|
else goto wrongNumArgs;
|
||||||
}
|
}
|
||||||
LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, recurse);
|
LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefTopLayer,
|
||||||
|
recurse);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LEF_WRITE:
|
case LEF_WRITE:
|
||||||
|
|
@ -245,6 +252,13 @@ CmdLef(w, cmd)
|
||||||
else
|
else
|
||||||
TxPrintf("The \"-hide\" option is only for lef write\n");
|
TxPrintf("The \"-hide\" option is only for lef write\n");
|
||||||
}
|
}
|
||||||
|
else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9))
|
||||||
|
{
|
||||||
|
if (is_lef)
|
||||||
|
lefTopLayer = TRUE;
|
||||||
|
else
|
||||||
|
TxPrintf("The \"-toplayer\" option is only for lef write\n");
|
||||||
|
}
|
||||||
else if (!strncmp(cmd->tx_argv[i], "-units", 5))
|
else if (!strncmp(cmd->tx_argv[i], "-units", 5))
|
||||||
{
|
{
|
||||||
if (is_lef)
|
if (is_lef)
|
||||||
|
|
@ -284,7 +298,7 @@ CmdLef(w, cmd)
|
||||||
DefWriteCell(selectedUse->cu_def, namep, allSpecial, units);
|
DefWriteCell(selectedUse->cu_def, namep, allSpecial, units);
|
||||||
else
|
else
|
||||||
LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def
|
LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def
|
||||||
== EditRootDef, lefTech, lefHide);
|
== EditRootDef, lefTech, lefHide, lefTopLayer);
|
||||||
break;
|
break;
|
||||||
case LEF_HELP:
|
case LEF_HELP:
|
||||||
wrongNumArgs:
|
wrongNumArgs:
|
||||||
|
|
|
||||||
|
|
@ -503,7 +503,12 @@ lefEraseGeometry(tile, cdata)
|
||||||
ttype = otype;
|
ttype = otype;
|
||||||
|
|
||||||
/* Erase the tile area out of lefFlat */
|
/* Erase the tile area out of lefFlat */
|
||||||
DBErase(flatDef, &area, ttype);
|
/* Use DBNMPaintPlane, NOT DBErase(). This erases contacts one */
|
||||||
|
/* plane at a time, which normally is bad, but since every plane */
|
||||||
|
/* gets erased eventually during "lef write", this is okay. */
|
||||||
|
/* DBErase(flatDef, &area, ttype); */
|
||||||
|
DBNMPaintPlane(flatDef->cd_planes[lefdata->pNum], otype, &area,
|
||||||
|
DBStdEraseTbl(ttype, lefdata->pNum), NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -563,6 +568,25 @@ lefAccumulateArea(tile, cdata)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* lefFindTopmost --
|
||||||
|
*
|
||||||
|
* Function called to find the topmost layer used by a pin network
|
||||||
|
*
|
||||||
|
* Return 0 to keep the search going.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
lefFindTopmost(tile, cdata)
|
||||||
|
Tile *tile;
|
||||||
|
ClientData cdata;
|
||||||
|
{
|
||||||
|
return 1; /* Stop processing on the first tile found */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -630,7 +654,7 @@ lefYankGeometry(tile, cdata)
|
||||||
while (ttype < DBNumUserLayers)
|
while (ttype < DBNumUserLayers)
|
||||||
{
|
{
|
||||||
lefMagicToLefLayer = lefdata->lefMagicMap;
|
lefMagicToLefLayer = lefdata->lefMagicMap;
|
||||||
if (lefMagicToLefLayer[ttype].lefInfo != NULL)
|
if (lefMagicToLefLayer[ttype].lefName != NULL)
|
||||||
{
|
{
|
||||||
if (IsSplit(tile))
|
if (IsSplit(tile))
|
||||||
// Set only the side being yanked
|
// Set only the side being yanked
|
||||||
|
|
@ -793,7 +817,7 @@ lefWriteGeometry(tile, cdata)
|
||||||
lefdata->numWrites++;
|
lefdata->numWrites++;
|
||||||
|
|
||||||
if (ttype != lefdata->lastType)
|
if (ttype != lefdata->lastType)
|
||||||
if (lefMagicToLefLayer[ttype].lefInfo != NULL)
|
if (lefMagicToLefLayer[ttype].lefName != NULL)
|
||||||
{
|
{
|
||||||
fprintf(f, IN2 "LAYER %s ;\n",
|
fprintf(f, IN2 "LAYER %s ;\n",
|
||||||
lefMagicToLefLayer[ttype].lefName);
|
lefMagicToLefLayer[ttype].lefName);
|
||||||
|
|
@ -1064,11 +1088,12 @@ LefWritePinHeader(f, lab)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
lefWriteMacro(def, f, scale, hide)
|
lefWriteMacro(def, f, scale, hide, toplayer)
|
||||||
CellDef *def; /* Def for which to generate LEF output */
|
CellDef *def; /* Def for which to generate LEF output */
|
||||||
FILE *f; /* Output to this file */
|
FILE *f; /* Output to this file */
|
||||||
float scale; /* Output distance units conversion factor */
|
float scale; /* Output distance units conversion factor */
|
||||||
bool hide; /* If TRUE, hide all detail except pins */
|
bool hide; /* If TRUE, hide all detail except pins */
|
||||||
|
bool toplayer; /* If TRUE, only output topmost layer of pins */
|
||||||
{
|
{
|
||||||
bool propfound, ispwrrail;
|
bool propfound, ispwrrail;
|
||||||
char *propvalue, *class = NULL;
|
char *propvalue, *class = NULL;
|
||||||
|
|
@ -1080,7 +1105,7 @@ lefWriteMacro(def, f, scale, hide)
|
||||||
TileTypeBitMask lmask, boundmask, *lrmask, gatetypemask, difftypemask;
|
TileTypeBitMask lmask, boundmask, *lrmask, gatetypemask, difftypemask;
|
||||||
TileType ttype;
|
TileType ttype;
|
||||||
lefClient lc;
|
lefClient lc;
|
||||||
int idx, pNum, maxport, curport;
|
int idx, pNum, pTop, maxport, curport;
|
||||||
char leffmt[2][10];
|
char leffmt[2][10];
|
||||||
char *LEFtext;
|
char *LEFtext;
|
||||||
HashSearch hs;
|
HashSearch hs;
|
||||||
|
|
@ -1410,6 +1435,17 @@ lefWriteMacro(def, f, scale, hide)
|
||||||
if (antdiffarea > 0) break;
|
if (antdiffarea > 0) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toplayer)
|
||||||
|
{
|
||||||
|
for (pTop = DBNumPlanes - 1; pTop >= PL_TECHDEPBASE; pTop--)
|
||||||
|
{
|
||||||
|
if (DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pTop],
|
||||||
|
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||||
|
lefFindTopmost, (ClientData)NULL) == 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For all geometry in the selection, write LEF records,
|
// For all geometry in the selection, write LEF records,
|
||||||
// and mark the corresponding tiles in lefFlatDef as
|
// and mark the corresponding tiles in lefFlatDef as
|
||||||
// visited.
|
// visited.
|
||||||
|
|
@ -1418,6 +1454,11 @@ lefWriteMacro(def, f, scale, hide)
|
||||||
lc.lastType = TT_SPACE;
|
lc.lastType = TT_SPACE;
|
||||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||||
{
|
{
|
||||||
|
/* Option to output only the topmost layer of a network */
|
||||||
|
/* as PIN geometry. All layers below it are considered */
|
||||||
|
/* obstructions. */
|
||||||
|
if (toplayer) pNum = pTop;
|
||||||
|
|
||||||
lc.pNum = pNum;
|
lc.pNum = pNum;
|
||||||
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
|
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
|
||||||
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||||
|
|
@ -1458,6 +1499,8 @@ lefWriteMacro(def, f, scale, hide)
|
||||||
&TiPlaneRect, &lc.rmask,
|
&TiPlaneRect, &lc.rmask,
|
||||||
lefWriteGeometry, (ClientData) &lc);
|
lefWriteGeometry, (ClientData) &lc);
|
||||||
lc.lefMode = LEF_MODE_PORT;
|
lc.lefMode = LEF_MODE_PORT;
|
||||||
|
|
||||||
|
if (toplayer) break; /* Stop after processing topmost layer */
|
||||||
}
|
}
|
||||||
DBCellClearDef(lc.lefYank);
|
DBCellClearDef(lc.lefYank);
|
||||||
lab->lab_flags |= PORT_VISITED;
|
lab->lab_flags |= PORT_VISITED;
|
||||||
|
|
@ -1777,11 +1820,12 @@ lefGetProperties(stackItem, i, clientData)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, recurse)
|
LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, recurse)
|
||||||
CellUse *rootUse;
|
CellUse *rootUse;
|
||||||
bool writeTopCell;
|
bool writeTopCell;
|
||||||
bool lefTech;
|
bool lefTech;
|
||||||
bool lefHide;
|
bool lefHide;
|
||||||
|
bool lefTopLayer;
|
||||||
bool recurse;
|
bool recurse;
|
||||||
{
|
{
|
||||||
HashTable propHashTbl, siteHashTbl;
|
HashTable propHashTbl, siteHashTbl;
|
||||||
|
|
@ -1847,7 +1891,7 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, recurse)
|
||||||
{
|
{
|
||||||
def->cd_client = (ClientData) 0;
|
def->cd_client = (ClientData) 0;
|
||||||
if (!SigInterruptPending)
|
if (!SigInterruptPending)
|
||||||
lefWriteMacro(def, f, scale, lefHide);
|
lefWriteMacro(def, f, scale, lefHide, lefTopLayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End the LEF file */
|
/* End the LEF file */
|
||||||
|
|
@ -1911,12 +1955,13 @@ lefDefPushFunc(use, recurse)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
LefWriteCell(def, outName, isRoot, lefTech, lefHide)
|
LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer)
|
||||||
CellDef *def; /* Cell being written */
|
CellDef *def; /* Cell being written */
|
||||||
char *outName; /* Name of output file, or NULL. */
|
char *outName; /* Name of output file, or NULL. */
|
||||||
bool isRoot; /* Is this the root cell? */
|
bool isRoot; /* Is this the root cell? */
|
||||||
bool lefTech; /* Output layer information if TRUE */
|
bool lefTech; /* Output layer information if TRUE */
|
||||||
bool lefHide; /* Hide detail other than pins if TRUE */
|
bool lefHide; /* Hide detail other than pins if TRUE */
|
||||||
|
bool lefTopLayer; /* Use only topmost layer of pin if TRUE */
|
||||||
{
|
{
|
||||||
char *filename;
|
char *filename;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
@ -1950,7 +1995,7 @@ LefWriteCell(def, outName, isRoot, lefTech, lefHide)
|
||||||
HashKill(&propHashTbl);
|
HashKill(&propHashTbl);
|
||||||
HashKill(&siteHashTbl);
|
HashKill(&siteHashTbl);
|
||||||
}
|
}
|
||||||
lefWriteMacro(def, f, scale, lefHide);
|
lefWriteMacro(def, f, scale, lefHide, lefTopLayer);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue