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:
Tim Edwards 2020-03-14 13:00:03 -04:00
parent ea339ba367
commit 4f8ac38b27
1 changed files with 97 additions and 60 deletions

View File

@ -361,6 +361,10 @@ lefGetBound(tile, cdata)
Rect area; Rect area;
TiToRect(tile, &area); TiToRect(tile, &area);
if (boundary->r_xtop <= boundary->r_xbot)
*boundary = area;
else
GeoInclude(&area, boundary); 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,6 +929,11 @@ 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. */
reflab = lab;
while (lab != NULL)
{
labr = lab->lab_rect; labr = lab->lab_rect;
/* Deal with degenerate (line or point) labels */ /* Deal with degenerate (line or point) labels */
@ -985,14 +995,24 @@ lefWriteMacro(def, f, scale, hide)
lefEraseGeometry, (ClientData) &lc); lefEraseGeometry, (ClientData) &lc);
} }
DBCellClearDef(lc.lefYank); 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) if (lc.numWrites > 0)
fprintf(f, " END\n"); /* end of port geometries */ fprintf(f, " END\n"); /* end of port geometries */
lab->lab_flags |= PORT_VISITED; lc.numWrites = 0;
}
LEFtext = MakeLegalLEFSyntax(lab->lab_text); LEFtext = MakeLegalLEFSyntax(reflab->lab_text);
fprintf(f, " END %s\n", lab->lab_text); /* end of pin */ fprintf(f, " END %s\n", reflab->lab_text); /* end of pin */
if (LEFtext != lab->lab_text) freeMagic(LEFtext); if (LEFtext != reflab->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)