check_placement: padding check flags a legal cell above a fixed block whose bottom is in the upper half of a row
Maintainers usually reply within 1 day
@gudeh is already working on this.
Since Nov 2, 2026.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
Research direction
Read src/dpl/src/PlacementDRC.cpp around PlacementDRC::checkPadding(const Node* cell) and compare its row selection with Grid::gridSnapDownY in src/dpl/src/infrastructure/Grid.cpp. Reproduce with the supplied tech.lef, cells.lef, flagged.def and check.tcl, then run check_placement. Done when the legal cell above the fixed block passes while padding violations are still detected in covered rows.
Written by the indexing model from the issue text.
Description
Description
check_placement reports [WARNING DPL-0011] Padding check failed and then [ERROR DPL-0033] for a FIXED block
whose bottom edge lies in the upper half of a row and whose height is not a whole number of rows, when a standard
cell sits legally in the row just above the block's top edge. There is no overlap and no padding is set; in our flow
detailed_placement, run just before the check, reported Found 0 overlaps between adjacent cells and
0 padding violations.
The cause seems to be a mismatch in how rows are assigned to the block:
- The grid marks a block's rows from the row its bottom snaps down to (
Grid::gridSnapDownY, used when painting
pixels,src/dpl/src/infrastructure/Grid.cpp), so the legalizer keeps cells out of exactly the rows the block
covers and may put a cell in the row above its top. PlacementDRC::checkPadding(const Node* cell)starts from the row nearest the bottom (grid_->gridRoundY(cell))
and ends atgridEndY(gridYToDbu(y) + cell->getHeight()), measured from that rounded row
(src/dpl/src/PlacementDRC.cpp). When the bottom is in the upper half of a row, the rounded row is one row higher,
so the checked window extends one row past the block's real top, onto that legal cell, and the BLOCK-vs-CORE
"no padded overlap" rule fails.
Flows that cut rows around macros (for example ORFS's tapcell step) never put a cell in that row, which may be why it
has not shown up. We met it in a flow that keeps uncut rows, with memory macros of fractional row height placed off
the row grid.
Suggested Solution
Start the padding check where the grid paints the cell, e.g. gridSnapDownY(cell) in the one-argument
checkPadding (or compute the window's end from the cell's real top rather than from the rounded row). For cells on
the row grid both give the same rows, so only off-row blocks would change.
Steps to reproduce
A self-contained case, no platform files: a 10 x 4.3 um block (3.07 rows of 1.4 um) FIXED at y = 3.6 um, 0.8 um
into row 2, so it covers rows 2-5 (top edge 7.9 um); an inverter PLACED in row 6 (y = 8.4 um), 0.5 um above the
block and not overlapping it.
tech.lef
VERSION 5.8 ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
UNITS
DATABASE MICRONS 1000 ;
END UNITS
MANUFACTURINGGRID 0.005 ;
SITE core
CLASS CORE ;
SYMMETRY Y ;
SIZE 0.2 BY 1.4 ;
END core
LAYER metal1
TYPE ROUTING ;
DIRECTION HORIZONTAL ;
PITCH 0.2 ;
WIDTH 0.07 ;
END metal1
END LIBRARY
cells.lef
VERSION 5.8 ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
MACRO INV
CLASS CORE ;
ORIGIN 0 0 ;
SIZE 0.6 BY 1.4 ;
SYMMETRY X Y ;
SITE core ;
END INV
MACRO RAM
CLASS BLOCK ;
ORIGIN 0 0 ;
SIZE 10 BY 4.3 ;
SYMMETRY X Y ;
END RAM
END LIBRARY
flagged.def
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN top ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 20000 14000 ) ;
ROW row_0 core 0 0 N DO 100 BY 1 STEP 200 0 ;
ROW row_1 core 0 1400 FS DO 100 BY 1 STEP 200 0 ;
ROW row_2 core 0 2800 N DO 100 BY 1 STEP 200 0 ;
ROW row_3 core 0 4200 FS DO 100 BY 1 STEP 200 0 ;
ROW row_4 core 0 5600 N DO 100 BY 1 STEP 200 0 ;
ROW row_5 core 0 7000 FS DO 100 BY 1 STEP 200 0 ;
ROW row_6 core 0 8400 N DO 100 BY 1 STEP 200 0 ;
ROW row_7 core 0 9800 FS DO 100 BY 1 STEP 200 0 ;
ROW row_8 core 0 11200 N DO 100 BY 1 STEP 200 0 ;
ROW row_9 core 0 12600 FS DO 100 BY 1 STEP 200 0 ;
COMPONENTS 2 ;
- ram RAM + FIXED ( 2000 3600 ) N ;
- inv INV + PLACED ( 4000 8400 ) N ;
END COMPONENTS
END DESIGN
check.tcl
read_lef tech.lef
read_lef cells.lef
read_def $::env(DEF)
if { [catch {check_placement -verbose} msg] } { puts "check_placement FAILED: $msg" } else { puts "check_placement passed" }
DEF=flagged.def openroad -no_init -exit check.tcl
Output:
[WARNING DPL-0011] Padding check failed (1).
ram
[ERROR DPL-0033] detailed placement checks failed during check placement.
check_placement FAILED: DPL-0033
Moving the block down to y = 3.4 um (0.6 um into its row, the lower half; same rows covered, the inverter unchanged)
makes check_placement pass.
Version
Reproduced with OpenROAD 26Q3-2811-gc487fc7086. As of 2026-10-28, checkPadding(const Node*) on master still uses
gridRoundY as above.
- Dominant language
- Verilog
- Stars
- 3.2k
- Forks
- 1.1k
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 270
Getting set up
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from The-OpenROAD-Project/OpenROAD
-
odb: Bazel build fails on linux/aarch64 — char fc compared to EOF in def/lef lexersPossibly taken A pull request linked to this issue is open or already merged. Openbazel bug odb
Difficulty 1/5 Under an hour Newbie friendliness 80/100
The-OpenROAD-Project/OpenROAD#12095 · 1 comment ·
Maintainers usually reply within 1 day
-
OpenRCX: extMeasure::calcRes0 segfaults on a null getRes() result when a rules file has sparse per-layer tablesPossibly taken @AcKoucher claimed this 1 day ago. Openbug rcx
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
The-OpenROAD-Project/OpenROAD#12052 · 2 comments · 1 assignee ·
Maintainers usually reply within 1 day
-
syn: acd_resynth -apply segfaults on a database resynthesized in an earlier processPossibly taken @zzf2024 claimed this 2 days ago. Openbug syn
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
The-OpenROAD-Project/OpenROAD#12046 · 2 comments ·
Maintainers usually reply within 1 day
-
dft: ScanStitch::Stitch dereferences std::deque::end() on chains of 3+ cellsPossibly taken @mmporong claimed this 8 days ago. Opendft
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
The-OpenROAD-Project/OpenROAD#11985 · 1 comment ·
Maintainers usually reply within 1 day
-
[cts] -useful_skew: add a test to document and enforce the intent at block boundariesPossibly taken @precisionmoon claimed this 3 days ago. Opencts documentation question rsz
The-OpenROAD-Project/OpenROAD#12088 · 2 comments · 1 assignee ·
Maintainers usually reply within 1 day
All issues in The-OpenROAD-Project/OpenROAD
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
OrchardCMS/OrchardCore#20192 ·
Maintainers usually reply within 1 day
-
0. Needs triage 35-feedback bug
Difficulty 1/5 Under an hour Newbie friendliness 62/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
getgrav/grav-plugin-api#74 ·
-
Substrait consumer doesn't recognise `shift_left` / `shift_right` from functions_arithmetic.yamlOpenbug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
apache/datafusion#27059 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 1/5 Under an hour Newbie friendliness 85/100
PostHog/posthog#128636 · 1 comment ·
Maintainers usually reply within 1 day