Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4f72503
Merge remote-tracking branch 'private/dpl-drc-penalty-and-debug' into…
gudeh Jun 18, 2026
dfb4aec
dpl: enlarge range of search window depending on instance dimensions,
gudeh Jun 1, 2026
94c7c5c
dpl: elevate debug level for negotiation verbose messages,
gudeh Jun 2, 2026
986a579
Merge remote-tracking branch 'myOR/dpl-fix-getMasterPwrs' into dpl-ne…
gudeh Jun 18, 2026
2bf3994
dpl: more info for debugging window range, and reduce runtiume debug …
gudeh Jun 8, 2026
d3cb753
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jun 18, 2026
7309eaa
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jun 24, 2026
7e1d80e
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jun 24, 2026
aaa89f5
dpl: maintain consistency with original checkPlacement and check firs…
gudeh Jun 25, 2026
9b80edf
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jun 29, 2026
230383f
dpl: extra extension for window search range depending on off-core an…
gudeh Jun 29, 2026
18b321b
dpl: snake case for variables
gudeh Jun 30, 2026
c709aa9
dpl: use helper functions for extended search window, renamings for c…
gudeh Jul 1, 2026
2029ce2
dpl: clang-format
gudeh Jul 1, 2026
e081417
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jul 1, 2026
83d0eea
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jul 4, 2026
1c7c00c
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jul 4, 2026
23f85a8
dpl: remove accidental duplicate after merge with master
gudeh Jul 4, 2026
9a14e87
dpl: update test after negotiation search window extension
gudeh Jul 6, 2026
b8aac0e
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jul 6, 2026
bfde0f9
dpl: max cap window extension for exntesion depending on overlap with…
gudeh Jul 6, 2026
9bcb478
dpl: clang-format
gudeh Jul 6, 2026
0f778bf
dpl: include print messages for window dimensions
gudeh Jul 6, 2026
654a214
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jul 6, 2026
4a78166
dpl: new tcl command for disabling negotiation legalizer window exten…
gudeh Jul 7, 2026
e65caa2
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jul 7, 2026
c831a4c
dpl: update test after adding option to skip dynamic window extension
gudeh Jul 7, 2026
4bff153
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jul 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/dpl/include/dpl/Opendp.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ class Opendp
bool run_abacus = false,
int site_search_window = -1,
int row_search_window = -1,
double drc_penalty = -1.0);
double drc_penalty = -1.0,
bool disable_window_extension = false);
void reportLegalizationStats() const;

void setPaddingGlobal(int left, int right);
Expand Down Expand Up @@ -374,8 +375,10 @@ class Opendp
std::unique_ptr<PlacementDRC> drc_engine_;
Journal* journal_ = nullptr;

// DPL-wide displacement budget set via detailedPlacement() and honored
// by every DPL pass (diamond search, and negotiation).
int max_displacement_x_ = 0; // sites
int max_displacement_y_ = 0; // sites
int max_displacement_y_ = 0; // rows
bool disallow_one_site_gaps_ = false;
std::vector<Node*> placement_failures_;

Expand Down
107 changes: 96 additions & 11 deletions src/dpl/src/NegotiationLegalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,15 @@ void NegotiationLegalizer::legalize()

logger_->info(utl::DPL,
1103,
"NegotiationLegalizer search window: +/-{} sites horizontally, "
"+/-{} rows vertically.",
"Negotiation base search window: +/-{} sites horizontally, "
"+/-{} rows vertically (extendable up to the max "
"displacement cap of +/-{} sites, +/-{} rows near walls).",
site_search_window_,
row_search_window_);
row_search_window_,
opendp_->max_displacement_x_,
opendp_->max_displacement_y_);
logger_->report("\tAutomatic search window extension {}.",
disable_window_extension_ ? "disabled" : "enabled");

logger_->info(
utl::DPL, 1104, "NegotiationLegalizer DRC penalty: {}.", drc_penalty_);
Expand Down Expand Up @@ -1026,7 +1031,6 @@ bool NegotiationLegalizer::isValidRow(int rowIdx,
if (rowIdx < 0 || rowIdx + cell.height > grid_h_) {
return false;
}
// Every row the cell spans must have real sites.
for (int dy = 0; dy < cell.height; ++dy) {
if (!row_has_sites_[rowIdx + dy]) {
return false;
Expand All @@ -1053,19 +1057,100 @@ bool NegotiationLegalizer::isValidRow(int rowIdx,
Node* node = network_->getNode(cell.db_inst);
if (node != nullptr && node->getMaster()->isMultiRow()
&& !opendp_->checkRowPowerCompatible(node, GridY{rowIdx})) {
debugPrint(logger_,
utl::DPL,
"negotiation",
2,
"rowIdx: {}, cell: {}, power incompatible",
rowIdx,
cell.db_inst->getName());
return false;
}
}
return true;
}

std::vector<int> NegotiationLegalizer::verticalWindowRows(const NegCell& cell,
int seed_y,
int probe_x,
int count_per_side,
int max_scan) const
{
// A "wall" in the Y direction is off-core: the die edge, or a band of rows
// with no placement sites at all (e.g. a full-width macro/blockage row).
//
// Note we deliberately do NOT treat a macro that merely overlaps the probe
// column (capacity == 0 at probe_x) as a vertical wall. probe_x is the
// cell's global-placement x, which may sit on top of a macro horizontally;
// that horizontal obstruction is resolved by the X-axis window extension, so
// it must not collapse the vertical row search.
auto hardWall = [&](int r) {
if (r < 0 || r + cell.height > grid_h_) {
return true;
}
for (int dy = 0; dy < cell.height; ++dy) {
if (!row_has_sites_[r + dy]) {
return true;
}
}
return false;
};

// Collect up to `target_valid` valid rows on one side, walking outward until
// it has enough, hits a macro/off-core wall, or exceeds `step_cap` steps.
// `step_cap` may exceed `max_scan` so the open side can reach further when
// the opposite side is walled.
auto scan = [&](int dir, int target_valid, int step_cap, bool& hit_wall) {
std::vector<int> found;
hit_wall = false;
for (int step = 1;
step <= step_cap && std::cmp_less(found.size(), target_valid);
++step) {
const int r = seed_y + dir * step;
if (hardWall(r)) {
hit_wall = true;
break;
}
if (isValidRow(r, cell, probe_x)) {
found.push_back(r);
}
}
return found;
};

// First pass: the nominal symmetric window — up to count_per_side valid rows
// on each side, within the max_scan step budget.
bool below_wall = false;
bool above_wall = false;
std::vector<int> below = scan(+1, count_per_side, max_scan, below_wall);
std::vector<int> above = scan(-1, count_per_side, max_scan, above_wall);

// When a macro/off-core wall cuts one side short of its quota, extend the
// opposite (open) side by the shortfall so the same number of candidate rows
// is still explored. The open side is allowed to walk past max_scan (capped
// at 2 * max_scan) to find the extra rows.
const int extended_step_cap
= std::min(2 * max_scan, opendp_->max_displacement_y_);
const int below_deficit
= (below_wall && !disable_window_extension_)
? count_per_side - static_cast<int>(below.size())
: 0;
const int above_deficit
= (above_wall && !disable_window_extension_)
? count_per_side - static_cast<int>(above.size())
: 0;
if (above_deficit > 0 && !below_wall) {
bool dummy = false;
below = scan(+1, count_per_side + above_deficit, extended_step_cap, dummy);
}
if (below_deficit > 0 && !above_wall) {
bool dummy = false;
above = scan(-1, count_per_side + below_deficit, extended_step_cap, dummy);
}

std::vector<int> rows;
rows.reserve(below.size() + above.size() + 1);
if (isValidRow(seed_y, cell, probe_x)) {
rows.push_back(seed_y);
}
rows.insert(rows.end(), below.begin(), below.end());
rows.insert(rows.end(), above.begin(), above.end());
return rows;
}

bool NegotiationLegalizer::respectsFence(int cell_idx, int x, int y) const
{
const NegCell& cell = cells_[cell_idx];
Expand Down
49 changes: 48 additions & 1 deletion src/dpl/src/NegotiationLegalizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ class NegotiationLegalizer
void setRowSearchWindow(int w) { row_search_window_ = w; }
void setDrcPenalty(double p) { drc_penalty_ = p; }
void setNumThreads(int n) { num_threads_ = n; }
// When set, disables the wall-deficit search-window extension in
// horizontalWindowBounds/verticalWindowRows: a cell blocked short on one
// side no longer gets that lost reach shifted onto the open side.
void setDisableWindowExtension(bool disable)
{
disable_window_extension_ = disable;
}

// Metrics (valid after legalize())
[[nodiscard]] double avgDisplacement() const;
Expand Down Expand Up @@ -200,8 +207,47 @@ class NegotiationLegalizer
[[nodiscard]] bool isValidRow(int rowIdx,
const NegCell& cell,
int gridX) const;
// Collect up to `count_per_side` rail-/site-compatible rows on each side of
// `seed_y`, plus `seed_y` itself when valid. Walks outward one row at a time
// and stops a side after `max_scan` steps or at an off-core wall. When one
// side is walled short of its quota, the open side is extended (past
// `max_scan`) by the shortfall. Lets the Y search adapt to cell height: for
// tall cells, valid rows are sparser, so the effective Y reach grows.
[[nodiscard]] std::vector<int> verticalWindowRows(const NegCell& cell,
int seed_y,
int probe_x,
int count_per_side,
int max_scan) const;
[[nodiscard]] bool respectsFence(int cell_idx, int x, int y) const;
[[nodiscard]] bool inDie(int x, int y, int w, int h) const;
[[nodiscard]] int effectiveSiteWindow(const NegCell& cell) const;
[[nodiscard]] int effectiveRowCap(const NegCell& cell) const;

// The rectangular candidate region findBestLocation scans around an anchor
// point. The horizontal reach (dx_lo..dx_hi, inclusive offsets from
// anchor_x) is already shifted away from any macro/off-core wall, and `rows`
// is the set of valid rows to visit, vertically extended past an off-core
// wall. Built once per anchor by buildSearchWindow().
struct SearchWindow
{
int dx_lo{0};
int dx_hi{0};
std::vector<int> rows;
};
[[nodiscard]] SearchWindow buildSearchWindow(const NegCell& cell,
int anchor_x,
int anchor_y) const;

// Asymmetric X search bounds around base_x on row target_y. When a macro or
// the core boundary cuts one side of the symmetric [-site_window,
// +site_window] window short, the lost reach is shifted to the opposite side
// so the same number of candidate sites is still explored. Returns the
// inclusive (dx_lo, dx_hi) offsets.
[[nodiscard]] std::pair<int, int> horizontalWindowBounds(
const NegCell& cell,
int base_x,
int target_y,
int site_window) const;
[[nodiscard]] std::pair<int, int> snapToLegal(int cell_idx,
int x,
int y) const;
Expand Down Expand Up @@ -267,6 +313,7 @@ class NegotiationLegalizer
int max_disp_threshold_{kThDefault}; // th on the paper
int max_iter_neg_{kMaxIterNeg};
int site_search_window_{kSiteSearchWindow};
int row_search_window_{kRowSearchWindow};
int current_iter_{0}; // updated at the start of each negotiationIter call

// Last-iteration stats, kept so runNegotiation can print the final row.
Expand All @@ -281,10 +328,10 @@ class NegotiationLegalizer
// are rendered in grey while current-iteration movers keep directional
// colors.
std::unordered_set<odb::dbInst*> current_iter_movers_;
int row_search_window_{kRowSearchWindow};
double drc_penalty_{kDrcPenalty};
int num_threads_{1};
bool run_abacus_{false};
bool disable_window_extension_{false};

// Mutable profiling accumulators for findBestLocation breakdown (seconds).
mutable double prof_init_search_s_{0};
Expand Down
Loading
Loading