Skip to content
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
33 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
5ce3432
dpl: actually disable all extension with the new TCL command -disable…
gudeh Jul 8, 2026
4d6b64d
dpl: new test for negotiation legalizer with multi height instances
gudeh Jul 8, 2026
dc273da
dpl: debug, automatic zoom in to instance when in deep iterative mode
gudeh Jul 8, 2026
40a30c0
dpl: rework negotiation window extensions for walls (off-core, and fi…
gudeh Jul 9, 2026
01d6f67
Merge remote-tracking branch 'private/master' into dpl-negotiation-dy…
gudeh Jul 9, 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
6 changes: 6 additions & 0 deletions src/dpl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ detailed_placement
[-report_file_name filename]
[-use_negotiation]
[-abacus]
[-site_search_window sites]
[-row_search_window rows]
[-drc_penalty penalty]
```

#### Options
Expand All @@ -86,6 +89,9 @@ detailed_placement
| `-report_file_name` | File name for saving the report to (e.g. `report.json`.) |
| `-use_negotiation` | Use the NegotiationLegalizer instead of the default diamond search engine. |
| `-abacus` | Enable the Abacus pre-pass within the NegotiationLegalizer. Only effective when `-use_negotiation` is set. |
| `-site_search_window` | NegotiationLegalizer: maximum number of sites a cell may be moved left or right of its initial position. Default `20`. |
| `-row_search_window` | NegotiationLegalizer: maximum number of rows a cell may be moved up or down from its initial position. Default `5`. |
| `-drc_penalty` | NegotiationLegalizer: priority to DRC violations, ramped up each iteration to push DRC cleanup later in the run. Lower values tolerate DRC violations early on while overlaps are resolved. Default `5`. |

### Set Placement Padding

Expand Down
13 changes: 11 additions & 2 deletions src/dpl/include/dpl/Opendp.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,10 @@ class Opendp
const std::string& report_file_name = std::string(""),
bool incremental = false,
bool use_negotiation = false,
bool run_abacus = false);
bool run_abacus = false,
int site_search_window = 0,
int row_search_window = 0,
double drc_penalty = 0.0);
void reportLegalizationStats() const;

void setPaddingGlobal(int left, int right);
Expand All @@ -120,6 +123,8 @@ class Opendp
void setJumpMoves(int jump_moves);
void setIterativePlacement(bool iterative);
void setDeepIterativePlacement(bool deep_iterative);
void setNegotiationDebugInterval(int iterative_jump);
void setNegotiationDebugStart(int iterative_start);

// Global padding.
int padGlobalLeft() const;
Expand Down Expand Up @@ -366,8 +371,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 Expand Up @@ -398,6 +405,8 @@ class Opendp
int move_count_ = 1;
bool iterative_debug_ = false;
bool deep_iterative_debug_ = false;
int negotiation_debug_interval_ = 1;
int negotiation_debug_start_ = 0;
bool incremental_ = false;
bool use_negotiation_ = false;

Expand Down
146 changes: 122 additions & 24 deletions src/dpl/src/NegotiationLegalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ void NegotiationLegalizer::legalize()
1,
"NegotiationLegalizer: starting legalization.");

logger_->info(utl::DPL,
1103,
"NegotiationLegalizer search window: +/-{} sites horizontally, "
"+/-{} rows vertically.",
site_search_window_,
row_search_window_);

logger_->info(
utl::DPL, 1104, "NegotiationLegalizer DRC penalty: {}.", drc_penalty_);

double init_from_db_s{0}, build_grid_s{0}, fence_regions_s{0}, abacus_s{0};
double negotiation_s{0}, post_neg_sync_s{0}, metrics_s{0}, flush_s{0},
orient_s{0};
Expand All @@ -114,7 +124,6 @@ void NegotiationLegalizer::legalize()

if (debug_observer_) {
debug_observer_->startPlacement(db_->getChip()->getBlock());
debugPause("Pause after initFromDb.");
}

{
Expand All @@ -137,6 +146,8 @@ void NegotiationLegalizer::legalize()
initFenceRegions();
}

debugPause("Pause after initialization.");

debugPrint(logger_,
utl::DPL,
"negotiation",
Expand Down Expand Up @@ -225,12 +236,17 @@ void NegotiationLegalizer::legalize()
}

if (debug_observer_) {
setDplPositions();
commitNegotiationPosToDpl();
// this flush may imply functional changes. It hides initial movements for
// clean debugging negotiation phase.
flushToDb();
logger_->report(
"Committing post-init positions to odb; debug move line drawings will "
"exclude gpl-to-init displacement.");
commitNegotiationPosToOdb();
pushNegotiationPixels();
logger_->report("Pause after Abacus pass.");
logger_->report(run_abacus_
? "Pause after initialization: Abacus executed."
: "Pause after initialization: Abacus skipped.");
debug_observer_->redrawAndPause();
}

Expand Down Expand Up @@ -302,12 +318,6 @@ void NegotiationLegalizer::legalize()
maxDisp,
nViol);

{
utl::DebugScopedTimer t(
flush_s, logger_, utl::DPL, "negotiation_runtime", 1, "flushToDb: {}");
flushToDb();
}

{
utl::DebugScopedTimer t(orient_s,
logger_,
Expand All @@ -332,6 +342,16 @@ void NegotiationLegalizer::legalize()
}
}

{
utl::DebugScopedTimer t(flush_s,
logger_,
utl::DPL,
"negotiation_runtime",
1,
"commitNegotiationPosToOdb: {}");
commitNegotiationPosToOdb();
}

const double total_s = total_timer.elapsed();
auto pct
= [total_s](double t) { return total_s > 0 ? 100.0 * t / total_s : 0.0; };
Expand All @@ -348,7 +368,7 @@ void NegotiationLegalizer::legalize()
"negotiation {:.1f}ms ({:.0f}%), "
"postNegSync {:.1f}ms ({:.0f}%), "
"metrics {:.1f}ms ({:.0f}%), "
"flushToDb {:.1f}ms ({:.0f}%), "
"commitNegotiationPosToOdb {:.1f}ms ({:.0f}%), "
"orientUpdate {:.1f}ms ({:.0f}%)",
to_ms(total_s),
to_ms(init_from_db_s),
Expand All @@ -369,13 +389,16 @@ void NegotiationLegalizer::legalize()
pct(flush_s),
to_ms(orient_s),
pct(orient_s));

debugPause("Pause after legalization complete.");
}

// ===========================================================================
// flushToDb – write current cell positions to ODB so the GUI reflects them
// commitNegotiationPosToOdb – write current cell positions to ODB so the GUI
// reflects them
// ===========================================================================

void NegotiationLegalizer::flushToDb()
void NegotiationLegalizer::commitNegotiationPosToOdb()
{
const Grid* dplGrid = opendp_->grid_.get();
for (const auto& cell : cells_) {
Expand Down Expand Up @@ -454,17 +477,18 @@ void NegotiationLegalizer::debugPause(const std::string& msg)
if (!debug_observer_) {
return;
}
setDplPositions();
commitNegotiationPosToDpl();
pushNegotiationPixels();
logger_->report("{}", msg);
debug_observer_->redrawAndPause();
}

// ===========================================================================
// setDplPositions – pass the positions to the DPL original structure (Node)
// commitNegotiationPosToDpl – pass the positions to the DPL original structure
// (Node)
// ===========================================================================

void NegotiationLegalizer::setDplPositions()
void NegotiationLegalizer::commitNegotiationPosToDpl()
{
if (!network_) {
return;
Expand Down Expand Up @@ -1012,7 +1036,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 @@ -1039,19 +1062,94 @@ 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 below_deficit
= below_wall ? count_per_side - static_cast<int>(below.size()) : 0;
const int above_deficit
= above_wall ? 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, 2 * max_scan, dummy);
}
if (below_deficit > 0 && !above_wall) {
bool dummy = false;
above = scan(-1, count_per_side + below_deficit, 2 * max_scan, 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
Loading
Loading