From 6e83cbe2d3348971c6b4d95b6a28eb28d446a8d2 Mon Sep 17 00:00:00 2001 From: "R. Timothy Edwards" Date: Sat, 29 Mar 2025 15:46:23 -0400 Subject: [PATCH] Added handling of coordinates in a FOREIGN statement in a LEF macro. Based on observation of cells in PDKs where ORIGIN and/or FOREIGN are non-zero, added code that forces a correction of LEF macro coordinates to match the GDS coordinates, with an equivalent negative shift of the LEF macro ORIGIN to compensate. Normally, both ORIGIN and FOREIGN will be zero and the added code will do nothing. Note that this code does not handle the additional optional orientation. A LEF macro with a different coordinate system than its GDS is already weird; a LEF macro with a different rotation than its GDS is hopefully something that nobody ever does in practice. If needed, I'll cross that bridge when I come to it. --- VERSION | 2 +- lef/lefInt.h | 2 +- lef/lefRead.c | 59 +++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/VERSION b/VERSION index a512729b..3badea7c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.524 +8.3.525 diff --git a/lef/lefInt.h b/lef/lefInt.h index 1ab0d722..5aeebd1e 100644 --- a/lef/lefInt.h +++ b/lef/lefInt.h @@ -152,7 +152,7 @@ extern CellDef *lefFindCell(const char *name); extern const char *LefNextToken(FILE *f, bool ignore_eol); extern char *LefLower(char *token); extern TileType LefHelper_DBTechNameType_LefLower(const char *name); -extern LinkedRect *LefReadGeometry(CellDef *lefMacro, FILE *f, float oscale, bool do_list, bool is_imported); +extern LinkedRect *LefReadGeometry(CellDef *lefMacro, FILE *f, float oscale, Point *, bool do_list, bool is_imported); extern void LefEstimate(int processed, int total, const char *item_name); extern lefLayer *LefRedefined(lefLayer *lefl, const char *redefname); extern void LefAddViaGeometry(FILE *f, lefLayer *lefl, TileType curlayer, float oscale); diff --git a/lef/lefRead.c b/lef/lefRead.c index 6ad92144..cccee7fe 100644 --- a/lef/lefRead.c +++ b/lef/lefRead.c @@ -852,7 +852,9 @@ LefReadLayer( * return the two coordinates in LEF units (floating-point). * * Results: - * Return 0 on success, 1 on error. + * Return 0 on success, 1 on error. Return -1 if no + * coordinates are found in the input (used where + * coordinates may be optional). * * Side Effects: * Reads input from file f; @@ -878,6 +880,7 @@ LefReadLefPoint( bool needMatch = FALSE; token = LefNextToken(f, TRUE); + if (!token) return -1; if (*token == '(') { token = LefNextToken(f, TRUE); @@ -1019,6 +1022,7 @@ LefReadPolygon( FILE *f, TileType curlayer, float oscale, + Point *gdsOffset, int *ppoints) { LinkedRect *lr = NULL, *newRect; @@ -1056,8 +1060,8 @@ LefReadPolygon( /* as we read it in. */ newRect = (LinkedRect *)mallocMagic(sizeof(LinkedRect)); - newRect->r_r.r_xbot = (int)roundf(px / oscale); - newRect->r_r.r_ybot = (int)roundf(py / oscale); + newRect->r_r.r_xbot = (int)roundf(px / oscale) + gdsOffset->p_x; + newRect->r_r.r_ybot = (int)roundf(py / oscale) + gdsOffset->p_y; newRect->r_next = lr; lr = newRect; lpoints++; @@ -1222,6 +1226,7 @@ LefReadGeometry( CellDef *lefMacro, FILE *f, float oscale, + Point *gdsOffset, bool do_list, bool is_imported) { @@ -1276,6 +1281,11 @@ LefReadGeometry( paintrect = (curlayer < 0) ? NULL : LefReadRect(f, curlayer, oscale); if (paintrect) { + paintrect->r_xbot += gdsOffset->p_x; + paintrect->r_ybot += gdsOffset->p_y; + paintrect->r_xtop += gdsOffset->p_x; + paintrect->r_ytop += gdsOffset->p_y; + if (is_imported) { int pNum = DBPlane(curlayer); /* FIXME unused return value from call to function with no side-effects */ @@ -1346,7 +1356,7 @@ LefReadGeometry( LefEndStatement(f); break; case LEF_POLYGON: - pointList = LefReadPolygon(f, curlayer, oscale, &points); + pointList = LefReadPolygon(f, curlayer, oscale, gdsOffset, &points); if (pointList) { if (lefMacro) @@ -1428,13 +1438,14 @@ LefReadPort( int pinUse, int pinShape, float oscale, + Point *gdsOffset, bool is_imported, Label *lanno) { Label *newlab; LinkedRect *rectList; - rectList = LefReadGeometry(lefMacro, f, oscale, TRUE, is_imported); + rectList = LefReadGeometry(lefMacro, f, oscale, gdsOffset, TRUE, is_imported); while (rectList != NULL) { @@ -1549,6 +1560,7 @@ LefReadPin( char *pinname, int pinNum, float oscale, + Point *gdsOffset, bool is_imported) { const char *token; @@ -1815,7 +1827,7 @@ LefReadPin( DBEraseLabelsByContent(lefMacro, NULL, -1, testpin); LefReadPort(lefMacro, f, testpin, pinNum, pinDir, pinUse, - pinShape, oscale, TRUE, lab); + pinShape, oscale, gdsOffset, TRUE, lab); } else LefSkipSection(f, NULL); @@ -1823,7 +1835,7 @@ LefReadPin( } else LefReadPort(lefMacro, f, testpin, pinNum, pinDir, pinUse, - pinShape, oscale, FALSE, NULL); + pinShape, oscale, gdsOffset, FALSE, NULL); break; case LEF_CAPACITANCE: case LEF_ANTENNADIFF: @@ -2124,10 +2136,11 @@ LefReadMacro( const char *token; char tsave[128], *propval; - int keyword, pinNum, propsize; + int keyword, pinNum, propsize, result; float x, y; bool has_size, is_imported = FALSE, propfound; Rect lefBBox; + Point gdsOffset; /* Difference between GDS and LEF coordinates */ static const char * const macro_keys[] = { "CLASS", @@ -2203,6 +2216,8 @@ LefReadMacro( has_size = FALSE; lefBBox.r_xbot = 0; lefBBox.r_ybot = 0; + gdsOffset.p_x = 0; + gdsOffset.p_y = 0; while ((token = LefNextToken(f, TRUE)) != NULL) { @@ -2252,6 +2267,8 @@ size_error: lefBBox.r_xtop += lefBBox.r_xbot; lefBBox.r_ytop += lefBBox.r_ybot; } + gdsOffset.p_x += lefBBox.r_xbot; + gdsOffset.p_y += lefBBox.r_ybot; LefEndStatement(f); break; origin_error: @@ -2312,7 +2329,7 @@ origin_error: TxPrintf(" Macro defines pin %s\n", token); */ sprintf(tsave, "%.127s", token); - LefReadPin(lefMacro, f, tsave, pinNum++, oscale, is_imported); + LefReadPin(lefMacro, f, tsave, pinNum++, oscale, &gdsOffset, is_imported); break; case LEF_OBS: /* Diagnostic */ @@ -2322,18 +2339,28 @@ origin_error: if (is_imported) LefSkipSection(f, NULL); else - LefReadGeometry(lefMacro, f, oscale, FALSE, is_imported); + LefReadGeometry(lefMacro, f, oscale, &gdsOffset, FALSE, is_imported); break; case LEF_TIMING: LefSkipSection(f, macro_keys[LEF_TIMING]); break; case LEF_FOREIGN: + token = LefNextToken(f, TRUE); + sprintf(tsave, "%.127s", token); + + /* Read (optional) FOREIGN coordinate */ + result = LefReadLefPoint(f, &x, &y); + if (result == 1) goto origin_error; + else if (result == 0) + { + gdsOffset.p_x += -(int)roundf(x / oscale); + gdsOffset.p_y += -(int)roundf(y / oscale); + } if (importForeign) { - token = LefNextToken(f, TRUE); - sprintf(tsave, "%.127s", token); - - /* To do: Read and apply X and Y offsets */ + /* There is no behavioral difference when using + * importForiegn. + */ } LefEndStatement(f); break; @@ -2349,6 +2376,10 @@ origin_error: } /* Finish up creating the cell */ + lefBBox.r_xbot -= gdsOffset.p_x; + lefBBox.r_ybot -= gdsOffset.p_y; + lefBBox.r_xtop -= gdsOffset.p_x; + lefBBox.r_ytop -= gdsOffset.p_y; DBReComputeBbox(lefMacro); if (is_imported)