From 898783467c58c7a27893be96d22624765e22c9bc Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 12 Nov 2021 11:34:16 -0500 Subject: [PATCH] Corrected the "lef write" routine to more correctly handle port statements, with all "hard" connections being enumerated in the same PORT entry, and "soft" connections (same label on unconnected areas; e.g., through substrate or resistor device) being enumerated as separate PORT entries, per the LEF spec. Also corrected behavior with respect to the "lef write -toplayer" option, which was treating each port label independently, and so generating entries for lower layers of a port if there were ports on those layers, in contravention to the "-toplayer" option. Also: Added the PINS section to the "def write" output; this had been left as a "to be completed" item but was never done in spite of being easy to add. --- VERSION | 2 +- lef/defWrite.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++- lef/lefWrite.c | 29 ++++++++++- 3 files changed, 163 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index fb3062c5..77bf3043 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.226 +8.3.227 diff --git a/lef/defWrite.c b/lef/defWrite.c index fcba26d2..08c58a04 100644 --- a/lef/defWrite.c +++ b/lef/defWrite.c @@ -1761,6 +1761,135 @@ defCountCompFunc(cellUse, total) return 0; /* Keep the search going */ } +/* + *------------------------------------------------------------ + * + * defCountPins -- + * + * First-pass function to count the number of pins + * to be written to the DEF output file. + * + * Results: + * The total number of pins to be written. + * + * Side Effects: + * None. + * + *------------------------------------------------------------ + */ + +int +defCountPins(rootDef) + CellDef *rootDef; +{ + int total; + Label *lab; + + TxPrintf("Diagnostic: Finding all pins of cell %s\n", rootDef->cd_name); + + total = 0; + for (lab = rootDef->cd_labels; lab; lab = lab->lab_next) + if (lab->lab_flags & PORT_DIR_MASK) + total++; + + return total; +} + +/* + *------------------------------------------------------------ + * + * defWritePins -- + * + * Output the PINS section of the DEF file. This + * is a listing of all ports, their placement, and + * name. + * + * Results: + * None. + * + * Side Effects: + * Output to the DEF file. + * + *------------------------------------------------------------ + */ + +void +defWritePins(f, rootDef, oscale) + FILE *f; /* File to write to */ + CellDef *rootDef; /* Cell definition to use */ + float oscale; /* Output scale factor */ +{ + Label *lab; + int lwidth, lheight; + int dcenterx, dcentery; + + for (lab = rootDef->cd_labels; lab; lab = lab->lab_next) + { + if (lab->lab_flags & PORT_DIR_MASK) + { + fprintf(f, " - %s + NET %s\n", lab->lab_text, lab->lab_text); + if (lab->lab_flags & PORT_CLASS_MASK) + { + fprintf(f, " + DIRECTION "); + switch (lab->lab_flags & PORT_CLASS_MASK) + { + case PORT_CLASS_INPUT: + fprintf(f, "INPUT"); + break; + case PORT_CLASS_OUTPUT: + fprintf(f, "OUTPUT"); + break; + case PORT_CLASS_TRISTATE: + case PORT_CLASS_BIDIRECTIONAL: + fprintf(f, "INOUT"); + break; + case PORT_CLASS_FEEDTHROUGH: + fprintf(f, "FEEDTHRU"); + break; + } + fprintf(f, "\n"); + } + if (lab->lab_flags & PORT_USE_MASK) + { + fprintf(f, " + USE "); + switch (lab->lab_flags & PORT_USE_MASK) + { + case PORT_USE_SIGNAL: + fprintf(f, "SIGNAL"); + break; + case PORT_USE_ANALOG: + fprintf(f, "ANALOG"); + break; + case PORT_USE_POWER: + fprintf(f, "POWER"); + break; + case PORT_USE_GROUND: + fprintf(f, "GROUND"); + break; + case PORT_USE_CLOCK: + fprintf(f, "CLOCK"); + break; + } + fprintf(f, "\n"); + } + + lwidth = lab->lab_rect.r_xtop - lab->lab_rect.r_xbot; + lheight = lab->lab_rect.r_ytop - lab->lab_rect.r_ybot; + + dcenterx = lab->lab_rect.r_xtop + lab->lab_rect.r_xbot; + dcentery = lab->lab_rect.r_ytop + lab->lab_rect.r_ybot; + + fprintf(f, " + PORT\n"); + fprintf(f, " + LAYER %s ( %.10g %.10g ) ( %.10g %.10g )", + DBTypeLongNameTbl[lab->lab_type], + oscale * (float)(-lwidth) / 2.0, oscale * (float)(-lheight) / 2.0, + oscale * (float)lwidth / 2.0, oscale * (float)lheight / 2.0); + fprintf(f, " + PLACED ( %.10g %.10g ) N ;\n", + oscale * (float)dcenterx / 2.0, oscale * (float)dcentery / 2.0); + } + } +} + /* *------------------------------------------------------------ * @@ -1996,7 +2125,11 @@ DefWriteCell(def, outName, allSpecial, units) fprintf(f, "END COMPONENTS\n\n"); /* Pins---assume no pins (for now) */ - fprintf(f, "PINS 0 ;\nEND PINS\n\n"); + total = defCountPins(def); + fprintf(f, "PINS %d ;\n", total); + if (total > 0) + defWritePins(f, def, scale); + fprintf(f, "END PINS\n\n"); /* Count the number of nets and "special" nets */ nets = defCountNets(def, allSpecial); diff --git a/lef/lefWrite.c b/lef/lefWrite.c index e23a2d0f..d32818fe 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -1602,10 +1602,37 @@ lefWriteMacro(def, f, scale, setback, pinonly, toplayer, domaster) lefWriteGeometry, (ClientData) &lc); lc.lefMode = LEF_MODE_PORT; } + + /* Check if any other ports are already contained in this selection. */ + /* If so, mark them as visited. Use lefFindTopmost(), which is just a */ + /* routine that stops the search by returning 1 when something is found */ + + for (tlab = lab->lab_next; tlab != (Label *)NULL; tlab = tlab->lab_next) + if (tlab->lab_flags & PORT_DIR_MASK) + if (!(tlab->lab_flags & PORT_VISITED)) + if ((tlab->lab_flags & PORT_NUM_MASK) == idx) + { + TileTypeBitMask lmask; + TTMaskSetOnlyType(&lmask, tlab->lab_type); + pNum = DBPlane(tlab->lab_type); + if (DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum], + &tlab->lab_rect, &lmask, + lefFindTopmost, (ClientData)NULL)) + tlab->lab_flags |= PORT_VISITED; + + /* For the "toplayer" option, ports on lower layers will not be */ + /* in the yank buffer but will still be in the selection. */ + else if (toplayer) + if (DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum], + &tlab->lab_rect, &lmask, + lefFindTopmost, (ClientData)NULL)) + tlab->lab_flags |= PORT_VISITED; + } + DBCellClearDef(lc.lefYank); lab->lab_flags |= PORT_VISITED; - /* Check if any other ports belong to this pin */ + /* Check if any other unvisited ports belong to this pin */ for (; lab != NULL; lab = lab->lab_next) if (lab->lab_flags & PORT_DIR_MASK)