Added new option "-hide" to the "lef write" command, which causes

the output to have an obstruction area over the entire cell except
for a keep-out area around each pin.  Instead of marking every
part of the pin geometry, only the "chunk" (largest immediate
rectangle) surrounding the port label is output as part of port
LEF geometry.  This avoids making unnecessarily complicated
abstract views, and makes it easier for other tools to read and
manage the same abstract views.
This commit is contained in:
Tim Edwards 2018-11-19 15:01:20 -05:00
parent f756825828
commit 17227ee427
3 changed files with 120 additions and 25 deletions

View File

@ -141,6 +141,7 @@ int calmaPaintLayerType;
* Hash table used to determine which GDS libraries have been output * Hash table used to determine which GDS libraries have been output
*/ */
HashTable calmaLibHash; HashTable calmaLibHash;
HashTable calmaPrefixHash;
/* Imports */ /* Imports */
extern time_t time(); extern time_t time();
@ -292,6 +293,7 @@ CalmaWrite(rootDef, f)
} }
HashInit(&calmaLibHash, 32, 0); HashInit(&calmaLibHash, 32, 0);
HashInit(&calmaPrefixHash, 32, 0);
/* /*
* Make sure that the entire hierarchy rooted at rootDef is * Make sure that the entire hierarchy rooted at rootDef is
@ -343,6 +345,7 @@ CalmaWrite(rootDef, f)
if (CalmaContactArrays) calmaDelContacts(); if (CalmaContactArrays) calmaDelContacts();
HashFreeKill(&calmaLibHash); HashFreeKill(&calmaLibHash);
HashKill(&calmaPrefixHash);
return (good); return (good);
} }
@ -596,7 +599,7 @@ calmaFullDump(def, fi, cellstart, outf, filename)
char *filename; char *filename;
{ {
int version, rval, i; int version, rval, i;
char *libname = NULL, uniqlibname[5]; char *libname = NULL, uniqlibname[3];
char *sptr; char *sptr;
HashTable calmaDefHash; HashTable calmaDefHash;
HashEntry *he; HashEntry *he;
@ -626,15 +629,32 @@ calmaFullDump(def, fi, cellstart, outf, filename)
// Record the GDS library so it will not be processed again. // Record the GDS library so it will not be processed again.
he = HashFind(&calmaLibHash, filename); he = HashFind(&calmaLibHash, filename);
// Generate a SHORT name for this cell (else it is easy to run into the
// GDS 32-character cellname limit). Save it in the hash record. /* Generate a SHORT name for this cell (else it is easy to run into the
for (i = 0; i < 4; i++) { * GDS 32-character cellname limit). Save it in the hash record. The
rval = random() % 62; * chance of generating the same prefix for a library that has items
rval = (rval < 26) ? ('A' + rval) : ((rval < 52) ? ('a' + rval - 26) : * with conflicting names is vanishingly small, but to be pedantic, store
* the prefix in a hash table and check to make sure that uniqueness is
* ensured.
*/
while (TRUE)
{
HashEntry *he2;
for (i = 0; i < 2; i++) {
rval = random() % 62;
rval = (rval < 26) ? ('A' + rval) : ((rval < 52) ? ('a' + rval - 26) :
('0' + rval - 52)); ('0' + rval - 52));
uniqlibname[i] = (char)(rval & 127); uniqlibname[i] = (char)(rval & 127);
}
uniqlibname[2] = '\0';
he2 = HashLookOnly(&calmaPrefixHash, uniqlibname);
if (he2 == NULL)
{
he2 = HashFind(&calmaPrefixHash, uniqlibname);
break;
}
} }
uniqlibname[4] = '\0';
HashSetValue(he, StrDup(NULL, uniqlibname)); HashSetValue(he, StrDup(NULL, uniqlibname));
while (calmaDumpStructure(def, cellstart, outf, &calmaDefHash, filename)) while (calmaDumpStructure(def, cellstart, outf, &calmaDefHash, filename))

View File

@ -61,7 +61,7 @@ CmdLef(w, cmd)
MagWindow *w; MagWindow *w;
TxCommand *cmd; TxCommand *cmd;
{ {
int option, i; int option, i, cargs;
char **msg, *namep; char **msg, *namep;
CellUse *selectedUse; CellUse *selectedUse;
CellDef *selectedDef; CellDef *selectedDef;
@ -83,12 +83,17 @@ CmdLef(w, cmd)
* will be output along with the * will be output along with the
* lef macro. * lef macro.
*/ */
bool lefHide = FALSE; /* If TRUE, hide all details of
* the macro other than pin area
* immediately surrounding labels.
*/
static char *cmdLefOption[] = static char *cmdLefOption[] =
{ {
"read [filename] read a LEF file filename[.lef]\n" "read [filename] read a LEF file filename[.lef]\n"
" read [filename] -import read a LEF file; import cells from .mag files", " read [filename] -import read a LEF file; import cells from .mag files",
"write [filename] [-tech] write LEF for current cell", "write [filename] [-tech] write LEF for current cell\n"
" write [filename] -hide hide all details other than ports",
"writeall write all cells including the top-level cell\n" "writeall write all cells including the top-level cell\n"
" writeall -notop write all subcells of the top-level cell", " writeall -notop write all subcells of the top-level cell",
"help print this help information", "help print this help information",
@ -188,6 +193,7 @@ CmdLef(w, cmd)
break; break;
case LEF_WRITE: case LEF_WRITE:
allSpecial = FALSE; allSpecial = FALSE;
cargs = cmd->tx_argc;
for (i = 2; i < cmd->tx_argc; i++) for (i = 2; i < cmd->tx_argc; i++)
{ {
if (*(cmd->tx_argv[i]) == '-') if (*(cmd->tx_argv[i]) == '-')
@ -206,18 +212,26 @@ CmdLef(w, cmd)
else else
TxPrintf("The \"-tech\" option is only for lef write\n"); TxPrintf("The \"-tech\" option is only for lef write\n");
} }
else if (!strncmp(cmd->tx_argv[i], "-hide", 5))
{
if (is_lef)
lefHide = TRUE;
else
TxPrintf("The \"-hide\" option is only for def write\n");
}
else goto wrongNumArgs; else goto wrongNumArgs;
cargs--;
} }
else if (i != 2) /* Is argument a filename? */ else if (i != 2) /* Is argument a filename? */
goto wrongNumArgs; goto wrongNumArgs;
} }
if (cmd->tx_argc != 2 && cmd->tx_argc != 3) goto wrongNumArgs; if (cargs != 2 && cargs != 3) goto wrongNumArgs;
if (selectedUse == NULL) if (selectedUse == NULL)
{ {
TxError("No cell selected\n"); TxError("No cell selected\n");
return; return;
} }
if (cmd->tx_argc == 2) if (cargs == 2)
namep = selectedUse->cu_def->cd_name; namep = selectedUse->cu_def->cd_name;
else else
namep = cmd->tx_argv[2]; namep = cmd->tx_argv[2];
@ -225,7 +239,7 @@ CmdLef(w, cmd)
DefWriteCell(selectedUse->cu_def, namep, allSpecial); DefWriteCell(selectedUse->cu_def, namep, allSpecial);
else else
LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def
== EditRootDef, lefTech); == EditRootDef, lefTech, lefHide);
break; break;
case LEF_HELP: case LEF_HELP:
wrongNumArgs: wrongNumArgs:

View File

@ -625,10 +625,11 @@ MakeLegalLEFSyntax(text)
*/ */
void void
lefWriteMacro(def, f, scale) lefWriteMacro(def, f, scale, hide)
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 propfound; bool propfound;
char *propvalue, *class = NULL; char *propvalue, *class = NULL;
@ -689,6 +690,7 @@ lefWriteMacro(def, f, scale)
TTMaskZero(&lc.rmask); TTMaskZero(&lc.rmask);
TTMaskZero(&boundmask); TTMaskZero(&boundmask);
TTMaskZero(&lmask);
/* Any layer which has a port label attached to it should by */ /* Any layer which has a port label attached to it should by */
/* necessity be considered a routing layer. Usually this will not */ /* necessity be considered a routing layer. Usually this will not */
@ -711,6 +713,8 @@ lefWriteMacro(def, f, scale)
lrmask = DBResidueMask(lefl->type); lrmask = DBResidueMask(lefl->type);
TTMaskSetMask(&lc.rmask, lrmask); TTMaskSetMask(&lc.rmask, lrmask);
} }
if ((lefl->lefClass == CLASS_ROUTE) && (lefl->obsType != -1))
TTMaskSetType(&lmask, lefl->type);
} }
if (lefl->obsType != -1) if (lefl->obsType != -1)
TTMaskSetType(&lc.rmask, lefl->obsType); TTMaskSetType(&lc.rmask, lefl->obsType);
@ -909,16 +913,17 @@ lefWriteMacro(def, f, scale)
labr.r_ybot--; labr.r_ybot--;
} }
// TTMaskSetOnlyType(&lmask, lab->lab_type);
// Avoid errors caused by labels attached to space or // Avoid errors caused by labels attached to space or
// various technology file issues. // various technology file issues.
TTMaskClearType(&lc.rmask, TT_SPACE); TTMaskClearType(&lc.rmask, TT_SPACE);
ttype = TT_SPACE;
scx.scx_area = labr; scx.scx_area = labr;
SelectClear(); SelectClear();
SelectNet(&scx, lab->lab_type, 0, NULL, FALSE);
if (hide)
SelectChunk(&scx, lab->lab_type, 0, NULL, FALSE);
else
SelectNet(&scx, lab->lab_type, 0, NULL, FALSE);
// 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
@ -981,13 +986,68 @@ lefWriteMacro(def, f, scale)
/* Restrict to routing planes only */ /* Restrict to routing planes only */
if (hide)
{
/* If details of the cell are to be hidden, then first paint */
/* all route layers with an obstruction rectangle the size of */
/* the cell bounding box. Then recompute the label chunk */
/* regions used above to write the ports, expand each chunk by */
/* the route metal spacing width, and erase that area from the */
/* obstruction. */
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
if (TTMaskHasType(&lmask, ttype))
DBPaint(lc.lefYank, &boundary, ttype);
scx.scx_use = &lefSourceUse;
for (lab = def->cd_labels; lab != NULL; lab = lab->lab_next)
{
Rect carea;
int lspace;
labr = lab->lab_rect;
/* Force label area to be non-degenerate */
if (labr.r_xbot >= labr.r_xtop)
{
labr.r_xbot--;
labr.r_xtop++;
}
if (labr.r_ybot >= labr.r_ytop)
{
labr.r_ybot--;
labr.r_ytop++;
}
if (lab->lab_flags & PORT_DIR_MASK)
{
scx.scx_area = labr;
SelectClear();
SelectChunk(&scx, lab->lab_type, 0, &carea, FALSE);
lspace = DRCGetDefaultLayerSpacing(lab->lab_type, lab->lab_type);
carea.r_xbot -= lspace;
carea.r_ybot -= lspace;
carea.r_xtop += lspace;
carea.r_ytop += lspace;
DBErase(lc.lefYank, &carea, lab->lab_type);
}
}
}
else
{
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
lc.pNum = pNum;
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
lefYankGeometry, (ClientData) &lc);
}
}
/* Write all the geometry just generated */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{ {
lc.pNum = pNum;
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
lefYankGeometry, (ClientData) &lc);
DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum], DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum],
&TiPlaneRect, &lc.rmask, &TiPlaneRect, &lc.rmask,
lefWriteGeometry, (ClientData) &lc); lefWriteGeometry, (ClientData) &lc);
@ -1140,11 +1200,12 @@ lefDefPushFunc(use)
*/ */
void void
LefWriteCell(def, outName, isRoot, lefTech) LefWriteCell(def, outName, isRoot, lefTech, lefHide)
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 */
{ {
char *filename; char *filename;
FILE *f; FILE *f;
@ -1168,7 +1229,7 @@ LefWriteCell(def, outName, isRoot, lefTech)
if (isRoot) if (isRoot)
lefWriteHeader(def, f, lefTech); lefWriteHeader(def, f, lefTech);
lefWriteMacro(def, f, scale); lefWriteMacro(def, f, scale, lefHide);
fclose(f); fclose(f);
} }