Substantially enhanced the "lef write" methods. This now preserves
multiple ports; also, when using the "-hide" option, the obstruction area is computed from layer geometry, not from the bounding box. Still left to do: Ensure minimum width on pins, and remove slivers of obstruction that are below minimum width.
This commit is contained in:
parent
ea339ba367
commit
4f8ac38b27
157
lef/lefWrite.c
157
lef/lefWrite.c
|
|
@ -361,7 +361,11 @@ lefGetBound(tile, cdata)
|
||||||
Rect area;
|
Rect area;
|
||||||
|
|
||||||
TiToRect(tile, &area);
|
TiToRect(tile, &area);
|
||||||
GeoInclude(&area, boundary);
|
|
||||||
|
if (boundary->r_xtop <= boundary->r_xbot)
|
||||||
|
*boundary = area;
|
||||||
|
else
|
||||||
|
GeoInclude(&area, boundary);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -641,7 +645,7 @@ lefWriteMacro(def, f, scale, hide)
|
||||||
{
|
{
|
||||||
bool propfound;
|
bool propfound;
|
||||||
char *propvalue, *class = NULL;
|
char *propvalue, *class = NULL;
|
||||||
Label *lab, *tlab;
|
Label *lab, *tlab, *reflab;
|
||||||
Rect boundary, labr;
|
Rect boundary, labr;
|
||||||
SearchContext scx;
|
SearchContext scx;
|
||||||
CellDef *lefFlatDef;
|
CellDef *lefFlatDef;
|
||||||
|
|
@ -771,8 +775,9 @@ lefWriteMacro(def, f, scale, hide)
|
||||||
|
|
||||||
if (!TTMaskIsZero(&boundmask))
|
if (!TTMaskIsZero(&boundmask))
|
||||||
{
|
{
|
||||||
|
boundary.r_xbot = boundary.r_xtop = 0;
|
||||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||||
DBSrPaintArea((Tile *)NULL, def->cd_planes[pNum],
|
DBSrPaintArea((Tile *)NULL, lefFlatUse.cu_def->cd_planes[pNum],
|
||||||
&TiPlaneRect, &boundmask, lefGetBound,
|
&TiPlaneRect, &boundmask, lefGetBound,
|
||||||
(ClientData)(&boundary));
|
(ClientData)(&boundary));
|
||||||
}
|
}
|
||||||
|
|
@ -924,75 +929,90 @@ lefWriteMacro(def, f, scale, hide)
|
||||||
/* Note: Use DBIsContact() to check if the layer is a VIA. */
|
/* Note: Use DBIsContact() to check if the layer is a VIA. */
|
||||||
/* Presently, I am treating contacts like any other layer. */
|
/* Presently, I am treating contacts like any other layer. */
|
||||||
|
|
||||||
labr = lab->lab_rect;
|
reflab = lab;
|
||||||
|
|
||||||
/* Deal with degenerate (line or point) labels */
|
while (lab != NULL)
|
||||||
/* by growing by 1 in each direction. */
|
|
||||||
|
|
||||||
if (labr.r_xtop - labr.r_xbot == 0)
|
|
||||||
{
|
{
|
||||||
labr.r_xtop++;
|
|
||||||
labr.r_xbot--;
|
|
||||||
}
|
|
||||||
if (labr.r_ytop - labr.r_ybot == 0)
|
|
||||||
{
|
|
||||||
labr.r_ytop++;
|
|
||||||
labr.r_ybot--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid errors caused by labels attached to space or
|
labr = lab->lab_rect;
|
||||||
// various technology file issues.
|
|
||||||
TTMaskClearType(&lc.rmask, TT_SPACE);
|
|
||||||
|
|
||||||
scx.scx_area = labr;
|
/* Deal with degenerate (line or point) labels */
|
||||||
SelectClear();
|
/* by growing by 1 in each direction. */
|
||||||
|
|
||||||
if (hide)
|
if (labr.r_xtop - labr.r_xbot == 0)
|
||||||
{
|
{
|
||||||
SelectChunk(&scx, lab->lab_type, 0, NULL, FALSE);
|
labr.r_xtop++;
|
||||||
|
labr.r_xbot--;
|
||||||
|
}
|
||||||
|
if (labr.r_ytop - labr.r_ybot == 0)
|
||||||
|
{
|
||||||
|
labr.r_ytop++;
|
||||||
|
labr.r_ybot--;
|
||||||
|
}
|
||||||
|
|
||||||
/* Note that a sticky label could be placed over multiple */
|
// Avoid errors caused by labels attached to space or
|
||||||
/* tile types, which would cause SelectChunk to fail. So */
|
// various technology file issues.
|
||||||
/* always paint the label type into the label area in */
|
TTMaskClearType(&lc.rmask, TT_SPACE);
|
||||||
/* SelectDef. */
|
|
||||||
|
|
||||||
pNum = DBPlane(lab->lab_type);
|
scx.scx_area = labr;
|
||||||
DBPaintPlane(SelectDef->cd_planes[pNum], &lab->lab_rect,
|
SelectClear();
|
||||||
DBStdPaintTbl(lab->lab_type, pNum), (PaintUndoInfo *) NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SelectNet(&scx, lab->lab_type, 0, NULL, FALSE);
|
|
||||||
|
|
||||||
// For all geometry in the selection, write LEF records,
|
if (hide)
|
||||||
// and mark the corresponding tiles in lefFlatDef as
|
{
|
||||||
// visited.
|
SelectChunk(&scx, lab->lab_type, 0, NULL, FALSE);
|
||||||
|
|
||||||
lc.numWrites = 0;
|
/* Note that a sticky label could be placed over multiple */
|
||||||
lc.lastType = TT_SPACE;
|
/* tile types, which would cause SelectChunk to fail. So */
|
||||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
/* always paint the label type into the label area in */
|
||||||
{
|
/* SelectDef. */
|
||||||
lc.pNum = pNum;
|
|
||||||
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
|
pNum = DBPlane(lab->lab_type);
|
||||||
|
DBPaintPlane(SelectDef->cd_planes[pNum], &lab->lab_rect,
|
||||||
|
DBStdPaintTbl(lab->lab_type, pNum), (PaintUndoInfo *) NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SelectNet(&scx, lab->lab_type, 0, NULL, FALSE);
|
||||||
|
|
||||||
|
// For all geometry in the selection, write LEF records,
|
||||||
|
// and mark the corresponding tiles in lefFlatDef as
|
||||||
|
// visited.
|
||||||
|
|
||||||
|
lc.numWrites = 0;
|
||||||
|
lc.lastType = TT_SPACE;
|
||||||
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||||
|
{
|
||||||
|
lc.pNum = pNum;
|
||||||
|
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
|
||||||
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||||
lefYankGeometry, (ClientData) &lc);
|
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);
|
||||||
|
|
||||||
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
|
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
|
||||||
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||||
lefEraseGeometry, (ClientData) &lc);
|
lefEraseGeometry, (ClientData) &lc);
|
||||||
|
}
|
||||||
|
DBCellClearDef(lc.lefYank);
|
||||||
|
lab->lab_flags |= PORT_VISITED;
|
||||||
|
|
||||||
|
/* Check if any other ports belong to this pin */
|
||||||
|
|
||||||
|
for (; lab != NULL; lab = lab->lab_next)
|
||||||
|
if (lab->lab_flags & PORT_DIR_MASK)
|
||||||
|
if (!(lab->lab_flags & PORT_VISITED))
|
||||||
|
if ((lab->lab_flags & PORT_NUM_MASK) == idx)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (lc.numWrites > 0)
|
||||||
|
fprintf(f, " END\n"); /* end of port geometries */
|
||||||
|
lc.numWrites = 0;
|
||||||
}
|
}
|
||||||
DBCellClearDef(lc.lefYank);
|
|
||||||
|
|
||||||
if (lc.numWrites > 0)
|
LEFtext = MakeLegalLEFSyntax(reflab->lab_text);
|
||||||
fprintf(f, " END\n"); /* end of port geometries */
|
fprintf(f, " END %s\n", reflab->lab_text); /* end of pin */
|
||||||
lab->lab_flags |= PORT_VISITED;
|
if (LEFtext != reflab->lab_text) freeMagic(LEFtext);
|
||||||
|
|
||||||
LEFtext = MakeLegalLEFSyntax(lab->lab_text);
|
|
||||||
fprintf(f, " END %s\n", lab->lab_text); /* end of pin */
|
|
||||||
if (LEFtext != lab->lab_text) freeMagic(LEFtext);
|
|
||||||
|
|
||||||
if (maxport >= 0)
|
if (maxport >= 0)
|
||||||
{
|
{
|
||||||
|
|
@ -1001,20 +1021,20 @@ lefWriteMacro(def, f, scale, hide)
|
||||||
/* is perfectly legal to have multiple ports with the same */
|
/* is perfectly legal to have multiple ports with the same */
|
||||||
/* name and index. */
|
/* name and index. */
|
||||||
|
|
||||||
for (tlab = lab->lab_next; tlab != NULL; tlab = tlab->lab_next)
|
for (tlab = reflab->lab_next; tlab != NULL; tlab = tlab->lab_next)
|
||||||
{
|
{
|
||||||
if (tlab->lab_flags & PORT_DIR_MASK)
|
if (tlab->lab_flags & PORT_DIR_MASK)
|
||||||
if ((tlab->lab_flags & PORT_NUM_MASK) == idx)
|
if ((tlab->lab_flags & PORT_NUM_MASK) == idx)
|
||||||
if (strcmp(lab->lab_text, lab->lab_text))
|
if (strcmp(reflab->lab_text, tlab->lab_text))
|
||||||
{
|
{
|
||||||
TxError("Index %d is used for ports \"%s\" and \"%s\"\n",
|
TxError("Index %d is used for ports \"%s\" and \"%s\"\n",
|
||||||
idx, lab->lab_text, tlab->lab_text);
|
idx, reflab->lab_text, tlab->lab_text);
|
||||||
idx--;
|
idx--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
lab = lab->lab_next;
|
lab = reflab->lab_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear all PORT_VISITED bits in labels */
|
/* Clear all PORT_VISITED bits in labels */
|
||||||
|
|
@ -1025,7 +1045,6 @@ lefWriteMacro(def, f, scale, hide)
|
||||||
/* List of routing obstructions */
|
/* List of routing obstructions */
|
||||||
|
|
||||||
lc.lefMode = LEF_MODE_OBSTRUCT;
|
lc.lefMode = LEF_MODE_OBSTRUCT;
|
||||||
lc.numWrites = 0;
|
|
||||||
lc.lastType = TT_SPACE;
|
lc.lastType = TT_SPACE;
|
||||||
|
|
||||||
/* Restrict to routing planes only */
|
/* Restrict to routing planes only */
|
||||||
|
|
@ -1037,11 +1056,29 @@ lefWriteMacro(def, f, scale, hide)
|
||||||
/* the cell bounding box. Then recompute the label chunk */
|
/* the cell bounding box. Then recompute the label chunk */
|
||||||
/* regions used above to write the ports, expand each chunk by */
|
/* regions used above to write the ports, expand each chunk by */
|
||||||
/* the route metal spacing width, and erase that area from the */
|
/* the route metal spacing width, and erase that area from the */
|
||||||
/* obstruction. */
|
/* obstruction. For the obstruction boundary, find the extent */
|
||||||
|
/* of paint on the layer, not the LEF macro boundary, since */
|
||||||
|
/* paint may extend beyond the boundary, and sometimes the */
|
||||||
|
/* boundary may extend beyond the paint. To be done: make */
|
||||||
|
/* sure that every pin has a legal path to the outside of the */
|
||||||
|
/* cell. Otherwise, this routine can block internal pins. */
|
||||||
|
|
||||||
|
Rect layerBound;
|
||||||
|
|
||||||
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
|
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
|
||||||
if (TTMaskHasType(&lmask, ttype))
|
if (TTMaskHasType(&lmask, ttype))
|
||||||
DBPaint(lc.lefYank, &boundary, ttype);
|
{
|
||||||
|
layerBound.r_xbot = layerBound.r_xtop = 0;
|
||||||
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||||
|
if (TTMaskHasType(&DBPlaneTypes[pNum], ttype))
|
||||||
|
{
|
||||||
|
DBSrPaintArea((Tile *)NULL, lefFlatUse.cu_def->cd_planes[pNum],
|
||||||
|
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||||
|
lefGetBound, (ClientData)(&layerBound));
|
||||||
|
}
|
||||||
|
|
||||||
|
DBPaint(lc.lefYank, &layerBound, ttype);
|
||||||
|
}
|
||||||
|
|
||||||
scx.scx_use = &lefSourceUse;
|
scx.scx_use = &lefSourceUse;
|
||||||
for (lab = def->cd_labels; lab != NULL; lab = lab->lab_next)
|
for (lab = def->cd_labels; lab != NULL; lab = lab->lab_next)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue