From bbbfe2ff7b239b74b4dd1aa1c127b1cbadfa3452 Mon Sep 17 00:00:00 2001 From: Augusto Berndt Date: Thu, 16 Apr 2026 18:41:11 +0000 Subject: [PATCH 1/9] dpl: introduce region awareness, fix rail alignment for negotiation, debug: include cell orientation when selected Signed-off-by: Augusto Berndt --- src/dpl/src/NegotiationLegalizer.cpp | 140 +++++++++++++++++++---- src/dpl/src/NegotiationLegalizerPass.cpp | 31 ++++- src/dpl/src/Opendp.cpp | 6 + src/dpl/src/graphics/Graphics.cpp | 14 +++ 4 files changed, 168 insertions(+), 23 deletions(-) diff --git a/src/dpl/src/NegotiationLegalizer.cpp b/src/dpl/src/NegotiationLegalizer.cpp index df06af4dcaa..917b942ffc4 100644 --- a/src/dpl/src/NegotiationLegalizer.cpp +++ b/src/dpl/src/NegotiationLegalizer.cpp @@ -533,12 +533,25 @@ bool NegotiationLegalizer::initFromDb() grid_w_ = dpl_grid->getRowSiteCount().v; grid_h_ = dpl_grid->getRowCount().v; - // Assign power-rail types using row-index parity (VSS at even rows). - // Replace with explicit LEF pg_pin parsing for advanced PDKs. + // Assign power-rail types from DB row orientations. + // R0/MY = right-side-up → VSS rail at bottom; MX/R180 = flipped → VDD at + // bottom. Rows missing from the DB default to VSS. row_rail_.clear(); - row_rail_.resize(grid_h_); - for (int r = 0; r < grid_h_; ++r) { - row_rail_[r] = (r % 2 == 0) ? NLPowerRailType::kVss : NLPowerRailType::kVdd; + row_rail_.resize(grid_h_, NLPowerRailType::kVss); + for (auto* db_row : block->getRows()) { + const int y_dbu = db_row->getOrigin().y() - die_ylo_; + if (y_dbu < 0 || y_dbu % row_height_ != 0) { + continue; + } + const int r = y_dbu / row_height_; + if (r >= grid_h_) { + continue; + } + const auto orient = db_row->getOrient(); + row_rail_[r] + = (orient == odb::dbOrientType::MX || orient == odb::dbOrientType::R180) + ? NLPowerRailType::kVdd + : NLPowerRailType::kVss; } // Build NegCell records from all placed instances. @@ -624,7 +637,51 @@ bool NegotiationLegalizer::initFromDb() // in original DPL. // they achieve the same objective, and the previous is more simple, // consider replacing this. - if (!isValidSite(cell.init_x, cell.init_y)) { + // For region-constrained cells, collect the region rects in grid + // coordinates so the BFS below can verify containment. + // initFenceRegions() has not run yet, so we read ODB directly. + // Instances reach their region via a GROUP, not via dbInst::region_, + // so we must check both paths. + odb::dbRegion* odb_region = db_inst->getRegion(); + if (odb_region == nullptr) { + auto* grp = db_inst->getGroup(); + if (grp != nullptr) { + odb_region = grp->getRegion(); + } + } + struct RegionRectInline + { + int xlo, ylo, xhi, yhi; + }; + std::vector region_rects_inline; + if (odb_region != nullptr) { + for (auto* box : odb_region->getBoundaries()) { + RegionRectInline r; + r.xlo = (box->xMin() - die_xlo_) / site_width_; + r.ylo = (box->yMin() - die_ylo_) / row_height_; + r.xhi = (box->xMax() - die_xlo_) / site_width_; + r.yhi = (box->yMax() - die_ylo_) / row_height_; + region_rects_inline.push_back(r); + } + } + // Returns true when (gx,gy) satisfies the region constraint: + // region-constrained cells must land inside their region; + // unconstrained cells have no restriction here (negotiation handles it). + auto isInRegionOk = [&](int gx, int gy) -> bool { + if (region_rects_inline.empty()) { + return true; + } + for (const auto& r : region_rects_inline) { + if (gx >= r.xlo && gy >= r.ylo && gx + cell.width <= r.xhi + && gy + cell.height <= r.yhi) { + return true; + } + } + return false; + }; + + if (!isValidSite(cell.init_x, cell.init_y) + || !isInRegionOk(cell.init_x, cell.init_y)) { debugPrint(logger_, utl::DPL, "negotiation", @@ -666,7 +723,7 @@ bool NegotiationLegalizer::initFromDb() while (!pq.empty()) { auto [dist, gx, gy] = pq.top(); pq.pop(); - if (isValidSite(gx, gy)) { + if (isValidSite(gx, gy) && isInRegionOk(gx, gy)) { cell.init_x = gx; cell.init_y = gy; cell.x = cell.init_x; @@ -690,14 +747,34 @@ bool NegotiationLegalizer::initFromDb() cell.rail_type = (cell.rail_type == NLPowerRailType::kVss) ? NLPowerRailType::kVdd : NLPowerRailType::kVss; + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "DEBUG rail_type flip: cell {} orient={} siteOrient={} " + "init_y={} -> rail_type={}", + db_inst->getName(), + db_inst->getOrient().getString(), + siteOrient.value().getString(), + cell.init_y, + cell.rail_type == NLPowerRailType::kVss ? "kVss" : "kVdd"); } cell.flippable = master->getSymmetryX(); // X-symmetry allows vertical flip (MX) - if (cell.height % 2 == 1) { - // For 1-row cells, we usually assume they are flippable in most PDKs. + if (cell.height == 1) { + // Consider all single height cells flippable cell.flippable = true; } + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "DEBUG cell init: {} height={} flippable={} rail_type={}", + db_inst->getName(), + cell.height, + cell.flippable, + cell.rail_type == NLPowerRailType::kVss ? "kVss" : "kVdd"); if (padding_ != nullptr) { cell.pad_left = padding_->padLeft(db_inst).v; @@ -722,13 +799,18 @@ void NegotiationLegalizer::buildGrid() { Grid* dplGrid = opendp_->grid_.get(); - // Reset all pixels to default negotiation state. + // Reset all pixels to default negotiation state. Also clear any cell + // and padding pointers (including dummy_cell_ set by groupInitPixels2 for + // region boundaries) — fixed cells and movable cells are re-painted later + // by syncAllCellsToDplGrid() before any DRC check runs. for (int gy = 0; gy < grid_h_; ++gy) { for (int gx = 0; gx < grid_w_; ++gx) { Pixel& pixel = dplGrid->pixel(GridY{gy}, GridX{gx}); pixel.capacity = pixel.is_valid ? 1 : 0; pixel.usage = 0; pixel.hist_cost = 1.0; + pixel.cell = nullptr; + pixel.padding_reserved_by = nullptr; } } @@ -793,11 +875,20 @@ void NegotiationLegalizer::initFenceRegions() } // Map each instance to its fence region (if any). + // Instances are assigned to regions via GROUPS in DEF, which sets + // dbInst::group_ but NOT dbInst::region_. We must go through the group. for (auto& cell : cells_) { if (cell.db_inst == nullptr) { continue; } - auto* region = cell.db_inst->getRegion(); + // Try direct region first, then group-based region. + odb::dbRegion* region = cell.db_inst->getRegion(); + if (region == nullptr) { + auto* grp = cell.db_inst->getGroup(); + if (grp != nullptr) { + region = grp->getRegion(); + } + } if (region == nullptr) { continue; } @@ -973,14 +1064,22 @@ bool NegotiationLegalizer::isValidRow(int rowIdx, return false; } } - const NLPowerRailType rowBot = row_rail_[rowIdx]; - if (cell.height % 2 == 1) { - // Odd-height: bottom rail must match, or cell can be vertically flipped. - return cell.flippable || (rowBot == cell.rail_type); - } - // Even-height: bottom boundary must be the correct rail type, and the - // cell may only move by an even number of rows. - return rowBot == cell.rail_type; + const NLPowerRailType bottom_rail = row_rail_[rowIdx]; + // row and cell rail must match, or cell can be flipped. + auto railStr = [](NLPowerRailType r) { + return r == NLPowerRailType::kVss ? "kVss" : "kVdd"; + }; + bool ret = (bottom_rail == cell.rail_type) || cell.flippable; + logger_->report( + "rowIdx: {}, bottom_rail: {}, cell.rail_type: {}, flippable: {}, " + "rail match: {}, is_valid: {}", + rowIdx, + railStr(bottom_rail), + railStr(cell.rail_type), + cell.flippable, + (bottom_rail == cell.rail_type), + ret); + return ret; } bool NegotiationLegalizer::respectsFence(int cell_idx, int x, int y) const @@ -998,6 +1097,7 @@ bool NegotiationLegalizer::respectsFence(int cell_idx, int x, int y) const return fences_[cell.fence_id].contains(x, y, cell.width, cell.height); } +// TODO: remove this function! std::pair NegotiationLegalizer::snapToLegal(int cell_idx, int x, int y) const @@ -1030,7 +1130,7 @@ std::pair NegotiationLegalizer::snapToLegal(int cell_idx, } } - if (ok) { + if (ok && respectsFence(cell_idx, tx, r)) { const int dx = std::abs(tx - x); if (dx < local_best_dx) { local_best_dx = dx; diff --git a/src/dpl/src/NegotiationLegalizerPass.cpp b/src/dpl/src/NegotiationLegalizerPass.cpp index 2a9c052bfeb..ede4867c23a 100644 --- a/src/dpl/src/NegotiationLegalizerPass.cpp +++ b/src/dpl/src/NegotiationLegalizerPass.cpp @@ -398,9 +398,20 @@ void NegotiationLegalizer::place(int cell_idx, int x, int y) const odb::dbInst* debug_inst = debug_observer_->getDebugInstance(); if (!debug_inst || cells_[cell_idx].db_inst == debug_inst) { pushNegotiationPixels(); - logger_->report("Pause at placing of cell {}.", - cells_[cell_idx].db_inst->getName()); - debug_observer_->drawSelected(cells_[cell_idx].db_inst, !debug_inst); + const NegCell& c = cells_[cell_idx]; + const int orig_x_dbu = die_xlo_ + c.init_x * site_width_; + const int orig_y_dbu = die_ylo_ + c.init_y * row_height_; + const int tgt_x_dbu = die_xlo_ + c.x * site_width_; + const int tgt_y_dbu = die_ylo_ + c.y * row_height_; + logger_->report( + "Pause at placing of cell {}. orig=({},{}) target=({},{}) dbu. rowidx={}.", + c.db_inst->getName(), + orig_x_dbu, + orig_y_dbu, + tgt_x_dbu, + tgt_y_dbu, + c.y); + debug_observer_->drawSelected(c.db_inst, !debug_inst); } } } @@ -546,6 +557,20 @@ std::pair NegotiationLegalizer::findBestLocation(int cell_idx, } } } + + if (best_cost == static_cast(kInfCost)) { + // Every candidate in the search window was filtered out (out-of-die, + // invalid row, or fence violation). The cell falls back to its current + // position, which may already be illegal — a likely stuck-cell scenario. + logger_->warn(utl::DPL, + 703, + "findBestLocation: no valid candidate found for cell '{}' " + "(iter {}) — all {} candidates filtered, cell may be stuck.", + cell.db_inst->getName(), + iter, + prof_candidates_filtered_); + } + return {best_x, best_y}; } diff --git a/src/dpl/src/Opendp.cpp b/src/dpl/src/Opendp.cpp index b776062688c..49ab13088d6 100644 --- a/src/dpl/src/Opendp.cpp +++ b/src/dpl/src/Opendp.cpp @@ -206,6 +206,12 @@ void Opendp::detailedPlacement(const int max_displacement_x, } else { initGrid(); setFixedGridCells(); + // Populate pixel->group for each fence region so diamondRecovery's + // underlying diamondSearch correctly enforces region constraints. + if (!arch_->getRegions().empty()) { + groupInitPixels2(); + groupInitPixels(); + } logger_->info(DPL, 1102, "Legalizing using negotiation legalizer."); NegotiationLegalizer negotiation(this, diff --git a/src/dpl/src/graphics/Graphics.cpp b/src/dpl/src/graphics/Graphics.cpp index 06b969dfd48..f93a3a9259e 100644 --- a/src/dpl/src/graphics/Graphics.cpp +++ b/src/dpl/src/graphics/Graphics.cpp @@ -144,6 +144,20 @@ void Graphics::drawObjects(gui::Painter& painter) painter.setPen(outline_color, /* cosmetic */ true); painter.setBrush(gui::Painter::kTransparent); painter.drawRect(target_bbox); + + // Indicate orientation change at the target location with a corner notch + // (mirroring the ODB orientation marker style) + const odb::dbOrientType orig_orient = cell->getDbInst()->getOrient(); + const odb::dbOrientType target_orient = cell->getOrient(); + // if (orig_orient != target_orient) + { + painter.setPen(outline_color, /* cosmetic */ true); + const int tag_size = std::min(width / 4, height / 8); + painter.drawLine(target_bbox.xMin() + tag_size, + target_bbox.yMin(), + target_bbox.xMin(), + target_bbox.yMin() + tag_size * 2); + } } else if (std::abs(dx) > std::abs(dy)) { line_color = (dx > 0) ? gui::Painter::kGreen : gui::Painter::kRed; } else { From 14576fd7b9344c94104594ab6291834eb391fc34 Mon Sep 17 00:00:00 2001 From: Augusto Berndt Date: Thu, 16 Apr 2026 21:51:36 +0000 Subject: [PATCH 2/9] dpl: make message debug Signed-off-by: Augusto Berndt --- src/dpl/src/NegotiationLegalizer.cpp | 5 ++++- src/dpl/src/Opendp.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/dpl/src/NegotiationLegalizer.cpp b/src/dpl/src/NegotiationLegalizer.cpp index 917b942ffc4..d0349892d98 100644 --- a/src/dpl/src/NegotiationLegalizer.cpp +++ b/src/dpl/src/NegotiationLegalizer.cpp @@ -1070,7 +1070,10 @@ bool NegotiationLegalizer::isValidRow(int rowIdx, return r == NLPowerRailType::kVss ? "kVss" : "kVdd"; }; bool ret = (bottom_rail == cell.rail_type) || cell.flippable; - logger_->report( + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, "rowIdx: {}, bottom_rail: {}, cell.rail_type: {}, flippable: {}, " "rail match: {}, is_valid: {}", rowIdx, diff --git a/src/dpl/src/Opendp.cpp b/src/dpl/src/Opendp.cpp index 49ab13088d6..77affc59c5c 100644 --- a/src/dpl/src/Opendp.cpp +++ b/src/dpl/src/Opendp.cpp @@ -183,7 +183,7 @@ void Opendp::detailedPlacement(const int max_displacement_x, max_displacement_x_, max_displacement_y_); - if (!use_negotiation_) { + if (use_negotiation_) { logger_->info(DPL, 1101, "Legalizing using diamond search."); diamondDPL(); findDisplacementStats(); From 74c5d7b9eb094b7a83fddeb91ecd362e9e4b3277 Mon Sep 17 00:00:00 2001 From: Augusto Berndt Date: Fri, 17 Apr 2026 11:00:19 +0000 Subject: [PATCH 3/9] dpl: keep diamond as default Signed-off-by: Augusto Berndt --- src/dpl/src/Opendp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dpl/src/Opendp.cpp b/src/dpl/src/Opendp.cpp index 77affc59c5c..49ab13088d6 100644 --- a/src/dpl/src/Opendp.cpp +++ b/src/dpl/src/Opendp.cpp @@ -183,7 +183,7 @@ void Opendp::detailedPlacement(const int max_displacement_x, max_displacement_x_, max_displacement_y_); - if (use_negotiation_) { + if (!use_negotiation_) { logger_->info(DPL, 1101, "Legalizing using diamond search."); diamondDPL(); findDisplacementStats(); From 4fbfe8408181772fba6617c2159eed98683e8c19 Mon Sep 17 00:00:00 2001 From: Augusto Berndt Date: Fri, 17 Apr 2026 17:20:10 +0000 Subject: [PATCH 4/9] dpl: fix negotation rail alignment, remove assumptions Signed-off-by: Augusto Berndt --- src/dpl/src/NegotiationLegalizer.cpp | 83 +++++++++++++++------------- src/dpl/src/NegotiationLegalizer.h | 7 ++- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/src/dpl/src/NegotiationLegalizer.cpp b/src/dpl/src/NegotiationLegalizer.cpp index d0349892d98..a1463e5b521 100644 --- a/src/dpl/src/NegotiationLegalizer.cpp +++ b/src/dpl/src/NegotiationLegalizer.cpp @@ -23,6 +23,7 @@ #include "infrastructure/Grid.h" #include "infrastructure/Objects.h" #include "infrastructure/Padding.h" +#include "infrastructure/architecture.h" #include "infrastructure/network.h" #include "odb/db.h" #include "odb/geom.h" @@ -737,27 +738,37 @@ bool NegotiationLegalizer::initFromDb() } } - cell.rail_type = inferRailType(cell.init_y); - // If the instance is currently flipped relative to the row's standard - // orientation, its internal rail design is opposite of the row's bottom - // rail. - auto siteOrient = dpl_grid->getSiteOrientation( - GridX{cell.init_x}, GridY{cell.init_y}, master->getSite()); - if (siteOrient.has_value() && db_inst->getOrient() != siteOrient.value()) { - cell.rail_type = (cell.rail_type == NLPowerRailType::kVss) - ? NLPowerRailType::kVdd - : NLPowerRailType::kVss; - debugPrint(logger_, - utl::DPL, - "negotiation", - 1, - "DEBUG rail_type flip: cell {} orient={} siteOrient={} " - "init_y={} -> rail_type={}", - db_inst->getName(), - db_inst->getOrient().getString(), - siteOrient.value().getString(), - cell.init_y, - cell.rail_type == NLPowerRailType::kVss ? "kVss" : "kVdd"); + // Derive power-rail types directly from the LEF geometry stored by the + // Network — never infer from the cell's current row or orientation. + // + // rail_type = bottom rail in R0 (unflipped) orientation. + // For most CORE cells this is kVss (VSS at bottom). + // rail_type_flipped = bottom rail in MX (flipped) orientation, which + // equals the TOP rail in R0. For most cells: kVdd. + // For symmetric multi-height cells whose VSS appears + // at both top and bottom (e.g. some double-height + // flops): kVss — meaning a flip cannot resolve a + // VDD-bottom row mismatch. + { + int bot_pwr = Architecture::Row::Power_UNK; + int top_pwr = Architecture::Row::Power_UNK; + if (network_ != nullptr) { + if (Master* dpl_master = network_->getMaster(master)) { + bot_pwr = dpl_master->getBottomPowerType(); + top_pwr = dpl_master->getTopPowerType(); + } + } + auto toRailType = [](int pwr, NLPowerRailType fallback) { + if (pwr == Architecture::Row::Power_VSS) { + return NLPowerRailType::kVss; + } + if (pwr == Architecture::Row::Power_VDD) { + return NLPowerRailType::kVdd; + } + return fallback; + }; + cell.rail_type = toRailType(bot_pwr, NLPowerRailType::kVss); + cell.rail_type_flipped = toRailType(top_pwr, NLPowerRailType::kVdd); } cell.flippable @@ -766,15 +777,17 @@ bool NegotiationLegalizer::initFromDb() // Consider all single height cells flippable cell.flippable = true; } - debugPrint(logger_, + + debugPrint(logger_, utl::DPL, "negotiation", 1, - "DEBUG cell init: {} height={} flippable={} rail_type={}", + "DEBUG cell init: {} height={} flippable={} rail_type={} rail_type_flipped={}", db_inst->getName(), cell.height, cell.flippable, - cell.rail_type == NLPowerRailType::kVss ? "kVss" : "kVdd"); + cell.rail_type == NLPowerRailType::kVss ? "kVss" : "kVdd", + cell.rail_type_flipped == NLPowerRailType::kVss ? "kVss" : "kVdd"); if (padding_ != nullptr) { cell.pad_left = padding_->padLeft(db_inst).v; @@ -787,13 +800,6 @@ bool NegotiationLegalizer::initFromDb() return true; } -NLPowerRailType NegotiationLegalizer::inferRailType(int rowIdx) const -{ - if (rowIdx >= 0 && rowIdx < static_cast(row_rail_.size())) { - return row_rail_[rowIdx]; - } - return NLPowerRailType::kVss; -} void NegotiationLegalizer::buildGrid() { @@ -1064,23 +1070,26 @@ bool NegotiationLegalizer::isValidRow(int rowIdx, return false; } } - const NLPowerRailType bottom_rail = row_rail_[rowIdx]; + const NLPowerRailType row_bottom_rail = row_rail_[rowIdx]; // row and cell rail must match, or cell can be flipped. auto railStr = [](NLPowerRailType r) { return r == NLPowerRailType::kVss ? "kVss" : "kVdd"; }; - bool ret = (bottom_rail == cell.rail_type) || cell.flippable; + bool ret = (row_bottom_rail == cell.rail_type) + || (cell.flippable && row_bottom_rail == cell.rail_type_flipped); debugPrint(logger_, utl::DPL, "negotiation", 1, - "rowIdx: {}, bottom_rail: {}, cell.rail_type: {}, flippable: {}, " - "rail match: {}, is_valid: {}", + "rowIdx: {}, row_bottom_rail: {}, cell: {}, cell.rail_type: {}, " + "rail_type_flipped: {}, flippable: {}, rail match: {}, is_valid: {}", rowIdx, - railStr(bottom_rail), + railStr(row_bottom_rail), + cell.db_inst ? cell.db_inst->getName() : "?", railStr(cell.rail_type), + railStr(cell.rail_type_flipped), cell.flippable, - (bottom_rail == cell.rail_type), + (row_bottom_rail == cell.rail_type), ret); return ret; } diff --git a/src/dpl/src/NegotiationLegalizer.h b/src/dpl/src/NegotiationLegalizer.h index c155d990088..3c8c81b4a1d 100644 --- a/src/dpl/src/NegotiationLegalizer.h +++ b/src/dpl/src/NegotiationLegalizer.h @@ -92,6 +92,12 @@ struct NegCell bool fixed{false}; NLPowerRailType rail_type{NLPowerRailType::kVss}; + // Bottom rail type of the cell when it is MX-flipped (= the top rail in + // the natural R0 orientation). For most cells this is kVdd (VDD↔VSS swap + // at the bottom edge after flip). For multi-height cells whose power is + // symmetric (VSS at both top and bottom, e.g. some double-height flops), + // this equals rail_type — flipping cannot fix a power-rail mismatch. + NLPowerRailType rail_type_flipped{NLPowerRailType::kVdd}; int fence_id{-1}; // -1 → default region bool flippable{true}; // odd-height cells may require fliping for moving bool legal{false}; // updated each negotiation iteration @@ -160,7 +166,6 @@ class NegotiationLegalizer bool initFromDb(); void buildGrid(); void initFenceRegions(); - [[nodiscard]] NLPowerRailType inferRailType(int rowIdx) const; void flushToDb(); // Write current cell positions to ODB (for GUI updates) void pushNegotiationPixels(); void debugPause(const std::string& msg); From 4d3dad6b390a0e6454b3eee4293ed533a59566a7 Mon Sep 17 00:00:00 2001 From: Matt Liberty Date: Sat, 18 Apr 2026 06:37:50 +0000 Subject: [PATCH 5/9] dpl: clang-format Signed-off-by: Matt Liberty --- src/dpl/src/NegotiationLegalizer.cpp | 22 ++++++++++++---------- src/dpl/src/NegotiationLegalizerPass.cpp | 3 ++- src/dpl/src/graphics/Graphics.cpp | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/dpl/src/NegotiationLegalizer.cpp b/src/dpl/src/NegotiationLegalizer.cpp index a1463e5b521..d63271ab9d4 100644 --- a/src/dpl/src/NegotiationLegalizer.cpp +++ b/src/dpl/src/NegotiationLegalizer.cpp @@ -778,11 +778,13 @@ bool NegotiationLegalizer::initFromDb() cell.flippable = true; } - debugPrint(logger_, - utl::DPL, - "negotiation", - 1, - "DEBUG cell init: {} height={} flippable={} rail_type={} rail_type_flipped={}", + debugPrint( + logger_, + utl::DPL, + "negotiation", + 1, + "DEBUG cell init: {} height={} flippable={} rail_type={} " + "rail_type_flipped={}", db_inst->getName(), cell.height, cell.flippable, @@ -800,7 +802,6 @@ bool NegotiationLegalizer::initFromDb() return true; } - void NegotiationLegalizer::buildGrid() { Grid* dplGrid = opendp_->grid_.get(); @@ -1077,10 +1078,11 @@ bool NegotiationLegalizer::isValidRow(int rowIdx, }; bool ret = (row_bottom_rail == cell.rail_type) || (cell.flippable && row_bottom_rail == cell.rail_type_flipped); - debugPrint(logger_, - utl::DPL, - "negotiation", - 1, + debugPrint( + logger_, + utl::DPL, + "negotiation", + 1, "rowIdx: {}, row_bottom_rail: {}, cell: {}, cell.rail_type: {}, " "rail_type_flipped: {}, flippable: {}, rail match: {}, is_valid: {}", rowIdx, diff --git a/src/dpl/src/NegotiationLegalizerPass.cpp b/src/dpl/src/NegotiationLegalizerPass.cpp index ede4867c23a..c4be1e0411d 100644 --- a/src/dpl/src/NegotiationLegalizerPass.cpp +++ b/src/dpl/src/NegotiationLegalizerPass.cpp @@ -404,7 +404,8 @@ void NegotiationLegalizer::place(int cell_idx, int x, int y) const int tgt_x_dbu = die_xlo_ + c.x * site_width_; const int tgt_y_dbu = die_ylo_ + c.y * row_height_; logger_->report( - "Pause at placing of cell {}. orig=({},{}) target=({},{}) dbu. rowidx={}.", + "Pause at placing of cell {}. orig=({},{}) target=({},{}) dbu. " + "rowidx={}.", c.db_inst->getName(), orig_x_dbu, orig_y_dbu, diff --git a/src/dpl/src/graphics/Graphics.cpp b/src/dpl/src/graphics/Graphics.cpp index f93a3a9259e..691ebe2ffd7 100644 --- a/src/dpl/src/graphics/Graphics.cpp +++ b/src/dpl/src/graphics/Graphics.cpp @@ -149,7 +149,7 @@ void Graphics::drawObjects(gui::Painter& painter) // (mirroring the ODB orientation marker style) const odb::dbOrientType orig_orient = cell->getDbInst()->getOrient(); const odb::dbOrientType target_orient = cell->getOrient(); - // if (orig_orient != target_orient) + // if (orig_orient != target_orient) { painter.setPen(outline_color, /* cosmetic */ true); const int tag_size = std::min(width / 4, height / 8); From ea98df95aabe1b369f462dee17f34acb87f3ea19 Mon Sep 17 00:00:00 2001 From: Matt Liberty Date: Sat, 18 Apr 2026 06:40:20 +0000 Subject: [PATCH 6/9] dpl: tidy missing includes Signed-off-by: Matt Liberty --- src/dpl/src/graphics/Graphics.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dpl/src/graphics/Graphics.cpp b/src/dpl/src/graphics/Graphics.cpp index 691ebe2ffd7..095ae4bb7cb 100644 --- a/src/dpl/src/graphics/Graphics.cpp +++ b/src/dpl/src/graphics/Graphics.cpp @@ -3,6 +3,7 @@ #include "Graphics.h" +#include #include #include #include @@ -16,6 +17,7 @@ #include "infrastructure/Objects.h" #include "infrastructure/network.h" #include "odb/db.h" +#include "odb/dbTypes.h" #include "odb/geom.h" namespace dpl { From 9a83672bf25c572faccfe56cc4e1352ead1e277f Mon Sep 17 00:00:00 2001 From: Augusto Berndt Date: Sat, 18 Apr 2026 09:23:44 +0000 Subject: [PATCH 7/9] dpl: remove unused variables Signed-off-by: Augusto Berndt --- src/dpl/src/graphics/Graphics.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/dpl/src/graphics/Graphics.cpp b/src/dpl/src/graphics/Graphics.cpp index 095ae4bb7cb..4379d53fb30 100644 --- a/src/dpl/src/graphics/Graphics.cpp +++ b/src/dpl/src/graphics/Graphics.cpp @@ -149,17 +149,12 @@ void Graphics::drawObjects(gui::Painter& painter) // Indicate orientation change at the target location with a corner notch // (mirroring the ODB orientation marker style) - const odb::dbOrientType orig_orient = cell->getDbInst()->getOrient(); - const odb::dbOrientType target_orient = cell->getOrient(); - // if (orig_orient != target_orient) - { - painter.setPen(outline_color, /* cosmetic */ true); - const int tag_size = std::min(width / 4, height / 8); - painter.drawLine(target_bbox.xMin() + tag_size, - target_bbox.yMin(), - target_bbox.xMin(), - target_bbox.yMin() + tag_size * 2); - } + painter.setPen(outline_color, /* cosmetic */ true); + const int tag_size = std::min(width / 4, height / 8); + painter.drawLine(target_bbox.xMin() + tag_size, + target_bbox.yMin(), + target_bbox.xMin(), + target_bbox.yMin() + tag_size * 2); } else if (std::abs(dx) > std::abs(dy)) { line_color = (dx > 0) ? gui::Painter::kGreen : gui::Painter::kRed; } else { From e682a4f14307ba2a90cfc1ff3dd3b9e3bccd8c26 Mon Sep 17 00:00:00 2001 From: Augusto Berndt Date: Sat, 18 Apr 2026 09:45:22 +0000 Subject: [PATCH 8/9] dpl: avoid redundant checks when handling regions, transform warn into debugPrint Signed-off-by: Augusto Berndt --- src/dpl/src/NegotiationLegalizer.cpp | 39 +++++++++++++++--------- src/dpl/src/NegotiationLegalizerPass.cpp | 16 +++++----- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/dpl/src/NegotiationLegalizer.cpp b/src/dpl/src/NegotiationLegalizer.cpp index d63271ab9d4..924ad5a650c 100644 --- a/src/dpl/src/NegotiationLegalizer.cpp +++ b/src/dpl/src/NegotiationLegalizer.cpp @@ -559,6 +559,14 @@ bool NegotiationLegalizer::initFromDb() cells_.clear(); cells_.reserve(block->getInsts().size()); + // Cache region boundaries converted to grid coordinates, keyed by dbRegion*. + struct RegionRectInline + { + int xlo, ylo, xhi, yhi; + }; + std::unordered_map> + region_rect_cache; + for (auto* db_inst : block->getInsts()) { const auto status = db_inst->getPlacementStatus(); if (status == odb::dbPlacementStatus::NONE) { @@ -650,29 +658,32 @@ bool NegotiationLegalizer::initFromDb() odb_region = grp->getRegion(); } } - struct RegionRectInline - { - int xlo, ylo, xhi, yhi; - }; - std::vector region_rects_inline; + // Look up (or populate) the cache for this region. + const std::vector* region_rects_ptr = nullptr; if (odb_region != nullptr) { - for (auto* box : odb_region->getBoundaries()) { - RegionRectInline r; - r.xlo = (box->xMin() - die_xlo_) / site_width_; - r.ylo = (box->yMin() - die_ylo_) / row_height_; - r.xhi = (box->xMax() - die_xlo_) / site_width_; - r.yhi = (box->yMax() - die_ylo_) / row_height_; - region_rects_inline.push_back(r); + auto it = region_rect_cache.find(odb_region); + if (it == region_rect_cache.end()) { + std::vector rects; + for (auto* box : odb_region->getBoundaries()) { + RegionRectInline r; + r.xlo = (box->xMin() - die_xlo_) / site_width_; + r.ylo = (box->yMin() - die_ylo_) / row_height_; + r.xhi = (box->xMax() - die_xlo_) / site_width_; + r.yhi = (box->yMax() - die_ylo_) / row_height_; + rects.push_back(r); + } + it = region_rect_cache.emplace(odb_region, std::move(rects)).first; } + region_rects_ptr = &it->second; } // Returns true when (gx,gy) satisfies the region constraint: // region-constrained cells must land inside their region; // unconstrained cells have no restriction here (negotiation handles it). auto isInRegionOk = [&](int gx, int gy) -> bool { - if (region_rects_inline.empty()) { + if (region_rects_ptr == nullptr) { return true; } - for (const auto& r : region_rects_inline) { + for (const auto& r : *region_rects_ptr) { if (gx >= r.xlo && gy >= r.ylo && gx + cell.width <= r.xhi && gy + cell.height <= r.yhi) { return true; diff --git a/src/dpl/src/NegotiationLegalizerPass.cpp b/src/dpl/src/NegotiationLegalizerPass.cpp index c4be1e0411d..d68f6885591 100644 --- a/src/dpl/src/NegotiationLegalizerPass.cpp +++ b/src/dpl/src/NegotiationLegalizerPass.cpp @@ -563,13 +563,15 @@ std::pair NegotiationLegalizer::findBestLocation(int cell_idx, // Every candidate in the search window was filtered out (out-of-die, // invalid row, or fence violation). The cell falls back to its current // position, which may already be illegal — a likely stuck-cell scenario. - logger_->warn(utl::DPL, - 703, - "findBestLocation: no valid candidate found for cell '{}' " - "(iter {}) — all {} candidates filtered, cell may be stuck.", - cell.db_inst->getName(), - iter, - prof_candidates_filtered_); + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "findBestLocation: no valid candidate found for cell '{}' " + "(iter {}) — all {} candidates filtered, cell may be stuck.", + cell.db_inst->getName(), + iter, + prof_candidates_filtered_); } return {best_x, best_y}; From a84048b42bbda81d3177c5304ea15fbb741fa6bf Mon Sep 17 00:00:00 2001 From: Augusto Berndt Date: Sat, 18 Apr 2026 09:55:52 +0000 Subject: [PATCH 9/9] dpl: remove unused header Signed-off-by: Augusto Berndt --- src/dpl/src/graphics/Graphics.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dpl/src/graphics/Graphics.cpp b/src/dpl/src/graphics/Graphics.cpp index 4379d53fb30..213ac184e0c 100644 --- a/src/dpl/src/graphics/Graphics.cpp +++ b/src/dpl/src/graphics/Graphics.cpp @@ -17,7 +17,6 @@ #include "infrastructure/Objects.h" #include "infrastructure/network.h" #include "odb/db.h" -#include "odb/dbTypes.h" #include "odb/geom.h" namespace dpl {