diff --git a/src/cts/test/array.ok b/src/cts/test/array.ok index c6758384ebc..2e43c041f79 100644 --- a/src/cts/test/array.ok +++ b/src/cts/test/array.ok @@ -132,7 +132,9 @@ Dummys used: [INFO RSZ-0058] Using max wire length 693um. [INFO RSZ-0047] Found 40 long wires. [INFO RSZ-0048] Inserted 88 buffers in 40 nets. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 24399648.00 um^2, Instances area: 20261654.79 um^2, Utilization: 83.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 2902 diff --git a/src/cts/test/array_ins_delay.ok b/src/cts/test/array_ins_delay.ok index a8b2e075d5a..5afeb694979 100644 --- a/src/cts/test/array_ins_delay.ok +++ b/src/cts/test/array_ins_delay.ok @@ -122,7 +122,9 @@ [INFO RSZ-0058] Using max wire length 693um. [INFO RSZ-0047] Found 40 long wires. [INFO RSZ-0048] Inserted 88 buffers in 40 nets. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 24399648.00 um^2, Instances area: 20261654.79 um^2, Utilization: 83.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 2902 diff --git a/src/cts/test/array_max_wl.ok b/src/cts/test/array_max_wl.ok index 70d56140b99..cb053d87400 100644 --- a/src/cts/test/array_max_wl.ok +++ b/src/cts/test/array_max_wl.ok @@ -572,7 +572,9 @@ TritonCTS forced slew degradation on these wires. [INFO RSZ-0058] Using max wire length 693um. [INFO RSZ-0047] Found 41 long wires. [INFO RSZ-0048] Inserted 87 buffers in 41 nets. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 24399648.00 um^2, Instances area: 20261996.33 um^2, Utilization: 83.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 3088 diff --git a/src/cts/test/array_no_blockages.ok b/src/cts/test/array_no_blockages.ok index 8cff6dfb2a1..93f163c7190 100644 --- a/src/cts/test/array_no_blockages.ok +++ b/src/cts/test/array_no_blockages.ok @@ -121,7 +121,9 @@ [INFO RSZ-0058] Using max wire length 693um. [INFO RSZ-0047] Found 42 long wires. [INFO RSZ-0048] Inserted 92 buffers in 42 nets. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 24399648.00 um^2, Instances area: 20261660.91 um^2, Utilization: 83.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 2907 diff --git a/src/cts/test/array_repair_clock_nets.ok b/src/cts/test/array_repair_clock_nets.ok index e715bb19135..2c73ca556e7 100644 --- a/src/cts/test/array_repair_clock_nets.ok +++ b/src/cts/test/array_repair_clock_nets.ok @@ -136,7 +136,9 @@ Dummys used: [INFO RSZ-0058] Using max wire length 693um. [INFO RSZ-0047] Found 5 long wires. [INFO RSZ-0048] Inserted 5 buffers in 5 nets. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 24399648.00 um^2, Instances area: 20261659.31 um^2, Utilization: 83.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 2901 diff --git a/src/cts/test/gated_clock4.ok b/src/cts/test/gated_clock4.ok index 0cf0800df2e..8cd7fdae3c5 100644 --- a/src/cts/test/gated_clock4.ok +++ b/src/cts/test/gated_clock4.ok @@ -48,7 +48,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000008 HPWL: 61445 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000011 HPWL: 61447 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000011 HPWL: 61445 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 999570.01 um^2, Instances area: 1274.41 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 283 diff --git a/src/cts/test/hier_insertion_delay.ok b/src/cts/test/hier_insertion_delay.ok index bc959819bf2..5bea7f4c294 100644 --- a/src/cts/test/hier_insertion_delay.ok +++ b/src/cts/test/hier_insertion_delay.ok @@ -50,7 +50,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000012 HPWL: 1229790 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000012 HPWL: 1229790 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000012 HPWL: 1229790 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 1357.12 um^2, Utilization: 2.8% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 278 diff --git a/src/cts/test/simple_test_hier.ok b/src/cts/test/simple_test_hier.ok index f6bbd73975f..13e653e7cd5 100644 --- a/src/cts/test/simple_test_hier.ok +++ b/src/cts/test/simple_test_hier.ok @@ -48,7 +48,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000010 HPWL: 9260 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000010 HPWL: 9260 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000010 HPWL: 9260 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 72.35 um^2, Utilization: 0.2% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 16 diff --git a/src/dbSta/test/escape_slash.ok b/src/dbSta/test/escape_slash.ok index 111762907ac..461140d0146 100644 --- a/src/dbSta/test/escape_slash.ok +++ b/src/dbSta/test/escape_slash.ok @@ -47,7 +47,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000010 HPWL: 61447 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000008 HPWL: 61444 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000009 HPWL: 61447 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 999570.01 um^2, Instances area: 1274.41 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 283 diff --git a/src/dbSta/test/escape_slash_hier.ok b/src/dbSta/test/escape_slash_hier.ok index 50f84a2c8be..e8e497add90 100644 --- a/src/dbSta/test/escape_slash_hier.ok +++ b/src/dbSta/test/escape_slash_hier.ok @@ -48,7 +48,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000008 HPWL: 61445 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000011 HPWL: 61447 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000011 HPWL: 61445 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 999570.01 um^2, Instances area: 1274.41 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 283 diff --git a/src/dpl/BUILD b/src/dpl/BUILD index cb9b843e38e..e04d85939fc 100644 --- a/src/dpl/BUILD +++ b/src/dpl/BUILD @@ -18,6 +18,9 @@ cc_library( "src/CheckPlacement.cpp", "src/DecapPlacement.cpp", "src/FillerPlacement.cpp", + "src/NegotiationLegalizer.cpp", + "src/NegotiationLegalizer.h", + "src/NegotiationLegalizerPass.cpp", "src/Opendp.cpp", "src/OptMirror.cpp", "src/Optdp.cpp", diff --git a/src/dpl/CMakeLists.txt b/src/dpl/CMakeLists.txt index 5996773d5ce..3cd6475ba8f 100644 --- a/src/dpl/CMakeLists.txt +++ b/src/dpl/CMakeLists.txt @@ -26,7 +26,8 @@ add_library(dpl_lib src/DecapPlacement.cpp src/OptMirror.cpp src/PlacementDRC.cpp - + src/NegotiationLegalizer.cpp + src/NegotiationLegalizerPass.cpp src/Optdp.cpp src/infrastructure/architecture.cxx src/util/color.cxx diff --git a/src/dpl/README.md b/src/dpl/README.md index 38d8d9489a4..96a577cdf17 100644 --- a/src/dpl/README.md +++ b/src/dpl/README.md @@ -1,12 +1,60 @@ # Detailed Placement -The detailed placement module in OpenROAD (`dpl`) is based on OpenDP, or -Open-Source Detailed Placement Engine. Its key features are: +The detailed placement module in OpenROAD (`dpl`) is based on OpenDP, or +Open-Source Detailed Placement Engine. Its key features are: -- Fence region. -- Fragmented ROWs. +- Fence region support +- Fragmented row support +- Mixed-cell-height (1x–4x) legalization +- Two placement engines selectable at runtime -## Commands +## Placement Engines + +#### Diamond Search + +The default engine performs a BFS-style diamond search from each cell's +global placement position, expanding outward in Manhattan order until a +legal site is found. + +#### NegotiationLegalizer + +An optional two-pass legalizer based on the NBLG paper. Enabled with +`-use_negotiation` on the `detailed_placement` command. + +``` +Global Placement result + │ + ▼ +┌───────────────────┐ +│ Abacus Pass │ Fast DP sweep, row-by-row. +│ (Skipped) │ Near-optimal for uncongested cells. +│ │ Mixed-cell-height via row assignment. +│ Handles: │ Power-rail alignment enforced. +│ - 1x/2x/3x/4x │ Fence violations → skipped (→ negotiation). +│ - Fence regions │ +└────────┬──────────┘ + │ illegal cells (overlap / fence violated) + ▼ +┌───────────────────┐ +│ Negotiation Pass │ Iterative rip-up & replace (from NBLG paper). +│ │ Illegal cells + spatial neighbors compete for +│ NBLG components: │ grid resources. History cost penalises +│ - Adaptive pf │ persistent congestion. Isolation point skips +│ - Isolation pt │ already-legal cells in phase 2. +│ - History cost │ +└────────┬──────────┘ + │ + ▼ +┌───────────────────┐ +│ Post-optimisation │ Greedy displacement improvement (5 passes). +│ (Skipped) │ Cell swap via bipartite matching within groups. +│ │ +└────────┬──────────┘ + │ + ▼ + Legal placement written back to OpenDB +``` +# Commands ```{note} - Parameters in square brackets `[-param param]` are optional. @@ -23,30 +71,35 @@ detailed_placement [-max_displacement disp|{disp_x disp_y}] [-disallow_one_site_gaps] [-report_file_name filename] + [-use_negotiation] + [-abacus] ``` #### Options -| Switch Name | Description | +| Switch Name | Description | | ----- | ----- | | `-max_displacement` | Max distance that an instance can be moved (in microns) when finding a site where it can be placed. Either set one value for both directions or set `{disp_x disp_y}` for individual directions. The default values are `{0, 0}`, and the allowed values within are integers `[0, MAX_INT]`. | | `-disallow_one_site_gaps` | Option is deprecated. | | `-report_file_name` | File name for saving the report to (e.g. `report.json`.) | | `-incremental` | By default DPL initiates with all instances unplaced. With this flag DPL will check for already legalized instances and set them as placed. | +| `-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. | ### Set Placement Padding The `set_placement_padding` command sets left and right padding in multiples of the row site width. Use the `set_placement_padding` command before legalizing placement to leave room for routing. Use the `-global` flag -for padding that applies to all instances. Use `-instances` +for padding that applies to all instances. Use `-instances` for instance-specific padding. The instances `insts` can be a list of instance names, or an instance object returned by the SDC `get_cells` command. To specify padding for all instances of a common master, use the `-filter` "ref_name == " option to `get_cells`. ```tcl -set_placement_padding +set_placement_padding -global|-masters masters|-instances insts [-right site_count] [-left site_count] @@ -59,7 +112,7 @@ Either one of these flags must be set: `-global | -masters | -instances`. The order of preference is `global > masters > instances` ``` -| Switch Name | Description | +| Switch Name | Description | | ----- | ----- | | `-global` | Set padding globally using `left` and `right` values. | | `-masters` | Set padding only for these masters using `left` and `right` values. | @@ -77,7 +130,7 @@ is supported, so `FILL*` will match, e.g., `FILLCELL_X1 FILLCELL_X16 FILLCELL_X2 FILLCELL_X32 FILLCELL_X4 FILLCELL_X8`. To specify a different naming prefix from `FILLER_` use `-prefix `. -```tcl +```tcl filler_placement [-prefix prefix] [-verbose] @@ -90,14 +143,14 @@ filler_placement | ----- | ----- | | `-prefix` | Prefix to name the filler cells. The default value is `FILLER_`. | | `-verbose` | Print the filler cell usage. | -| `filler_masters` | Filler master cells. | +| `filler_masters` | Filler master cells. | ### Remove Fillers This command removes all filler cells. ```tcl -remove_fillers +remove_fillers ``` ### Check Placement @@ -128,6 +181,7 @@ a weak attempt to reduce the total half-perimeter wirelength (HPWL). ```tcl optimize_mirroring ``` + ### Improve Placement The `improve_placement` command optimizes a given placed design. @@ -150,7 +204,7 @@ If you are a developer, you might find these useful. More details can be found i | `get_inst_bbox` | Get bounding box of an instance. | | `get_inst_grid_bbox` | Get grid bounding box of an instance. | | `format_grid` | Format grid (takes in length `x` and site width `w` as inputs). | -| `get_row_site` | Get row site name. +| `get_row_site` | Get row site name. | ## Example scripts @@ -164,7 +218,7 @@ Examples scripts demonstrating how to run `dpl` on a sample design of `aes` as f There are a set of regression tests in `./test`. Refer to this [section](../../README.md#regression-tests) for more information. -Simply run the following script: +Simply run the following script: ```shell ./test/regression @@ -172,6 +226,25 @@ Simply run the following script: ## Limitations +The following limitations apply when using the NegotiationLegalizer (`-use_negotiation`): + +1. **Abacus cluster chain**: The current Abacus implementation uses a + simplified cluster structure. A production version should maintain an + explicit doubly-linked list of cells within each cluster, as in the + original Spindler et al. paper. + +2. **Multithreading**: The negotiation pass is single-threaded. + Extend with the inter-region parallelism from NBLG (Algorithm 2, dynamic + region adjustment) using OpenMP or std::thread. + +3. **Fence region R-tree**: Replace linear scan in `FenceRegion::nearestRect()` + with a spatial index (Boost.Geometry rtree or OpenROAD's existing RTree) + for large designs with many fence sub-rectangles. + +4. **Row rail inference**: Currently uses row-index parity as a proxy for + VDD/VSS. Replace with actual LEF pg_pin parsing once available in the + build context. + ## FAQs Check out [GitHub discussion](https://github.com/The-OpenROAD-Project/OpenROAD/discussions/categories/q-a?discussions_q=category%3AQ%26A+opendp+in%3Atitle) @@ -184,7 +257,11 @@ about this tool. - Rewrite and port to OpenDB/OpenROAD by James Cherry, Parallax Software ## References + 1. Do, S., Woo, M., & Kang, S. (2019, May). Fence-region-aware mixed-height standard cell legalization. In Proceedings of the 2019 on Great Lakes Symposium on VLSI (pp. 259-262). [(.pdf)](https://dl.acm.org/doi/10.1145/3299874.3318012) +2. P. Spindler et al., "Abacus: Fast legalization of standard cell circuits with minimal movement," ISPD 2008. +3. J. Chen et al., "NBLG: A Robust Legalizer for Mixed-Cell-Height Modern Design," IEEE TCAD, vol. 41, no. 11, 2022. +4. L. McMurchie and C. Ebeling, "PathFinder: A negotiation-based performance-driven router for FPGAs," 1995. ## License diff --git a/src/dpl/include/dpl/Opendp.h b/src/dpl/include/dpl/Opendp.h index cb29060de18..a4ed962849a 100644 --- a/src/dpl/include/dpl/Opendp.h +++ b/src/dpl/include/dpl/Opendp.h @@ -107,7 +107,9 @@ class Opendp void detailedPlacement(int max_displacement_x, int max_displacement_y, const std::string& report_file_name = std::string(""), - bool incremental = false); + bool incremental = false, + bool use_negotiation = false, + bool run_abacus = false); void reportLegalizationStats() const; void setPaddingGlobal(int left, int right); @@ -192,6 +194,7 @@ class Opendp friend class OpendpTest_IsPlaced_Test; friend class Graphics; friend class CellPlaceOrderLess; + friend class NegotiationLegalizer; void findDisplacementStats(); DbuPt pointOffMacro(const Node& cell); void convertDbToCell(odb::dbInst* db_inst, Node& cell); @@ -214,7 +217,7 @@ class Opendp void initPlacementDRC(); std::string printBgBox(const boost::geometry::model::box& queryBox); - void detailedPlacement(); + void diamondDPL(); DbuPt nearestPt(const Node* cell, const DbuRect& rect) const; int distToRect(const Node* cell, const odb::Rect& rect) const; static bool checkOverlap(const odb::Rect& cell, const odb::Rect& box); @@ -394,6 +397,7 @@ class Opendp bool iterative_debug_ = false; bool deep_iterative_debug_ = false; bool incremental_ = false; + bool use_negotiation_ = false; // Magic numbers static constexpr double group_refine_percent_ = .05; diff --git a/src/dpl/src/CheckPlacement.cpp b/src/dpl/src/CheckPlacement.cpp index 5ba8f5d7429..9584f083593 100644 --- a/src/dpl/src/CheckPlacement.cpp +++ b/src/dpl/src/CheckPlacement.cpp @@ -133,7 +133,8 @@ void Opendp::checkPlacement(const bool verbose, + region_placement_failures.size() + edge_spacing_failures.size() + blocked_layers_failures.size() > 0) { - logger_->error(DPL, 33, "detailed placement checks failed."); + logger_->error( + DPL, 33, "detailed placement checks failed during check placement."); } } diff --git a/src/dpl/src/NegotiationLegalizer.cpp b/src/dpl/src/NegotiationLegalizer.cpp new file mode 100644 index 00000000000..df06af4dcaa --- /dev/null +++ b/src/dpl/src/NegotiationLegalizer.cpp @@ -0,0 +1,1307 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2018-2026, The OpenROAD Authors + +#include "NegotiationLegalizer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PlacementDRC.h" +#include "dpl/Opendp.h" +#include "graphics/DplObserver.h" +#include "infrastructure/Grid.h" +#include "infrastructure/Objects.h" +#include "infrastructure/Padding.h" +#include "infrastructure/network.h" +#include "odb/db.h" +#include "odb/geom.h" +#include "utl/Logger.h" +#include "utl/timer.h" + +namespace dpl { + +// =========================================================================== +// FenceRegion +// =========================================================================== + +bool FenceRegion::contains(int x, int y, int w, int h) const +{ + for (const auto& r : rects) { + if (x >= r.xlo && y >= r.ylo && x + w <= r.xhi && y + h <= r.yhi) { + return true; + } + } + return false; +} + +FenceRect FenceRegion::nearestRect(int cx, int cy) const +{ + assert(!rects.empty()); + const FenceRect* best = rects.data(); + int best_dist = std::numeric_limits::max(); + for (const auto& r : rects) { + const int d = odb::manhattanDistance(odb::Rect(r.xlo, r.ylo, r.xhi, r.yhi), + odb::Point(cx, cy)); + if (d < best_dist) { + best_dist = d; + best = &r; + } + } + return *best; +} + +// =========================================================================== +// Constructor +// =========================================================================== + +NegotiationLegalizer::NegotiationLegalizer(Opendp* opendp, + odb::dbDatabase* db, + utl::Logger* logger, + const Padding* padding, + DplObserver* debug_observer, + Network* network) + : opendp_(opendp), + db_(db), + logger_(logger), + padding_(padding), + debug_observer_(debug_observer), + network_(network) +{ +} + +// =========================================================================== +// legalize – top-level entry point +// =========================================================================== + +void NegotiationLegalizer::legalize() +{ + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "NegotiationLegalizer: starting legalization."); + + 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}; + const utl::Timer total_timer; + + { + utl::DebugScopedTimer t(init_from_db_s, + logger_, + utl::DPL, + "negotiation_runtime", + 1, + "initFromDb: {}"); + if (!initFromDb()) { + return; + } + } + + if (debug_observer_) { + debug_observer_->startPlacement(db_->getChip()->getBlock()); + debugPause("Pause after initFromDb."); + } + + { + utl::DebugScopedTimer t(build_grid_s, + logger_, + utl::DPL, + "negotiation_runtime", + 1, + "buildGrid: {}"); + buildGrid(); + } + + { + utl::DebugScopedTimer t(fence_regions_s, + logger_, + utl::DPL, + "negotiation_runtime", + 1, + "initFenceRegions: {}"); + initFenceRegions(); + } + + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "NegotiationLegalizer: {} cells, grid {}x{}.", + cells_.size(), + grid_w_, + grid_h_); + + // --- Part 1: Abacus (handles the majority of cells cheaply) ------------- + std::vector illegal; + if (run_abacus_) { + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "NegotiationLegalizer: running Abacus pass."); + { + utl::DebugScopedTimer t(abacus_s, + logger_, + utl::DPL, + "negotiation_runtime", + 1, + "runAbacus: {}"); + illegal = runAbacus(); + } + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "NegotiationLegalizer: Abacus done, {} cells still illegal.", + illegal.size()); + } else { + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "NegotiationLegalizer: skipping Abacus pass."); + { + utl::DebugScopedTimer t(abacus_s, + logger_, + utl::DPL, + "negotiation_runtime", + 1, + "skip-Abacus addUsage: {}"); + // Populate usage from initial coordinates + for (int i = 0; i < static_cast(cells_.size()); ++i) { + if (!cells_[i].fixed) { + addUsage(i, 1); + } + } + } + { + utl::DebugScopedTimer t(abacus_s, + logger_, + utl::DPL, + "negotiation_runtime", + 1, + "skip-Abacus syncAllCellsToDplGrid: {}"); + // Sync all movable cells to the DPL Grid so PlacementDRC neighbour + // lookups see the correct placement state. + syncAllCellsToDplGrid(); + } + { + utl::DebugScopedTimer t(abacus_s, + logger_, + utl::DPL, + "negotiation_runtime", + 1, + "skip-Abacus isCellLegal scan: {}"); + for (int i = 0; i < static_cast(cells_.size()); ++i) { + if (!cells_[i].fixed) { + cells_[i].legal = isCellLegal(i); + if (!cells_[i].legal) { + illegal.push_back(i); + } + } + } + } + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "{} illegal cells", + illegal.size()); + } + + if (debug_observer_) { + setDplPositions(); + // this flush may imply functional changes. It hides initial movements for + // clean debugging negotiation phase. + flushToDb(); + pushNegotiationPixels(); + logger_->report("Pause after Abacus pass."); + debug_observer_->redrawAndPause(); + } + + // --- Part 2: Negotiation (main legalization) ------------------- + if (!illegal.empty()) { + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "NegotiationLegalizer: negotiation pass on {} cells.", + illegal.size()); + utl::DebugScopedTimer t(negotiation_s, + logger_, + utl::DPL, + "negotiation_runtime", + 1, + "runNegotiation: {}"); + runNegotiation(illegal); + } + + // Re-sync the DPL pixel grid after negotiation. During negotiation, + // overlapping cells share a single pixel->cell slot; when one is ripped + // up, the other's presence is lost. A full re-sync ensures every cell + // is correctly painted so subsequent DRC checks (numViolations, etc.) + // see the true placement state. + { + utl::DebugScopedTimer t(post_neg_sync_s, + logger_, + utl::DPL, + "negotiation_runtime", + 1, + "post-negotiation syncAllCellsToDplGrid: {}"); + syncAllCellsToDplGrid(); + } + + debugPause("Pause after negotiation pass"); + + // --- Part 3: Post-optimisation ------------------------------------------ + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "NegotiationLegalizer: post-optimisation."); + // greedyImprove(5); + // cellSwap(); + // greedyImprove(1); + + double avgDisp{0}; + int maxDisp{0}, nViol{0}; + { + utl::DebugScopedTimer t(metrics_s, + logger_, + utl::DPL, + "negotiation_runtime", + 1, + "metrics (avgDisp/maxDisp/violations): {}"); + avgDisp = avgDisplacement(); + maxDisp = maxDisplacement(); + nViol = numViolations(); + } + + debugPrint( + logger_, + utl::DPL, + "negotiation", + 1, + "NegotiationLegalizer: done. AvgDisp={:.2f} MaxDisp={} Violations={}.", + avgDisp, + maxDisp, + nViol); + + { + utl::DebugScopedTimer t( + flush_s, logger_, utl::DPL, "negotiation_runtime", 1, "flushToDb: {}"); + flushToDb(); + } + + { + utl::DebugScopedTimer t(orient_s, + logger_, + utl::DPL, + "negotiation_runtime", + 1, + "orientation update: {}"); + const Grid* dplGrid = opendp_->grid_.get(); + for (const auto& cell : cells_) { + if (cell.fixed || cell.db_inst == nullptr) { + continue; + } + // Set orientation from the row so cells are properly flipped. + odb::dbSite* site = cell.db_inst->getMaster()->getSite(); + if (site != nullptr) { + auto orient + = dplGrid->getSiteOrientation(GridX{cell.x}, GridY{cell.y}, site); + if (orient.has_value()) { + cell.db_inst->setOrient(orient.value()); + } + } + } + } + + const double total_s = total_timer.elapsed(); + auto pct + = [total_s](double t) { return total_s > 0 ? 100.0 * t / total_s : 0.0; }; + auto to_ms = [](double s) { return s * 1e3; }; + debugPrint(logger_, + utl::DPL, + "negotiation_runtime", + 1, + "legalize() total {:.1f}ms breakdown: " + "initFromDb {:.1f}ms ({:.0f}%), " + "buildGrid {:.1f}ms ({:.0f}%), " + "initFenceRegions {:.1f}ms ({:.0f}%), " + "abacus {:.1f}ms ({:.0f}%), " + "negotiation {:.1f}ms ({:.0f}%), " + "postNegSync {:.1f}ms ({:.0f}%), " + "metrics {:.1f}ms ({:.0f}%), " + "flushToDb {:.1f}ms ({:.0f}%), " + "orientUpdate {:.1f}ms ({:.0f}%)", + to_ms(total_s), + to_ms(init_from_db_s), + pct(init_from_db_s), + to_ms(build_grid_s), + pct(build_grid_s), + to_ms(fence_regions_s), + pct(fence_regions_s), + to_ms(abacus_s), + pct(abacus_s), + to_ms(negotiation_s), + pct(negotiation_s), + to_ms(post_neg_sync_s), + pct(post_neg_sync_s), + to_ms(metrics_s), + pct(metrics_s), + to_ms(flush_s), + pct(flush_s), + to_ms(orient_s), + pct(orient_s)); +} + +// =========================================================================== +// flushToDb – write current cell positions to ODB so the GUI reflects them +// =========================================================================== + +void NegotiationLegalizer::flushToDb() +{ + const Grid* dplGrid = opendp_->grid_.get(); + for (const auto& cell : cells_) { + if (cell.fixed || cell.db_inst == nullptr) { + continue; + } + const int db_x = die_xlo_ + cell.x * site_width_; + const int db_y = die_ylo_ + dplGrid->gridYToDbu(GridY{cell.y}).v; + cell.db_inst->setPlacementStatus(odb::dbPlacementStatus::PLACED); + cell.db_inst->setLocation(db_x, db_y); + } +} + +// =========================================================================== +// pushNegotiationPixels – send grid state to the debug observer for rendering +// =========================================================================== + +void NegotiationLegalizer::pushNegotiationPixels() +{ + if (!debug_observer_) { + return; + } + std::vector pixels(static_cast(grid_w_) + * grid_h_); + for (int gy = 0; gy < grid_h_; ++gy) { + for (int gx = 0; gx < grid_w_; ++gx) { + const Pixel& g = gridAt(gx, gy); + const int idx = gy * grid_w_ + gx; + if (g.capacity == 0) { + pixels[idx] = (g.usage > 0) ? NegotiationPixelState::kBlocked + : NegotiationPixelState::kNoRow; + } else if (g.overuse() > 0) { + pixels[idx] = NegotiationPixelState::kOveruse; + } else if (g.usage > 0) { + pixels[idx] = NegotiationPixelState::kOccupied; + } else { + pixels[idx] = NegotiationPixelState::kFree; + } + } + } + // Overlay cells that fail PlacementDRC checks. + if (opendp_->drc_engine_ && network_) { + for (const auto& cell : cells_) { + if (cell.fixed) { + continue; + } + Node* node = network_->getNode(cell.db_inst); + if (node == nullptr) { + continue; + } + if (!opendp_->drc_engine_->checkDRC( + node, GridX{cell.x}, GridY{cell.y}, node->getOrient())) { + for (int dy = 0; dy < cell.height; ++dy) { + for (int gx = cell.x; gx < cell.x + cell.width; ++gx) { + const int pidx = (cell.y + dy) * grid_w_ + gx; + if (pidx >= 0 && pidx < static_cast(pixels.size())) { + pixels[pidx] = NegotiationPixelState::kDrcViolation; + } + } + } + } + } + } + + const Grid* dplGrid = opendp_->grid_.get(); + std::vector row_y_dbu(grid_h_ + 1); + for (int r = 0; r <= grid_h_; ++r) { + row_y_dbu[r] = dplGrid->gridYToDbu(GridY{r}).v; + } + debug_observer_->setNegotiationPixels( + pixels, grid_w_, grid_h_, die_xlo_, die_ylo_, site_width_, row_y_dbu); +} + +void NegotiationLegalizer::debugPause(const std::string& msg) +{ + if (!debug_observer_) { + return; + } + setDplPositions(); + pushNegotiationPixels(); + logger_->report("{}", msg); + debug_observer_->redrawAndPause(); +} + +// =========================================================================== +// setDplPositions – pass the positions to the DPL original structure (Node) +// =========================================================================== + +void NegotiationLegalizer::setDplPositions() +{ + if (!network_) { + return; + } + std::unordered_map inst_to_node; + inst_to_node.reserve(network_->getNodes().size()); + for (const auto& node_ptr : network_->getNodes()) { + if (node_ptr->getDbInst()) { + inst_to_node[node_ptr->getDbInst()] = node_ptr.get(); + } + } + + for (const auto& cell : cells_) { + if (cell.fixed || cell.db_inst == nullptr) { + continue; + } + auto it = inst_to_node.find(cell.db_inst); + if (it != inst_to_node.end()) { + const int coreX = cell.x * site_width_; + const int coreY = opendp_->grid_->gridYToDbu(GridY{cell.y}).v; + it->second->setLeft(DbuX(coreX)); + it->second->setBottom(DbuY(coreY)); + it->second->setPlaced(true); + + // Update orientation to match the row. + odb::dbSite* site = cell.db_inst->getMaster()->getSite(); + if (site != nullptr) { + auto orient = opendp_->grid_->getSiteOrientation( + GridX{cell.x}, GridY{cell.y}, site); + if (orient.has_value()) { + it->second->setOrient(orient.value()); + } + } + } + } +} + +// =========================================================================== +// Initialisation +// =========================================================================== + +bool NegotiationLegalizer::initFromDb() +{ + if (db_->getChip() == nullptr || !opendp_ || !opendp_->grid_) { + return false; + } + auto* block = db_->getChip()->getBlock(); + if (block == nullptr) { + return false; + } + + const Grid* dpl_grid = opendp_->grid_.get(); + + const odb::Rect core_area = dpl_grid->getCore(); + die_xlo_ = core_area.xMin(); + die_ylo_ = core_area.yMin(); + die_xhi_ = core_area.xMax(); + die_yhi_ = core_area.yMax(); + + // Site width from the DPL grid; row height from the first DB row. + site_width_ = dpl_grid->getSiteWidth().v; + for (auto* row : block->getRows()) { + row_height_ = row->getSite()->getHeight(); + break; + } + assert(site_width_ > 0 && row_height_ > 0); + + // Grid dimensions from the DPL grid (accounts for actual DB rows). + 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. + 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; + } + + // Build NegCell records from all placed instances. + cells_.clear(); + cells_.reserve(block->getInsts().size()); + + for (auto* db_inst : block->getInsts()) { + const auto status = db_inst->getPlacementStatus(); + if (status == odb::dbPlacementStatus::NONE) { + continue; + } + // Skip non-core-auto-placeable instances (pads, blocks, etc.) — these + // are absent from the Opendp network so DRC/legality checks can't be + // performed on them. They are handled separately by setFixedGridCells(). + if (!db_inst->getMaster()->isCoreAutoPlaceable()) { + continue; + } + + NegCell cell; + cell.db_inst = db_inst; + cell.fixed = status.isFixed(); + + int db_x = 0; + int db_y = 0; + db_inst->getLocation(db_x, db_y); + // Snap to grid, findBestLocation() and snapToLegal() iterate over grid + // positions + cell.init_x = dpl_grid->gridX(DbuX{db_x - die_xlo_}).v; + cell.init_y = dpl_grid->gridRoundY(DbuY{db_y - die_ylo_}).v; + + // Width/height must be computed before clamping so the upper bounds + // account for the full cell footprint (x + width <= grid_w_, etc.). + auto* master = db_inst->getMaster(); + cell.width = std::max( + 1, + static_cast( + std::round(static_cast(master->getWidth()) / site_width_))); + cell.height = std::max( + 1, + static_cast(std::round(static_cast(master->getHeight()) + / row_height_))); + + // Clamp to valid grid range – gridRoundY can return grid_h_ when the + // instance is near the top edge. Use (grid_w_ - width) so the full + // footprint stays within the grid (matches Opendp::legalPt behaviour). + cell.init_x = std::max(0, std::min(cell.init_x, grid_w_ - cell.width)); + cell.init_y = std::max(0, std::min(cell.init_y, grid_h_ - cell.height)); + cell.x = cell.init_x; + cell.y = cell.init_y; + + // gridX() / gridRoundY() are purely arithmetic and don't check whether a + // site actually exists at the computed position. Instances near the chip + // boundary or in sparse-row designs can land on invalid (is_valid=false) + // pixels pixels or on pixels that don't support this cell's site type. Fix + // those with a diamond search from the initial position; we only check site + // validity here, not blockages — the negotiation part handles those. + if (!cell.fixed) { + odb::dbSite* site = master->getSite(); + // Check that the full cell footprint (width x height) fits on valid + // sites. + auto isValidSite = [&](int gx, int gy) -> bool { + if (gx < 0 || gx + cell.width > grid_w_ || gy < 0 + || gy + cell.height > grid_h_) { + return false; + } + // Site type check at the anchor row is representative for all rows. + if (site != nullptr + && !dpl_grid->getSiteOrientation(GridX{gx}, GridY{gy}, site) + .has_value()) { + return false; + } + for (int dy = 0; dy < cell.height; ++dy) { + for (int dx = 0; dx < cell.width; ++dx) { + if (!dpl_grid->pixel(GridY{gy + dy}, GridX{gx + dx}).is_valid) { + return false; + } + } + } + return true; + }; + + // The snapping here is actually quite similar to the "hopeless" approach + // 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)) { + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "Instance {} at ({}, {}) snaps to invalid site at " + "({}, {}). Searching for nearest valid site.", + cell.db_inst->getName(), + db_x, + db_y, + die_xlo_ + cell.init_x * site_width_, + die_ylo_ + cell.init_y * row_height_); + + // Priority queue keyed on physical Manhattan distance (DBU) so the + // search expands in true physical proximity, not grid-unit proximity. + // One step in X = site_width_ DBU; one step in Y = row_height_ DBU. + using PQEntry = std::tuple; // physDist, gx, gy + std:: + priority_queue, std::greater> + pq; + std::unordered_set visited; + + auto tryEnqueue = [&](int gx, int gy) { + // Leave room for the full cell footprint before enqueueing. + if (gx < 0 || gx + cell.width > grid_w_ || gy < 0 + || gy + cell.height > grid_h_) { + return; + } + if (!visited.insert(gy * grid_w_ + gx).second) { + return; + } + const int dist = std::abs(gx - cell.init_x) * site_width_ + + std::abs(gy - cell.init_y) * row_height_; + pq.emplace(dist, gx, gy); + }; + + tryEnqueue(cell.init_x, cell.init_y); + constexpr std::array, 4> kNeighbors{ + {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}}; + while (!pq.empty()) { + auto [dist, gx, gy] = pq.top(); + pq.pop(); + if (isValidSite(gx, gy)) { + cell.init_x = gx; + cell.init_y = gy; + cell.x = cell.init_x; + cell.y = cell.init_y; + break; + } + for (auto [ox, oy] : kNeighbors) { + tryEnqueue(gx + ox, gy + oy); + } + } + } + } + + 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; + } + + 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. + cell.flippable = true; + } + + if (padding_ != nullptr) { + cell.pad_left = padding_->padLeft(db_inst).v; + cell.pad_right = padding_->padRight(db_inst).v; + } + + cells_.push_back(cell); + } + + 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() +{ + Grid* dplGrid = opendp_->grid_.get(); + + // Reset all pixels to default negotiation state. + 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; + } + } + + // Derive per-row existence: a row "has sites" if at least one site + // on that row has capacity > 0. + row_has_sites_.assign(grid_h_, false); + for (int gy = 0; gy < grid_h_; ++gy) { + for (int gx = 0; gx < grid_w_; ++gx) { + if (gridAt(gx, gy).capacity > 0) { + row_has_sites_[gy] = true; + break; + } + } + } + + // Mark blockages and record fixed-cell usage in one pass. + // The padded range of fixed cells is also blocked so movable cells + // cannot violate padding constraints relative to fixed instances. + for (const NegCell& cell : cells_) { + if (!cell.fixed) { + continue; + } + const int xBegin = effXBegin(cell); + const int xEnd = effXEnd(cell); + for (int dy = 0; dy < cell.height; ++dy) { + const int gy = cell.y + dy; + for (int gx = xBegin; gx < xEnd; ++gx) { + if (gridExists(gx, gy)) { + gridAt(gx, gy).capacity = 0; + // Physical footprint carries usage=1; padding slots do not. + if (gx >= cell.x && gx < cell.x + cell.width) { + gridAt(gx, gy).usage = 1; + } + } + } + } + } +} + +void NegotiationLegalizer::initFenceRegions() +{ + fences_.clear(); // Guard against double-population if legalize() is re-run. + + auto* block = db_->getChip()->getBlock(); + + for (auto* region : block->getRegions()) { + FenceRegion fr; + fr.id = region->getId(); + + for (auto* box : region->getBoundaries()) { + FenceRect 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_; + fr.rects.push_back(r); + } + + if (!fr.rects.empty()) { + fences_.push_back(std::move(fr)); + } + } + + // Map each instance to its fence region (if any). + for (auto& cell : cells_) { + if (cell.db_inst == nullptr) { + continue; + } + auto* region = cell.db_inst->getRegion(); + if (region == nullptr) { + continue; + } + const int rid = region->getId(); + for (int fi = 0; fi < static_cast(fences_.size()); ++fi) { + if (fences_[fi].id == rid) { + cell.fence_id = fi; + break; + } + } + } +} + +// =========================================================================== +// Grid helpers for Negotiation Legalizer +// =========================================================================== + +void NegotiationLegalizer::addUsage(int cell_idx, int delta) +{ + const NegCell& cell = cells_[cell_idx]; + const int xBegin = effXBegin(cell); + const int xEnd = effXEnd(cell); + for (int dy = 0; dy < cell.height; ++dy) { + const int gy = cell.y + dy; + for (int gx = xBegin; gx < xEnd; ++gx) { + if (gridExists(gx, gy)) { + gridAt(gx, gy).usage += delta; + } + } + } +} + +// =========================================================================== +// DPL Grid synchronisation +// =========================================================================== + +void NegotiationLegalizer::syncCellToDplGrid(int cell_idx) +{ + if (!opendp_ || !opendp_->grid_ || !network_) { + return; + } + const NegCell& neg_cell = cells_[cell_idx]; + if (neg_cell.db_inst == nullptr) { + return; + } + Node* node = network_->getNode(neg_cell.db_inst); + if (node == nullptr) { + return; + } + // Update the Node's position to match the NegCell so Grid operations + // (which read Node left/bottom) see the current placement. + node->setLeft(DbuX(neg_cell.x * site_width_)); + node->setBottom(DbuY(opendp_->grid_->gridYToDbu(GridY{neg_cell.y}).v)); + + // Update orientation to match the row. + odb::dbSite* site = neg_cell.db_inst->getMaster()->getSite(); + if (site != nullptr) { + auto orient = opendp_->grid_->getSiteOrientation( + GridX{neg_cell.x}, GridY{neg_cell.y}, site); + if (orient.has_value()) { + node->setOrient(orient.value()); + } + } + + opendp_->grid_->paintPixel(node, GridX{neg_cell.x}, GridY{neg_cell.y}); +} + +void NegotiationLegalizer::eraseCellFromDplGrid(int cell_idx) +{ + if (!opendp_ || !opendp_->grid_ || !network_) { + return; + } + const NegCell& neg_cell = cells_[cell_idx]; + if (neg_cell.db_inst == nullptr) { + return; + } + Node* node = network_->getNode(neg_cell.db_inst); + if (node == nullptr) { + return; + } + // Ensure the Node's position matches the current NegCell position so + // erasePixel clears the correct pixels (it reads gridCoveringPadded). + node->setLeft(DbuX(neg_cell.x * site_width_)); + node->setBottom(DbuY(opendp_->grid_->gridYToDbu(GridY{neg_cell.y}).v)); + opendp_->grid_->erasePixel(node); +} + +void NegotiationLegalizer::syncAllCellsToDplGrid() +{ + if (!opendp_ || !opendp_->grid_ || !network_) { + return; + } + // Clear all movable cells from the DPL Grid first, then repaint at + // their current positions. Fixed cells were already painted during + // Opendp::setFixedGridCells() and should not be touched. + for (const NegCell& neg_cell : cells_) { + if (neg_cell.fixed || neg_cell.db_inst == nullptr) { + continue; + } + Node* node = network_->getNode(neg_cell.db_inst); + if (node == nullptr) { + continue; + } + // Update Node position then erase whatever was previously painted. + node->setLeft(DbuX(neg_cell.x * site_width_)); + node->setBottom(DbuY(opendp_->grid_->gridYToDbu(GridY{neg_cell.y}).v)); + opendp_->grid_->erasePixel(node); + } + for (const NegCell& neg_cell : cells_) { + if (neg_cell.fixed || neg_cell.db_inst == nullptr) { + continue; + } + Node* node = network_->getNode(neg_cell.db_inst); + if (node == nullptr) { + continue; + } + // Set orientation to match the row, same as syncCellToDplGrid. + odb::dbSite* site = neg_cell.db_inst->getMaster()->getSite(); + if (site != nullptr) { + auto orient = opendp_->grid_->getSiteOrientation( + GridX{neg_cell.x}, GridY{neg_cell.y}, site); + if (orient.has_value()) { + node->setOrient(orient.value()); + } + } + opendp_->grid_->paintPixel(node, GridX{neg_cell.x}, GridY{neg_cell.y}); + } + // Re-paint fixed cells last so they always win over any movable cell that + // may have been placed at an overlapping initial position. Without this, + // a movable cell painted on top of an endcap overwrites pixel->cell, and + // the subsequent erasePixel call clears the endcap from the grid, making + // checkOneSiteGap blind to it. + for (const NegCell& cell : cells_) { + if (!cell.fixed || cell.db_inst == nullptr) { + continue; + } + Node* node = network_->getNode(cell.db_inst); + if (node == nullptr) { + continue; + } + opendp_->grid_->paintPixel(node); + } +} + +// =========================================================================== +// Constraint helpers +// =========================================================================== + +bool NegotiationLegalizer::inDie(int x, int y, int w, int h) const +{ + return x >= 0 && y >= 0 && x + w <= grid_w_ && y + h <= grid_h_; +} + +bool NegotiationLegalizer::isValidRow(int rowIdx, + const NegCell& cell, + int gridX) const +{ + 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; + } + } + // Verify that the cell's site type is available on the target row. + if (cell.db_inst != nullptr && opendp_ && opendp_->grid_) { + odb::dbSite* site = cell.db_inst->getMaster()->getSite(); + if (site != nullptr + && !opendp_->grid_->getSiteOrientation( + GridX{gridX}, GridY{rowIdx}, site)) { + 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; +} + +bool NegotiationLegalizer::respectsFence(int cell_idx, int x, int y) const +{ + const NegCell& cell = cells_[cell_idx]; + if (cell.fence_id < 0) { + // Default region: must not overlap any named fence. + for (const auto& fence : fences_) { + if (fence.contains(x, y, cell.width, cell.height)) { + return false; + } + } + return true; + } + return fences_[cell.fence_id].contains(x, y, cell.width, cell.height); +} + +std::pair NegotiationLegalizer::snapToLegal(int cell_idx, + int x, + int y) const +{ + const NegCell& cell = cells_[cell_idx]; + int best_x = std::max(0, std::min(x, grid_w_ - cell.width)); + int best_y = y; + double best_dist_sq = 1e18; + + for (int r = 0; r + cell.height <= grid_h_; ++r) { + if (!isValidRow(r, cell, x)) { + continue; + } + + // Find nearest valid X region in this row. + int local_best_x = -1; + int local_best_dx = 1e9; + + for (int tx = 0; tx + cell.width <= grid_w_; ++tx) { + bool ok = true; + for (int dy = 0; dy < cell.height; ++dy) { + for (int dx = 0; dx < cell.width; ++dx) { + if (gridAt(tx + dx, r + dy).capacity == 0) { + ok = false; + break; + } + } + if (!ok) { + break; + } + } + + if (ok) { + const int dx = std::abs(tx - x); + if (dx < local_best_dx) { + local_best_dx = dx; + local_best_x = tx; + } + } + } + + if (local_best_x != -1) { + const double dy = static_cast(r - y); + const double dx = static_cast(local_best_dx); + const double distSq = dx * dx + dy * dy; + if (distSq < best_dist_sq) { + best_dist_sq = distSq; + best_x = local_best_x; + best_y = r; + } + } + } + + return {best_x, best_y}; +} + +// =========================================================================== +// Abacus pass +// =========================================================================== + +std::vector NegotiationLegalizer::runAbacus() +{ + // Build sorted order: ascending y then x. + std::vector order; + order.reserve(cells_.size()); + for (int i = 0; i < static_cast(cells_.size()); ++i) { + if (!cells_[i].fixed) { + order.push_back(i); + } + } + std::ranges::sort(order, [this](int a, int b) { + if (cells_[a].y != cells_[b].y) { + return cells_[a].y < cells_[b].y; + } + return cells_[a].x < cells_[b].x; + }); + + // Remove movable cell usage before replanting. + for (int i : order) { + addUsage(i, -1); + } + + // Snap each cell to a legal row and group by that row. + std::vector> byRow(grid_h_); + for (int i : order) { + auto [sx, sy] = snapToLegal(i, cells_[i].x, cells_[i].y); + cells_[i].x = sx; + cells_[i].y = sy; + if (sy >= 0 && sy < grid_h_) { + byRow[sy].push_back(i); + } + } + + // Run the Abacus sweep row by row. + for (int r = 0; r < grid_h_; ++r) { + if (byRow[r].empty()) { + continue; + } + std::ranges::sort( + byRow[r], [this](int a, int b) { return cells_[a].x < cells_[b].x; }); + abacusRow(r, byRow[r]); + } + + // Restore movable cell usage after placement. + for (int i : order) { + addUsage(i, 1); + } + + // Sync to DPL Grid before DRC checks. + syncAllCellsToDplGrid(); + + // Collect still-illegal cells. + std::vector illegal; + for (int i : order) { + cells_[i].legal = isCellLegal(i); + if (!cells_[i].legal) { + illegal.push_back(i); + } + } + return illegal; +} + +void NegotiationLegalizer::abacusRow(int rowIdx, std::vector& cellsInRow) +{ + std::vector clusters; + + for (int idx : cellsInRow) { + const NegCell& cell = cells_[idx]; + + // Skip cells that violate fence or row constraints – negotiation handles + // them later. + if (!respectsFence(idx, cell.x, rowIdx) + || !isValidRow(rowIdx, cell, cell.x)) { + continue; + } + + AbacusCluster nc; + nc.cell_indices.push_back(idx); + const int eff_width = cell.width + cell.pad_left + cell.pad_right; + // Target the padded-left position so that cell.init_x lands correctly. + nc.optimal_x = static_cast(cell.init_x - cell.pad_left); + nc.total_weight = 1.0; + nc.total_q = nc.optimal_x; + nc.total_width = eff_width; + + // Clamp to die boundary (padded width). + nc.optimal_x = std::max( + 0.0, std::min(nc.optimal_x, static_cast(grid_w_ - eff_width))); + clusters.push_back(std::move(nc)); + collapseClusters(clusters, rowIdx); + } + + // Write solved positions back to cells_. + for (const auto& cluster : clusters) { + assignClusterPositions(cluster, rowIdx); + } +} + +void NegotiationLegalizer::collapseClusters( + std::vector& clusters, + int /*rowIdx*/) +{ + while (clusters.size() >= 2) { + AbacusCluster& last = clusters[clusters.size() - 1]; + AbacusCluster& prev = clusters[clusters.size() - 2]; + + // Solve optimal position for the last cluster. + last.optimal_x = last.total_q / last.total_weight; + last.optimal_x + = std::max(0.0, + std::min(last.optimal_x, + static_cast(grid_w_ - last.total_width))); + + // If the last cluster overlaps the previous one, merge them. + if (prev.optimal_x + prev.total_width > last.optimal_x) { + prev.total_weight += last.total_weight; + prev.total_q += last.total_q; + prev.total_width += last.total_width; + for (int idx : last.cell_indices) { + prev.cell_indices.push_back(idx); + } + prev.optimal_x = prev.total_q / prev.total_weight; + prev.optimal_x + = std::max(0.0, + std::min(prev.optimal_x, + static_cast(grid_w_ - prev.total_width))); + clusters.pop_back(); + } else { + break; + } + } + + // Re-solve the top cluster after any merge. + if (!clusters.empty()) { + AbacusCluster& top = clusters.back(); + top.optimal_x = top.total_q / top.total_weight; + top.optimal_x + = std::max(0.0, + std::min(top.optimal_x, + static_cast(grid_w_ - top.total_width))); + } +} + +void NegotiationLegalizer::assignClusterPositions(const AbacusCluster& cluster, + int rowIdx) +{ + // cluster.optimal_x is the padded-left edge of the cluster. + int paddedX = static_cast(std::round(cluster.optimal_x)); + paddedX = std::max(0, std::min(paddedX, grid_w_ - cluster.total_width)); + + for (int idx : cluster.cell_indices) { + const int eff_width + = cells_[idx].width + cells_[idx].pad_left + cells_[idx].pad_right; + // Physical left edge = padded-left edge + pad_left of this cell. + cells_[idx].x = paddedX + cells_[idx].pad_left; + cells_[idx].y = rowIdx; + paddedX += eff_width; + if (debug_observer_ && cells_[idx].db_inst != nullptr) { + debug_observer_->drawSelected(cells_[idx].db_inst, false); + if (opendp_->iterative_debug_) { + pushNegotiationPixels(); + debug_observer_->redrawAndPause(); + } + } + } +} + +bool NegotiationLegalizer::isCellLegal(int cell_idx) const +{ + const NegCell& cell = cells_[cell_idx]; + if (!inDie(cell.x, cell.y, cell.width, cell.height)) { + return false; + } + if (!isValidRow(cell.y, cell, cell.x)) { + return false; + } + if (!respectsFence(cell_idx, cell.x, cell.y)) { + return false; + } + + // Check placement DRCs (edge spacing, blocked layers, padding, + // one-site gaps) against neighbours on the DPL Grid. + if (opendp_ && opendp_->drc_engine_ && network_) { + Node* node = network_->getNode(cell.db_inst); + if (node != nullptr + && !opendp_->drc_engine_->checkDRC( + node, GridX{cell.x}, GridY{cell.y}, node->getOrient())) { + return false; + } + } else { + logger_->report("DRC objects not available!"); + return false; + } + + const int xBegin = effXBegin(cell); + const int xEnd = effXEnd(cell); + for (int dy = 0; dy < cell.height; ++dy) { + for (int gx = xBegin; gx < xEnd; ++gx) { + if (gridAt(gx, cell.y + dy).capacity == 0 + || gridAt(gx, cell.y + dy).overuse() > 0) { + return false; + } + } + } + return true; +} + +// =========================================================================== +// Metrics +// =========================================================================== + +double NegotiationLegalizer::avgDisplacement() const +{ + double sum = 0.0; + int count = 0; + for (const auto& cell : cells_) { + if (!cell.fixed) { + sum += cell.displacement(); + ++count; + } + } + return count > 0 ? sum / count : 0.0; +} + +int NegotiationLegalizer::maxDisplacement() const +{ + int mx = 0; + for (const auto& cell : cells_) { + if (!cell.fixed) { + mx = std::max(mx, cell.displacement()); + } + } + return mx; +} + +int NegotiationLegalizer::numViolations() const +{ + int count = 0; + for (int i = 0; i < static_cast(cells_.size()); ++i) { + if (!cells_[i].fixed && !isCellLegal(i)) { + ++count; + } + } + return count; +} + +} // namespace dpl diff --git a/src/dpl/src/NegotiationLegalizer.h b/src/dpl/src/NegotiationLegalizer.h new file mode 100644 index 00000000000..c155d990088 --- /dev/null +++ b/src/dpl/src/NegotiationLegalizer.h @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2018-2026, The OpenROAD Authors + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "infrastructure/Grid.h" +#include "odb/db.h" +#include "utl/Logger.h" + +namespace dpl { + +class DplObserver; +class Opendp; +class Padding; +class Node; +class Network; +class Group; +class Master; +class Edge; + +// --------------------------------------------------------------------------- +// Constants (defaults match the NBLG paper) +// --------------------------------------------------------------------------- +constexpr int kInfCost = std::numeric_limits::max() / 2; +constexpr int kHorizWindow = 20; // search width, current row (sites) +constexpr int kAdjWindow = 5; // search width, adjacent rows +constexpr int kMaxIterNeg = 400; // negotiation phase-1 limit +constexpr int kMaxIterNeg2 = 1000; // negotiation phase-2 limit +constexpr int kIsolationPt = 1; // isolation-point parameter I +constexpr double kMfDefault = 1.5; // max-disp penalty multiplier +constexpr int kThDefault = 30; // max-disp threshold (sites) +constexpr double kHfDefault = 1.0; // history-cost increment factor +constexpr double kAlpha = 0.7; // adaptive-pf α +constexpr double kBeta = 10.0; // adaptive-pf β +constexpr double kGamma = 0.005; // adaptive-pf γ +constexpr int kIth = 300; // pf ramp-up threshold iteration + +// --------------------------------------------------------------------------- +// NLPowerRailType +// --------------------------------------------------------------------------- +enum class NLPowerRailType +{ + kVss = 0, + kVdd = 1 +}; + +// --------------------------------------------------------------------------- +// FenceRect / FenceRegion +// --------------------------------------------------------------------------- +struct FenceRect +{ + int xlo{0}; + int ylo{0}; + int xhi{0}; + int yhi{0}; +}; + +struct FenceRegion +{ + int id{-1}; + std::vector rects; + + // True when footprint [x, x+w) × [y, y+h) lies inside at least one rect. + [[nodiscard]] bool contains(int x, int y, int w, int h) const; + + // Sub-rectangle whose centre is nearest (cx, cy). + [[nodiscard]] FenceRect nearestRect(int cx, int cy) const; +}; + +// --------------------------------------------------------------------------- +// NegCell – per-instance legalisation state +// --------------------------------------------------------------------------- +struct NegCell +{ + odb::dbInst* db_inst{nullptr}; + + int init_x{0}; // position after global placement (sites) + int init_y{0}; // position after global placement (rows) + int x{0}; // current legalised position (sites) + int y{0}; // current legalised position (rows) + int width{0}; // footprint width (sites) + int height{0}; // footprint height (row units: 1–4) + int pad_left{0}; // left padding (sites) + int pad_right{0}; // right padding (sites) + + bool fixed{false}; + NLPowerRailType rail_type{NLPowerRailType::kVss}; + 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 + + [[nodiscard]] int displacement() const + { + return std::abs(x - init_x) + std::abs(y - init_y); + } +}; + +// --------------------------------------------------------------------------- +// AbacusCluster – transient state during the Abacus row sweep +// --------------------------------------------------------------------------- +struct AbacusCluster +{ + std::vector cell_indices; // ordered left-to-right within the row + double optimal_x{0.0}; // solved optimal left-edge (fractional) + double total_weight{0.0}; + double total_q{0.0}; // Σ w_i * x_i^0 + int total_width{0}; // Σ cell widths (sites) +}; + +// --------------------------------------------------------------------------- +// NegotiationLegalizer +// --------------------------------------------------------------------------- +class NegotiationLegalizer +{ + public: + NegotiationLegalizer(Opendp* opendp, + odb::dbDatabase* db, + utl::Logger* logger, + const Padding* padding = nullptr, + DplObserver* debug_observer = nullptr, + Network* network = nullptr); + ~NegotiationLegalizer() = default; + + NegotiationLegalizer(const NegotiationLegalizer&) = delete; + NegotiationLegalizer& operator=(const NegotiationLegalizer&) = delete; + NegotiationLegalizer(NegotiationLegalizer&&) = delete; + NegotiationLegalizer& operator=(NegotiationLegalizer&&) = delete; + + // Main entry point – call instead of (or after) the existing opendp path. + // May be called multiple times on the same object; internal state is reset + // at the start of each call (cells_, grid_, fences_, row_rail_ are cleared). + void legalize(); + + // Pass positions back to the DPL original structure. + void setDplPositions(); + + // Tuning knobs (all have paper-default values) + void setRunAbacus(bool run) { run_abacus_ = run; } + void setMf(double mf) { max_disp_multiplier_ = mf; } + void setTh(int th) { max_disp_threshold_ = th; } + void setMaxIterNeg(int n) { max_iter_neg_ = n; } + void setHorizWindow(int w) { horiz_window_ = w; } + void setAdjWindow(int w) { adj_window_ = w; } + void setNumThreads(int n) { num_threads_ = n; } + + // Metrics (valid after legalize()) + [[nodiscard]] double avgDisplacement() const; + [[nodiscard]] int maxDisplacement() const; + [[nodiscard]] int numViolations() const; + + private: + // Initialisation + 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); + + // Abacus pass + [[nodiscard]] std::vector runAbacus(); + void abacusRow(int rowIdx, std::vector& cellsInRow); + void collapseClusters(std::vector& clusters, int rowIdx); + void assignClusterPositions(const AbacusCluster& cluster, int rowIdx); + [[nodiscard]] bool isCellLegal(int cell_idx) const; + + // Negotiation pass + void runNegotiation(const std::vector& illegalCells); + int negotiationIter(std::vector& activeCells, + int iter, + bool updateHistory); + void ripUp(int cell_idx); + void place(int cell_idx, int x, int y); + [[nodiscard]] std::pair findBestLocation(int cell_idx, + int iter = 0) const; + [[nodiscard]] double negotiationCost(int cell_idx, int x, int y) const; + [[nodiscard]] double targetCost(int cell_idx, int x, int y) const; + [[nodiscard]] double adaptivePf(int iter) const; + void updateHistoryCosts(); + void updateDrcHistoryCosts(const std::vector& activeCells); + void sortByNegotiationOrder(std::vector& indices) const; + + // Post-optimisation + void greedyImprove(int passes); + void cellSwap(); + void diamondRecovery(const std::vector& activeCells); + + // Constraint helpers + [[nodiscard]] bool isValidRow(int rowIdx, + const NegCell& cell, + int gridX) 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]] std::pair snapToLegal(int cell_idx, + int x, + int y) const; + + // DPL Grid synchronisation helpers – keep the Opendp pixel grid in sync + // with NegotiationLegalizer cell positions so that PlacementDRC neighbour + // lookups (edge spacing, padding, one-site gaps) see correct data. + void syncCellToDplGrid(int cell_idx); + void eraseCellFromDplGrid(int cell_idx); + void syncAllCellsToDplGrid(); + + // Pixel helpers – use the main DPL grid. + Pixel& gridAt(int x, int y) + { + return opendp_->grid_->pixel(GridY{y}, GridX{x}); + } + [[nodiscard]] const Pixel& gridAt(int x, int y) const + { + return opendp_->grid_->pixel(GridY{y}, GridX{x}); + } + [[nodiscard]] bool gridExists(int x, int y) const + { + return x >= 0 && x < grid_w_ && y >= 0 && y < grid_h_; + } + void addUsage(int cell_idx, int delta); + + // Effective padded footprint helpers (inclusive of padding zones). + [[nodiscard]] int effXBegin(const NegCell& cell) const + { + return std::max(0, cell.x - cell.pad_left); + } + [[nodiscard]] int effXEnd(const NegCell& cell) const + { + return std::min(grid_w_, cell.x + cell.width + cell.pad_right); + } + + // Data + Opendp* opendp_{nullptr}; + odb::dbDatabase* db_{nullptr}; + utl::Logger* logger_{nullptr}; + const Padding* padding_{nullptr}; + DplObserver* debug_observer_{nullptr}; + Network* network_{nullptr}; + + int site_width_{0}; + int row_height_{0}; + int die_xlo_{0}; + int die_ylo_{0}; + int die_xhi_{0}; + int die_yhi_{0}; + int grid_w_{0}; + int grid_h_{0}; + + std::vector cells_; + std::vector fences_; + std::vector row_rail_; + std::vector + row_has_sites_; // true when at least one DB row exists at y + + double max_disp_multiplier_{kMfDefault}; // mf on the paper + int max_disp_threshold_{kThDefault}; // th on the paper + int max_iter_neg_{kMaxIterNeg}; + int horiz_window_{kHorizWindow}; + int adj_window_{kAdjWindow}; + int num_threads_{1}; + bool run_abacus_{false}; + + // Mutable profiling accumulators for findBestLocation breakdown (seconds). + mutable double prof_init_search_s_{0}; + mutable double prof_curr_search_s_{0}; + mutable double prof_filter_s_{0}; + mutable double prof_neg_cost_s_{0}; + mutable double prof_drc_s_{0}; + mutable int prof_candidates_evaluated_{0}; + mutable int prof_candidates_filtered_{0}; +}; + +} // namespace dpl diff --git a/src/dpl/src/NegotiationLegalizerPass.cpp b/src/dpl/src/NegotiationLegalizerPass.cpp new file mode 100644 index 00000000000..2a9c052bfeb --- /dev/null +++ b/src/dpl/src/NegotiationLegalizerPass.cpp @@ -0,0 +1,909 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2018-2026, The OpenROAD Authors + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "NegotiationLegalizer.h" +#include "PlacementDRC.h" +#include "dpl/Opendp.h" +#include "graphics/DplObserver.h" +#include "infrastructure/Coordinates.h" +#include "infrastructure/Grid.h" +#include "infrastructure/Objects.h" +#include "infrastructure/network.h" +#include "odb/db.h" +#include "odb/geom.h" +#include "utl/Logger.h" +#include "utl/timer.h" + +namespace dpl { + +// =========================================================================== +// runNegotiation – top-level negotiation driver +// =========================================================================== + +void NegotiationLegalizer::runNegotiation(const std::vector& illegalCells) +{ + // Seed with illegal cells and all movable neighbors within the search + // window so the loop can create space organically. + std::unordered_set active_set(illegalCells.begin(), illegalCells.end()); + + for (int idx : illegalCells) { + const NegCell& seed = cells_[idx]; + const int xlo = seed.x - horiz_window_; + const int xhi = seed.x + seed.width + horiz_window_; + const int ylo = seed.y - adj_window_; + const int yhi = seed.y + seed.height + adj_window_; + + for (int i = 0; i < static_cast(cells_.size()); ++i) { + if (cells_[i].fixed) { + continue; + } + const NegCell& nb = cells_[i]; + if (nb.x >= xlo && nb.x <= xhi && nb.y >= ylo && nb.y <= yhi) { + active_set.insert(i); + } + } + } + + std::vector active(active_set.begin(), active_set.end()); + + // Phase 1 – all active cells rip-up every iteration (isolation point = 0). + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "Negotiation phase 1: {} active cells, {} iterations.", + active.size(), + max_iter_neg_); + + int prev_overflows = -1; + int stall_count = 0; + for (int iter = 0; iter < max_iter_neg_; ++iter) { + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "Starting phase 1 negotiation iteration {} ({} active cells)", + iter, + active.size()); + const int phase_1_overflows + = negotiationIter(active, iter, /*updateHistory=*/true); + if (phase_1_overflows == 0) { + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "Negotiation phase 1 converged at iteration {}.", + iter); + logger_->metric("negotiation__converge__phase_1__iteration", iter); + debugPause("Pause after convergence at phase 1."); + return; + } + if (phase_1_overflows == prev_overflows) { + ++stall_count; + if (stall_count == 3) { + logger_->warn( + utl::DPL, + 700, + "Negotiation phase 1: overflow stuck at {} for 3 consecutive " + "iterations.\nUsing old diamond search for remaining cells.", + phase_1_overflows); + diamondRecovery(active); + break; + } + } else { + stall_count = 0; + } + prev_overflows = phase_1_overflows; + } + + debugPause("Pause before negotiation phase 2."); + + // Phase 2 – isolation point active: skip already-legal cells. + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "Negotiation phase 2: isolation point active, {} iterations.", + kMaxIterNeg2); + + prev_overflows = -1; + stall_count = 0; + for (int iter = 0; iter < kMaxIterNeg2; ++iter) { + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "Starting phase 2 negotiation iteration {} (+{} phase 1 " + "iterations) ({} active cells)", + iter, + max_iter_neg_, + active.size()); + const int phase_2_overflows + = negotiationIter(active, iter + max_iter_neg_, /*updateHistory=*/true); + if (phase_2_overflows == 0) { + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "Negotiation phase 2 converged at iteration {}.", + iter); + logger_->metric("negotiation__converge__phase_2__iteration", iter); + debugPause("Pause after convergence at phase 2."); + return; + } + if (phase_2_overflows == prev_overflows) { + ++stall_count; + if (stall_count == 3) { + logger_->warn(utl::DPL, + 702, + "Negotiation phase 2: overflow stuck at {} for 3 " + "consecutive iterations.", + phase_2_overflows); + diamondRecovery(active); + break; + } + } else { + stall_count = 0; + } + prev_overflows = phase_2_overflows; + } + + // Non-convergence is reported by the caller (Opendp::detailedPlacement) + // via numViolations(), which avoids registering a message ID in this file. + debugPrint(logger_, + utl::DPL, + "negotiation", + 1, + "Negotiation did not fully converge. Remaining violations: {}.", + numViolations()); + debugPause("Pause after non-convergence at negotiation phases 1 and 2."); +} + +// =========================================================================== +// negotiationIter – one full rip-up/replace sweep over activeCells +// =========================================================================== + +int NegotiationLegalizer::negotiationIter(std::vector& activeCells, + int iter, + bool updateHistory) +{ + if (debug_observer_) { + debug_observer_->clearNegotiationSearchWindows(); + } + + // Reset findBestLocation profiling accumulators. + prof_init_search_s_ = 0; + prof_curr_search_s_ = 0; + prof_filter_s_ = 0; + prof_neg_cost_s_ = 0; + prof_drc_s_ = 0; + prof_candidates_evaluated_ = 0; + prof_candidates_filtered_ = 0; + + double sort_s{0}, rip_up_s{0}, find_best_s{0}, place_s{0}; + double sync_s{0}, overflow_s{0}, bystander_s{0}, history_s{0}; + const utl::Timer total_iter_timer; + + int moves_count = 0; + { + utl::DebugScopedTimer t(sort_s); + sortByNegotiationOrder(activeCells); + } + + for (int idx : activeCells) { + if (cells_[idx].fixed) { + continue; + } + // Isolation point: skip legal cells during phase 2. + if (iter >= kIsolationPt && isCellLegal(idx)) { + continue; + } + int bx, by; + { + utl::DebugScopedTimer t(rip_up_s); + ripUp(idx); + } + { + utl::DebugScopedTimer t(find_best_s); + std::tie(bx, by) = findBestLocation(idx, iter); + } + { + utl::DebugScopedTimer t(place_s); + place(idx, bx, by); + } + moves_count++; + debugPrint(logger_, + utl::DPL, + "negotiation", + 2, + "Negotiation iter {}, cell {}, moves {}, best location {}, {}", + iter, + cells_[idx].db_inst->getName(), + moves_count, + bx, + by); + } + + // Re-sync the DPL pixel grid before checking violations. During the + // rip-up/place loop above, overlapping cells can lose their pixel->cell + // entry when a co-located cell is ripped up, leaving bystander cells + // invisible to DRC checks. A full re-sync restores every cell so the + // violation scan below is accurate. + { + utl::DebugScopedTimer t(sync_s); + syncAllCellsToDplGrid(); + } + + // Count remaining overflows (grid overuse) AND DRC violations. + // Both must reach zero for the negotiation to converge. + // Also detect any non-active cells that have become DRC-illegal + // (e.g. a move created a one-site gap with a neighbor outside the + // active set) and pull them in so the negotiation can fix them. + int totalOverflow = 0; + std::unordered_set active_set(activeCells.begin(), activeCells.end()); + { + utl::DebugScopedTimer t(overflow_s); + for (int idx : activeCells) { + if (cells_[idx].fixed) { + continue; + } + const NegCell& cell = cells_[idx]; + const int xBegin = effXBegin(cell); + const int xEnd = effXEnd(cell); + for (int dy = 0; dy < cell.height; ++dy) { + for (int gx = xBegin; gx < xEnd; ++gx) { + if (gridExists(gx, cell.y + dy)) { + totalOverflow += gridAt(gx, cell.y + dy).overuse(); + } + } + } + if (!isCellLegal(idx)) { + ++totalOverflow; + } + } + } + + // Scan all movable cells for newly-created DRC violations outside the + // current active set. This handles cases where a move in the active + // set created a one-site gap (or other DRC issue) with a bystander. + { + utl::DebugScopedTimer t(bystander_s); + for (int i = 0; i < static_cast(cells_.size()); ++i) { + if (cells_[i].fixed || active_set.contains(i)) { + continue; + } + if (!isCellLegal(i)) { + activeCells.push_back(i); + active_set.insert(i); + ++totalOverflow; + } + } + } + + if (totalOverflow > 0 && updateHistory) { + utl::DebugScopedTimer t(history_s); + updateHistoryCosts(); + updateDrcHistoryCosts(activeCells); + sortByNegotiationOrder(activeCells); + } + + if (logger_->debugCheck(utl::DPL, "negotiation_runtime", 1)) { + const double total_ms = total_iter_timer.elapsed() * 1e3; + auto pct = [total_ms](double ms_val) { + return total_ms > 0 ? 100.0 * ms_val / total_ms : 0.0; + }; + auto to_ms = [](double s) { return s * 1e3; }; + const double rip_up_ms = to_ms(rip_up_s); + const double find_best_ms = to_ms(find_best_s); + const double place_ms = to_ms(place_s); + const double sort_ms = to_ms(sort_s); + const double sync_ms = to_ms(sync_s); + const double overflow_ms = to_ms(overflow_s); + const double bystander_ms = to_ms(bystander_s); + const double history_ms = to_ms(history_s); + const double initSearchMs = prof_init_search_s_ * 1e3; + const double currSearchMs = prof_curr_search_s_ * 1e3; + const double filterMs = prof_filter_s_ * 1e3; + const double negCostMs = prof_neg_cost_s_ * 1e3; + const double drcMs = prof_drc_s_ * 1e3; + const double overhead = find_best_ms - filterMs - negCostMs - drcMs; + logger_->report( + " negotiationIter {} ({:.1f}ms, {} moves): " + "sort {:.1f}ms ({:.0f}%), " + "ripUp {:.1f}ms ({:.0f}%), findBest {:.1f}ms ({:.0f}%), place {:.1f}ms " + "({:.0f}%), " + "syncGrid {:.1f}ms ({:.0f}%), overflowCount {:.1f}ms ({:.0f}%), " + "bystanderScan {:.1f}ms ({:.0f}%), historyUpdate {:.1f}ms ({:.0f}%)", + iter, + total_ms, + moves_count, + sort_ms, + pct(sort_ms), + rip_up_ms, + pct(rip_up_ms), + find_best_ms, + pct(find_best_ms), + place_ms, + pct(place_ms), + sync_ms, + pct(sync_ms), + overflow_ms, + pct(overflow_ms), + bystander_ms, + pct(bystander_ms), + history_ms, + pct(history_ms)); + logger_->report( + " findBest by region ({} candidates, {} filtered): " + "initSearch {:.1f}ms ({:.0f}%), currSearch {:.1f}ms ({:.0f}%)", + prof_candidates_evaluated_, + prof_candidates_filtered_, + initSearchMs, + pct(initSearchMs), + currSearchMs, + pct(currSearchMs)); + logger_->report( + " findBest by function: " + "filter {:.1f}ms ({:.0f}%), negCost {:.1f}ms ({:.0f}%), " + "drc {:.1f}ms ({:.0f}%), overhead {:.1f}ms ({:.0f}%)", + filterMs, + pct(filterMs), + negCostMs, + pct(negCostMs), + drcMs, + pct(drcMs), + overhead, + pct(overhead)); + } + + logger_->report( + "Negotiation iteration {}: total overflow {}.", iter, totalOverflow); + if (opendp_->iterative_debug_ && debug_observer_) { + setDplPositions(); + pushNegotiationPixels(); + logger_->report("Pause after negotiation iteration {}.", iter); + debug_observer_->redrawAndPause(); + } + return totalOverflow; +} + +// =========================================================================== +// ripUp / place +// =========================================================================== + +void NegotiationLegalizer::ripUp(int cell_idx) +{ + eraseCellFromDplGrid(cell_idx); + addUsage(cell_idx, -1); +} + +void NegotiationLegalizer::place(int cell_idx, int x, int y) +{ + cells_[cell_idx].x = x; + cells_[cell_idx].y = y; + addUsage(cell_idx, 1); + syncCellToDplGrid(cell_idx); + if (opendp_->deep_iterative_debug_ && debug_observer_) { + 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); + } + } +} + +// =========================================================================== +// findBestLocation – enumerate candidates within the search window +// =========================================================================== + +std::pair NegotiationLegalizer::findBestLocation(int cell_idx, + int iter) const +{ + const NegCell& cell = cells_[cell_idx]; + + auto best_cost = static_cast(kInfCost); + int best_x = cell.x; + int best_y = cell.y; + + // Look up the DPL Node once for DRC checks (may be null if no + // Opendp integration is available). + Node* node = (opendp_ && opendp_->drc_engine_ && network_) + ? network_->getNode(cell.db_inst) + : nullptr; + + // DRC penalty escalates with iteration count: early iterations are + // lenient (cells can tolerate DRC violations to resolve overlaps first), + // later iterations strongly penalise DRC violations to force resolution. + const double kDrcPenalty = 1e3 * (1.0 + iter); + + // Helper: evaluate one candidate position. + auto tryLocation = [&](int tx, int ty) { + { + utl::DebugScopedTimer t(prof_filter_s_); + if (!inDie(tx, ty, cell.width, cell.height) || !isValidRow(ty, cell, tx) + || !respectsFence(cell_idx, tx, ty)) { + ++prof_candidates_filtered_; + return; + } + } + + double cost; + { + utl::DebugScopedTimer t(prof_neg_cost_s_); + cost = negotiationCost(cell_idx, tx, ty); + } + + // Add a DRC penalty so clean positions are strongly preferred, + // but a DRC-violating position can still be chosen if nothing + // better is available (avoids infinite non-convergence). + if (node != nullptr) { + utl::DebugScopedTimer t(prof_drc_s_); + odb::dbOrientType targetOrient = node->getOrient(); + odb::dbSite* site = cell.db_inst->getMaster()->getSite(); + if (site != nullptr) { + auto orient + = opendp_->grid_->getSiteOrientation(GridX{tx}, GridY{ty}, site); + if (orient.has_value()) { + targetOrient = orient.value(); + } + } + const int drcCount = opendp_->drc_engine_->countDRCViolations( + node, GridX{tx}, GridY{ty}, targetOrient); + cost += kDrcPenalty * drcCount; + } + ++prof_candidates_evaluated_; + if (cost < best_cost) { + best_cost = cost; + best_x = tx; + best_y = ty; + } + }; + + // Search around the initial (GP) position. + { + utl::DebugScopedTimer t(prof_init_search_s_); + for (int dy = -adj_window_; dy <= adj_window_; ++dy) { + for (int dx = -horiz_window_; dx <= horiz_window_; ++dx) { + tryLocation(cell.init_x + dx, cell.init_y + dy); + } + } + } + + // Also search around the current position — critical when the cell has + // already been displaced far from init_x and needs to explore its local + // neighbourhood to resolve DRC violations (e.g. one-site gaps). + if (cell.x != cell.init_x || cell.y != cell.init_y) { + utl::DebugScopedTimer t(prof_curr_search_s_); + for (int dy = -adj_window_; dy <= adj_window_; ++dy) { + for (int dx = -horiz_window_; dx <= horiz_window_; ++dx) { + tryLocation(cell.x + dx, cell.y + dy); + } + } + } + + if (debug_observer_) { + const odb::Rect core = opendp_->grid_->getCore(); + const DbuX sw = opendp_->grid_->getSiteWidth(); + const auto toX = [&](int gx) { + return core.xMin() + gridToDbu(GridX{std::clamp(gx, 0, grid_w_)}, sw).v; + }; + const auto toY = [&](int gy) { + return core.yMin() + + opendp_->grid_->gridYToDbu(GridY{std::clamp(gy, 0, grid_h_)}).v; + }; + const odb::Rect init_win(toX(cell.init_x - horiz_window_), + toY(cell.init_y - adj_window_), + toX(cell.init_x + horiz_window_ + 1), + toY(cell.init_y + adj_window_ + 1)); + const bool displaced = (cell.x != cell.init_x || cell.y != cell.init_y); + const odb::Rect curr_win = displaced + ? odb::Rect(toX(cell.x - horiz_window_), + toY(cell.y - adj_window_), + toX(cell.x + horiz_window_ + 1), + toY(cell.y + adj_window_ + 1)) + : odb::Rect(); + debug_observer_->setNegotiationSearchWindow( + cell.db_inst, init_win, curr_win); + } + + if (opendp_->deep_iterative_debug_ && debug_observer_) { + const odb::dbInst* debug_inst = debug_observer_->getDebugInstance(); + if (cell.db_inst == debug_inst) { + const DbuX site_width = opendp_->grid_->getSiteWidth(); + logger_->report(" Best location for {} is ({}, {}) with cost {}.", + cell.db_inst->getName(), + gridToDbu(GridX{best_x}, site_width).v, + opendp_->grid_->gridYToDbu(GridY{best_y}).v, + best_cost == static_cast(kInfCost) + ? "inf" + : std::to_string(best_cost)); + if (node != nullptr) { + odb::dbOrientType targetOrient = node->getOrient(); + odb::dbSite* site = cell.db_inst->getMaster()->getSite(); + if (site != nullptr) { + auto orient = opendp_->grid_->getSiteOrientation( + GridX{best_x}, GridY{best_y}, site); + if (orient.has_value()) { + targetOrient = orient.value(); + } + } + const int drcCount = opendp_->drc_engine_->countDRCViolations( + node, GridX{best_x}, GridY{best_y}, targetOrient); + logger_->report(" DRC violations at best location: {}.", drcCount); + } + } + } + return {best_x, best_y}; +} + +// =========================================================================== +// negotiationCost – Eq. 10 from the NBLG paper +// Cost(x,y) = b(x,y) + Σ_grids h(g) * p(g) +// =========================================================================== + +double NegotiationLegalizer::negotiationCost(int cell_idx, int x, int y) const +{ + const NegCell& cell = cells_[cell_idx]; + double cost = targetCost(cell_idx, x, y); + + const int xBegin = std::max(0, x - cell.pad_left); + const int xEnd = std::min(grid_w_, x + cell.width + cell.pad_right); + for (int dy = 0; dy < cell.height; ++dy) { + for (int gx = xBegin; gx < xEnd; ++gx) { + const int gy = y + dy; + if (!gridExists(gx, gy)) { + cost += kInfCost; + continue; + } + const Pixel& g = gridAt(gx, gy); + if (g.capacity == 0) { + cost += kInfCost; // blockage + continue; + } + // Congestion term: h * p (Eq. 10). + // Usage is incremented by 1 to account for this cell being placed. + const auto usageWithCell = static_cast(g.usage + 1); + const auto cap = static_cast(g.capacity); + const double penalty = usageWithCell / cap; + cost += g.hist_cost * penalty; + } + } + return cost; +} + +// =========================================================================== +// targetCost – Eq. 11 from the NBLG paper +// b(x,y) = δ + mf * max(δ − th, 0) +// =========================================================================== + +double NegotiationLegalizer::targetCost(int cell_idx, int x, int y) const +{ + const NegCell& cell = cells_[cell_idx]; + const int disp = std::abs(x - cell.init_x) + std::abs(y - cell.init_y); + return static_cast(disp) + + max_disp_multiplier_ + * static_cast(std::max(0, disp - max_disp_threshold_)); +} + +// =========================================================================== +// adaptivePf – Eq. 14 from the NBLG paper +// pf = 1.0 + α * exp(−β * exp(−γ * (i − ith))) +// =========================================================================== + +double NegotiationLegalizer::adaptivePf(int iter) const +{ + return 1.0 + kAlpha * std::exp(-kBeta * std::exp(-kGamma * (iter - kIth))); +} + +// =========================================================================== +// updateHistoryCosts – Eq. 12 from the NBLG paper +// h_new = h_old + hf * overuse +// =========================================================================== + +void NegotiationLegalizer::updateHistoryCosts() +{ + for (int gy = 0; gy < grid_h_; ++gy) { + for (int gx = 0; gx < grid_w_; ++gx) { + Pixel& g = gridAt(gx, gy); + const int ov = g.overuse(); + if (ov > 0) { + g.hist_cost += kHfDefault * ov; + } + } + } +} + +// =========================================================================== +// updateDrcHistoryCosts – bump history on pixels occupied by cells that +// have DRC violations, so the negotiation loop builds pressure to move +// them away from DRC-problematic positions over iterations. +// =========================================================================== + +void NegotiationLegalizer::updateDrcHistoryCosts( + const std::vector& activeCells) +{ + if (!opendp_ || !opendp_->drc_engine_ || !network_) { + return; + } + for (int idx : activeCells) { + if (cells_[idx].fixed) { + continue; + } + const NegCell& cell = cells_[idx]; + Node* node = network_->getNode(cell.db_inst); + if (node == nullptr) { + continue; + } + odb::dbOrientType orient = node->getOrient(); + odb::dbSite* site = cell.db_inst->getMaster()->getSite(); + if (site != nullptr) { + auto o = opendp_->grid_->getSiteOrientation( + GridX{cell.x}, GridY{cell.y}, site); + if (o.has_value()) { + orient = o.value(); + } + } + const int drcCount = opendp_->drc_engine_->countDRCViolations( + node, GridX{cell.x}, GridY{cell.y}, orient); + if (drcCount > 0) { + const int xBegin = effXBegin(cell); + const int xEnd = effXEnd(cell); + for (int dy = 0; dy < cell.height; ++dy) { + for (int gx = xBegin; gx < xEnd; ++gx) { + if (gridExists(gx, cell.y + dy)) { + gridAt(gx, cell.y + dy).hist_cost += kHfDefault * drcCount; + } + } + } + } + } +} + +// =========================================================================== +// sortByNegotiationOrder +// Primary: total overuse descending (most congested processed first) +// Secondary: height ascending (smaller cells settle before larger) +// Tertiary: width ascending +// =========================================================================== + +void NegotiationLegalizer::sortByNegotiationOrder( + std::vector& indices) const +{ + auto cellOveruse = [this](int idx) { + const NegCell& cell = cells_[idx]; + int ov = 0; + const int xBegin = effXBegin(cell); + const int xEnd = effXEnd(cell); + for (int dy = 0; dy < cell.height; ++dy) { + for (int gx = xBegin; gx < xEnd; ++gx) { + if (gridExists(gx, cell.y + dy)) { + ov += gridAt(gx, cell.y + dy).overuse(); + } + } + } + return ov; + }; + + std::ranges::sort(indices, [&](int a, int b) { + const int oa = cellOveruse(a); + const int ob = cellOveruse(b); + if (oa != ob) { + return oa > ob; + } + if (cells_[a].height != cells_[b].height) { + return cells_[a].height < cells_[b].height; + } + return cells_[a].width < cells_[b].width; + }); +} + +// =========================================================================== +// greedyImprove – post-optimisation: reduce displacement without creating +// new overlaps. +// =========================================================================== + +void NegotiationLegalizer::greedyImprove(int passes) +{ + std::vector order; + order.reserve(cells_.size()); + for (int i = 0; i < static_cast(cells_.size()); ++i) { + if (!cells_[i].fixed) { + order.push_back(i); + } + } + + for (int pass = 0; pass < passes; ++pass) { + int improved = 0; + + for (int idx : order) { + NegCell& cell = cells_[idx]; + const int curDisp = cell.displacement(); + + ripUp(idx); + + int best_x = cell.x; + int best_y = cell.y; + int best_dist = curDisp; + + auto tryLoc = [&](int tx, int ty) { + if (!inDie(tx, ty, cell.width, cell.height)) { + return; + } + if (!isValidRow(ty, cell, tx)) { + return; + } + if (!respectsFence(idx, tx, ty)) { + return; + } + // Only accept if no new overlap or padding violation is introduced. + const int txBegin = std::max(0, tx - cell.pad_left); + const int txEnd = std::min(grid_w_, tx + cell.width + cell.pad_right); + for (int dy = 0; dy < cell.height; ++dy) { + for (int gx = txBegin; gx < txEnd; ++gx) { + if (gridAt(gx, ty + dy).overuse() > 0) { + return; + } + } + } + const int d = std::abs(tx - cell.init_x) + std::abs(ty - cell.init_y); + if (d < best_dist) { + best_dist = d; + best_x = tx; + best_y = ty; + } + }; + + for (int dx = -horiz_window_; dx <= horiz_window_; ++dx) { + tryLoc(cell.init_x + dx, cell.y); + tryLoc(cell.init_x + dx, cell.y - cell.height); + tryLoc(cell.init_x + dx, cell.y + cell.height); + } + + place(idx, best_x, best_y); + if (best_dist < curDisp) { + ++improved; + } + } + + if (improved == 0) { + break; + } + } +} + +// =========================================================================== +// cellSwap – swap pairs of same-type cells when total displacement decreases +// without exceeding the current maximum displacement. +// =========================================================================== + +void NegotiationLegalizer::cellSwap() +{ + const int maxDisp = maxDisplacement(); + + // Group movable cells by (height, width, rail_type). + struct GroupKey + { + int height; + int width; + NLPowerRailType rail; + bool operator==(const GroupKey& o) const + { + return height == o.height && width == o.width && rail == o.rail; + } + }; + struct GroupKeyHash + { + size_t operator()(const GroupKey& k) const + { + return std::hash()(k.height) ^ (std::hash()(k.width) << 8) + ^ (std::hash()(static_cast(k.rail)) << 16); + } + }; + + std::unordered_map, GroupKeyHash> groups; + for (int i = 0; i < static_cast(cells_.size()); ++i) { + if (!cells_[i].fixed) { + groups[{cells_[i].height, cells_[i].width, cells_[i].rail_type}] + .push_back(i); + } + } + + for (auto& [key, grp] : groups) { + for (int ii = 0; ii < static_cast(grp.size()); ++ii) { + for (int jj = ii + 1; jj < static_cast(grp.size()); ++jj) { + const int a = grp[ii]; + const int b = grp[jj]; + NegCell& ca = cells_[a]; + NegCell& cb = cells_[b]; + + const int dispBefore = ca.displacement() + cb.displacement(); + const int newDispA + = std::abs(cb.x - ca.init_x) + std::abs(cb.y - ca.init_y); + const int newDispB + = std::abs(ca.x - cb.init_x) + std::abs(ca.y - cb.init_y); + const int dispAfter = newDispA + newDispB; + + if (dispAfter >= dispBefore) { + continue; + } + if (newDispA > maxDisp || newDispB > maxDisp) { + continue; + } + if (!respectsFence(a, cb.x, cb.y) || !respectsFence(b, ca.x, ca.y)) { + continue; + } + if (!isValidRow(cb.y, ca, cb.x) || !isValidRow(ca.y, cb, ca.x)) { + continue; + } + + ripUp(a); + ripUp(b); + std::swap(ca.x, cb.x); + std::swap(ca.y, cb.y); + place(a, ca.x, ca.y); + place(b, cb.x, cb.y); + } + } + } +} + +// =========================================================================== +// diamondRecovery – break stalls by trying the Opendp BFS diamond search on +// each illegal cell. Unlike findBestLocation (bounded rectangular window), +// the diamond search expands outward in physical Manhattan order until it +// finds a pixel where canBePlaced() passes, so it can escape local congestion +// pockets that the rectangular window cannot resolve. +// =========================================================================== + +void NegotiationLegalizer::diamondRecovery(const std::vector& activeCells) +{ + if (!opendp_ || !network_) { + return; + } + int recovered = 0; + for (int idx : activeCells) { + if (cells_[idx].fixed || isCellLegal(idx)) { + continue; + } + const NegCell& cell = cells_[idx]; + Node* node = network_->getNode(cell.db_inst); + if (node == nullptr) { + continue; + } + // diamondSearch uses canBePlaced which reads the DPL pixel grid, so the + // cell must be ripped up first to avoid blocking itself. + ripUp(idx); + const PixelPt pt + = opendp_->diamondSearch(node, GridX{cell.x}, GridY{cell.y}); + if (pt.pixel) { + place(idx, pt.x.v, pt.y.v); + logger_->report("diamondRecovery: cell {} recovered at ({}, {}).", + cell.db_inst->getName(), + pt.x.v, + pt.y.v); + ++recovered; + } else { + // No legal site found — restore at current position so the negotiation + // loop can keep trying. + place(idx, cell.x, cell.y); + } + } + logger_->report("diamondRecovery: recovered {}/{} stuck cells.", + recovered, + activeCells.size()); +} + +} // namespace dpl diff --git a/src/dpl/src/Opendp.cpp b/src/dpl/src/Opendp.cpp index 3a03f7328ff..b776062688c 100644 --- a/src/dpl/src/Opendp.cpp +++ b/src/dpl/src/Opendp.cpp @@ -14,6 +14,7 @@ #include #include +#include "NegotiationLegalizer.h" #include "PlacementDRC.h" #include "boost/geometry/index/predicates.hpp" #include "dpl/OptMirror.h" @@ -115,9 +116,12 @@ Journal* Opendp::getJournal() const void Opendp::detailedPlacement(const int max_displacement_x, const int max_displacement_y, const std::string& report_file_name, - bool incremental) + bool incremental, + const bool use_negotiation, + const bool run_abacus) { incremental_ = incremental; + use_negotiation_ |= use_negotiation; importDb(); adjustNodesOrient(); if (!incremental_) { @@ -132,8 +136,39 @@ void Opendp::detailedPlacement(const int max_displacement_x, logger_->warn(DPL, 37, "Use remove_fillers before detailed placement."); } + { + const int64_t core_area + = static_cast(core_.dx()) * static_cast(core_.dy()); + int64_t inst_area = 0; + for (const auto& node : network_->getNodes()) { + if (node->getType() == Node::CELL) { + inst_area += static_cast(node->getWidth().v) + * static_cast(node->getHeight().v); + } + } + const double utilization = core_area > 0 + ? (static_cast(inst_area) + / static_cast(core_area)) + * 100.0 + : 0.0; + logger_->info(DPL, + 6, + "Core area: {:.2f} um^2, Instances area: {:.2f} um^2, " + "Utilization: {:.1f}%", + block_->dbuAreaToMicrons(core_area), + block_->dbuAreaToMicrons(inst_area), + utilization); + logger_->metric("utilizatin__before__dpl", utilization); + if (utilization > 100.0) { + logger_->error( + DPL, 38, "Utilization greater than 100%, impossible to legalize"); + } + } + + odb::WireLengthEvaluator eval(block_); + hpwl_before_ = eval.hpwl(); + if (max_displacement_x == 0 || max_displacement_y == 0) { - // defaults max_displacement_x_ = 500; max_displacement_y_ = 100; } else { @@ -141,33 +176,60 @@ void Opendp::detailedPlacement(const int max_displacement_x, max_displacement_y_ = max_displacement_y; } - logger_->info( - DPL, - 5, - "Max displacement: +/- {} sites horizontally, +/- {} rows vertically.", - max_displacement_x_, - max_displacement_y_); + logger_->info(DPL, + 5, + "Diamond search max displacement: +/- {} sites horizontally, " + "+/- {} rows vertically.", + max_displacement_x_, + max_displacement_y_); + + if (!use_negotiation_) { + logger_->info(DPL, 1101, "Legalizing using diamond search."); + diamondDPL(); + findDisplacementStats(); + updateDbInstLocations(); + if (!placement_failures_.empty()) { + logger_->info(DPL, + 34, + "Detailed placement failed on the following {} instances:", + placement_failures_.size()); + for (auto cell : placement_failures_) { + logger_->info(DPL, 35, " {}", cell->name()); + } - odb::WireLengthEvaluator eval(block_); - hpwl_before_ = eval.hpwl(); - detailedPlacement(); - // Save displacement stats before updating instance DB locations. - findDisplacementStats(); - updateDbInstLocations(); - if (!placement_failures_.empty()) { - logger_->info(DPL, - 34, - "Detailed placement failed on the following {} instances:", - placement_failures_.size()); - for (auto cell : placement_failures_) { - logger_->info(DPL, 35, " {}", cell->name()); + saveFailures({}, {}, {}, {}, {}, {}, {}, placement_failures_, {}, {}); + if (!report_file_name.empty()) { + writeJsonReport(report_file_name); + } + logger_->error(DPL, 36, "Detailed placement failed inside DPL."); } - - saveFailures({}, {}, {}, {}, {}, {}, {}, placement_failures_, {}, {}); - if (!report_file_name.empty()) { - writeJsonReport(report_file_name); + } else { + initGrid(); + setFixedGridCells(); + logger_->info(DPL, 1102, "Legalizing using negotiation legalizer."); + + NegotiationLegalizer negotiation(this, + db_, + logger_, + padding_.get(), + debug_observer_.get(), + network_.get()); + negotiation.setRunAbacus(run_abacus); + negotiation.legalize(); + negotiation.setDplPositions(); + + if (negotiation.numViolations() > 0) { + logger_->warn(DPL, + 701, + "NegotiationLegalizer did not fully converge. " + "Violations remain: {}", + negotiation.numViolations()); + logger_->metric("NL__no__converge__final_violations", + negotiation.numViolations()); } - logger_->error(DPL, 36, "Detailed placement failed."); + + findDisplacementStats(); + updateDbInstLocations(); } } @@ -221,6 +283,8 @@ void Opendp::reportLegalizationStats() const : round((hpwl_legal - hpwl_before_) / hpwl_before_ * 100); logger_->report("delta HPWL {:10} %", hpwl_delta); logger_->report(""); + logger_->metric("dpl__hpwl__delta", hpwl_legal - hpwl_before_); + logger_->metric("dpl__hpwl__delta__percent", hpwl_delta); } //////////////////////////////////////////////////////////////// diff --git a/src/dpl/src/Opendp.i b/src/dpl/src/Opendp.i index 2a611d364eb..ef0cd61a3b4 100644 --- a/src/dpl/src/Opendp.i +++ b/src/dpl/src/Opendp.i @@ -27,9 +27,13 @@ void detailed_placement_cmd(int max_displacment_x, int max_displacment_y, const char* report_file_name, - bool incremental){ + bool incremental, + bool use_negotiation, + bool run_abacus){ dpl::Opendp *opendp = ord::OpenRoad::openRoad()->getOpendp(); - opendp->detailedPlacement(max_displacment_x, max_displacment_y, std::string(report_file_name), incremental); + opendp->detailedPlacement(max_displacment_x, max_displacment_y, + std::string(report_file_name), + incremental, use_negotiation, run_abacus); } void @@ -102,7 +106,8 @@ set_debug_cmd(float min_displacement, int jump_moves, bool iterative_placement, bool deep_iterative_placement, - bool paint_pixels) + bool paint_pixels, + bool paint_negotiation_pixels) { dpl::Opendp* opendp = ord::OpenRoad::openRoad()->getOpendp(); opendp->setJumpMoves(jump_moves); @@ -110,7 +115,7 @@ set_debug_cmd(float min_displacement, opendp->setDeepIterativePlacement(deep_iterative_placement); if (dpl::Graphics::guiActive()) { std::unique_ptr graphics = std::make_unique( - opendp, debug_instance, paint_pixels); + opendp, debug_instance, paint_pixels, paint_negotiation_pixels); opendp->setDebug(graphics); } } diff --git a/src/dpl/src/Opendp.tcl b/src/dpl/src/Opendp.tcl index 364c8dc10d6..059b1dc1f10 100644 --- a/src/dpl/src/Opendp.tcl +++ b/src/dpl/src/Opendp.tcl @@ -5,11 +5,14 @@ sta::define_cmd_args "detailed_placement" { \ [-max_displacement disp|{disp_x disp_y}] \ [-disallow_one_site_gaps] \ [-incremental] \ - [-report_file_name file_name]} + [-report_file_name file_name] \ + [-use_negotiation] \ + [-abacus]} proc detailed_placement { args } { sta::parse_key_args "detailed_placement" args \ - keys {-max_displacement -report_file_name} flags {-disallow_one_site_gaps -incremental} + keys {-max_displacement -report_file_name} \ + flags {-disallow_one_site_gaps -incremental -use_negotiation -abacus} if { [info exists keys(-max_displacement)] } { set max_displacement $keys(-max_displacement) @@ -48,7 +51,9 @@ proc detailed_placement { args } { set max_displacement_y [expr [ord::microns_to_dbu $max_displacement_y] \ / [$site getHeight]] dpl::detailed_placement_cmd $max_displacement_x $max_displacement_y \ - $file_name [info exists flags(-incremental)] + $file_name [info exists flags(-incremental)] \ + [info exists flags(-use_negotiation)] \ + [info exists flags(-abacus)] dpl::report_legalization_stats } else { utl::error "DPL" 27 "no rows defined in design. Use initialize_floorplan to add rows." @@ -299,7 +304,7 @@ namespace eval dpl { proc detailed_placement_debug { args } { sta::parse_key_args "detailed_placement_debug" args \ keys {-instance -min_displacement -jump_moves} \ - flags {-iterative -deep_iterative -paint_pixels} ;# checker off + flags {-iterative -deep_iterative -paint_pixels -paint_negotiation_pixels} ;# checker off if { [info exists keys(-min_displacement)] } { @@ -327,7 +332,7 @@ proc detailed_placement_debug { args } { dpl::set_debug_cmd $min_displacement $debug_instance $jump_moves \ [info exists flags(-iterative)] [info exists flags(-deep_iterative)] \ - [info exists flags(-paint_pixels)] + [info exists flags(-paint_pixels)] [info exists flags(-paint_negotiation_pixels)] } proc get_masters_arg { arg_name arg } { diff --git a/src/dpl/src/Place.cpp b/src/dpl/src/Place.cpp index 4a886339f7a..8ff15fbe8b0 100644 --- a/src/dpl/src/Place.cpp +++ b/src/dpl/src/Place.cpp @@ -58,7 +58,7 @@ std::string Opendp::printBgBox( queryBox.max_corner().y()); } -void Opendp::detailedPlacement() +void Opendp::diamondDPL() { if (debug_observer_) { debug_observer_->startPlacement(block_); @@ -392,7 +392,10 @@ void Opendp::place() bool diamond_move = diamondMove(cell); bool rip_up_move = false; + if (!diamond_move) { + // TODO: this is non-deteministic due to std::set, + // and experiments show no legalization for failed diamond searches. rip_up_move = ripUpAndReplace(cell); if (!rip_up_move) { failed_rip_up++; @@ -658,7 +661,7 @@ bool Opendp::diamondMove(Node* cell, const GridPt& grid_pt) if (pixel_pt.pixel) { placeCell(cell, pixel_pt.x, pixel_pt.y); if (debug_observer_) { - debug_observer_->placeInstance(cell->getDbInst()); + debug_observer_->drawSelected(cell->getDbInst(), false); } return true; } diff --git a/src/dpl/src/PlacementDRC.cpp b/src/dpl/src/PlacementDRC.cpp index 45660c01fd7..bde60fd024c 100644 --- a/src/dpl/src/PlacementDRC.cpp +++ b/src/dpl/src/PlacementDRC.cpp @@ -14,9 +14,12 @@ #include "odb/dbTypes.h" #include "odb/geom.h" #include "odb/isotropy.h" +#include "utl/Logger.h" namespace dpl { +using utl::DPL; + namespace cell_edges { odb::Rect transformEdgeRect(const odb::Rect& edge_rect, const Node* cell, @@ -50,11 +53,13 @@ odb::Rect getQueryRect(const odb::Rect& edge_box, const int spc) }; // namespace cell_edges // Constructor -PlacementDRC::PlacementDRC(Grid* grid, +PlacementDRC::PlacementDRC(utl::Logger* logger, + Grid* grid, odb::dbTech* tech, Padding* padding, bool disallow_one_site_gap) - : grid_(grid), + : logger_(logger), + grid_(grid), padding_(padding), disallow_one_site_gap_(disallow_one_site_gap) { @@ -189,8 +194,60 @@ bool PlacementDRC::checkDRC(const Node* cell, const GridY y, const odb::dbOrientType& orient) const { - return checkEdgeSpacing(cell, x, y, orient) && checkPadding(cell, x, y) - && checkBlockedLayers(cell, x, y) && checkOneSiteGap(cell, x, y); + const std::string cell_name = cell->name(); + + const bool edge_ok = checkEdgeSpacing(cell, x, y, orient); + const bool padding_ok = checkPadding(cell, x, y); + const bool blocked_ok = checkBlockedLayers(cell, x, y); + const bool gap_ok = checkOneSiteGap(cell, x, y); + + const bool all_ok = edge_ok && padding_ok && blocked_ok && gap_ok; + + if (!all_ok && logger_->debugCheck(DPL, "checkDRC", 1)) { + debugPrint( + logger_, + DPL, + "checkDRC", + 1, + "cell {} at ({}, {}): ok?={} edge={} padding={} blocked={} gap={}", + cell_name, + x.v, + y.v, + all_ok ? 1 : 0, + edge_ok ? 1 : 0, + padding_ok ? 1 : 0, + blocked_ok ? 1 : 0, + gap_ok ? 1 : 0); + } + + return all_ok; +} + +int PlacementDRC::countDRCViolations(const Node* cell) const +{ + return countDRCViolations( + cell, grid_->gridX(cell), grid_->gridRoundY(cell), cell->getOrient()); +} + +int PlacementDRC::countDRCViolations(const Node* cell, + const GridX x, + const GridY y, + const odb::dbOrientType& orient) const +{ + int count = 0; + if (!checkEdgeSpacing(cell, x, y, orient)) { + ++count; + } + if (!checkPadding(cell, x, y)) { + ++count; + } + if (!checkBlockedLayers(cell, x, y)) { + ++count; + } + if (!checkOneSiteGap(cell, x, y)) { + ++count; + } + return count; } namespace { diff --git a/src/dpl/src/PlacementDRC.h b/src/dpl/src/PlacementDRC.h index 71003b55ffa..82fa81160a7 100644 --- a/src/dpl/src/PlacementDRC.h +++ b/src/dpl/src/PlacementDRC.h @@ -6,6 +6,7 @@ #include "dpl/Opendp.h" #include "infrastructure/Coordinates.h" +#include "utl/Logger.h" namespace odb { class dbTech; @@ -35,7 +36,8 @@ class PlacementDRC { public: // Constructor - PlacementDRC(Grid* grid, + PlacementDRC(utl::Logger* logger, + Grid* grid, odb::dbTech* tech, Padding* padding, bool disallow_one_site_gap); @@ -62,12 +64,20 @@ class PlacementDRC GridY y, const odb::dbOrientType& orient) const; + // Count the number of DRC check categories that fail (0–4) + int countDRCViolations(const Node* cell) const; + int countDRCViolations(const Node* cell, + GridX x, + GridY y, + const odb::dbOrientType& orient) const; + int getEdgeTypeIdx(const std::string& edge_type) const; bool hasCellEdgeSpacingTable() const; int getMaxSpacing(int edge_type_idx) const; private: // Member variables + utl::Logger* logger_{nullptr}; Grid* grid_{nullptr}; // Pointer to the grid for placement Padding* padding_{nullptr}; // Pointer to the padding std::unordered_map edge_types_indices_; diff --git a/src/dpl/src/dbToOpendp.cpp b/src/dpl/src/dbToOpendp.cpp index 54249fbbc48..9796e59cddb 100644 --- a/src/dpl/src/dbToOpendp.cpp +++ b/src/dpl/src/dbToOpendp.cpp @@ -143,8 +143,11 @@ void Opendp::importClear() void Opendp::initPlacementDRC() { - drc_engine_ = std::make_unique( - grid_.get(), db_->getTech(), padding_.get(), !odb::hasOneSiteMaster(db_)); + drc_engine_ = std::make_unique(logger_, + grid_.get(), + db_->getTech(), + padding_.get(), + !odb::hasOneSiteMaster(db_)); } static bool swapWidthHeight(const dbOrientType& orient) diff --git a/src/dpl/src/graphics/DplObserver.h b/src/dpl/src/graphics/DplObserver.h index 9e352c104d6..9f03cff6909 100644 --- a/src/dpl/src/graphics/DplObserver.h +++ b/src/dpl/src/graphics/DplObserver.h @@ -3,21 +3,37 @@ #pragma once +#include +#include + #include "dpl/Opendp.h" #include "odb/db.h" +#include "odb/geom.h" namespace dpl { class Opendp; class Node; +// Pixel state values passed from NegotiationLegalizer to the observer. +enum class NegotiationPixelState : int8_t +{ + kNoRow = 0, // no row exists here (capacity == 0, not a blockage) + kFree = 1, // valid site, unused + kOccupied = 2, // valid site, usage == capacity + kOveruse = 3, // valid site, usage > capacity + kBlocked = 4, // blockage (fixed cell / capacity forced to 0) + kInvalid = 5, // pixel is outside of core or in a hole (is_valid == false) + kDrcViolation = 6 // cell at this site fails a PlacementDRC check +}; + class DplObserver { public: virtual ~DplObserver() = default; virtual void startPlacement(odb::dbBlock* block) = 0; - virtual void placeInstance(odb::dbInst* instance) = 0; + virtual void drawSelected(odb::dbInst* instance, bool force) = 0; virtual void binSearch(const Node* cell, GridX xl, GridY yl, @@ -25,6 +41,31 @@ class DplObserver GridY yh) = 0; virtual void redrawAndPause() = 0; + virtual const odb::dbInst* getDebugInstance() const { return nullptr; } + + // Negotiation-legalizer grid visualisation support (default no-ops). + virtual void setNegotiationPixels( + const std::vector& pixels, + int grid_w, + int grid_h, + int die_xlo, + int die_ylo, + int site_width, + const std::vector& row_y_dbu) + { + } + virtual void clearNegotiationPixels() {} + + // Store the search window for |inst| so it can be drawn when that instance + // is selected in the GUI. |curr_window| is the window around the current + // (displaced) position; pass an empty Rect when the cell has not moved. + virtual void setNegotiationSearchWindow(odb::dbInst* inst, + const odb::Rect& init_window, + const odb::Rect& curr_window) + { + } + // Clear all stored search windows (call at the start of each iteration). + virtual void clearNegotiationSearchWindows() {} }; } // namespace dpl diff --git a/src/dpl/src/graphics/Graphics.cpp b/src/dpl/src/graphics/Graphics.cpp index 1eff479a24b..06b969dfd48 100644 --- a/src/dpl/src/graphics/Graphics.cpp +++ b/src/dpl/src/graphics/Graphics.cpp @@ -6,8 +6,10 @@ #include #include #include +#include #include "dpl/Opendp.h" +#include "graphics/DplObserver.h" #include "gui/gui.h" #include "infrastructure/Coordinates.h" #include "infrastructure/Grid.h" @@ -20,8 +22,12 @@ namespace dpl { Graphics::Graphics(Opendp* dp, const odb::dbInst* debug_instance, - bool paint_pixels) - : dp_(dp), debug_instance_(debug_instance), paint_pixels_(paint_pixels) + bool paint_pixels, + bool paint_negotiation_pixels) + : dp_(dp), + debug_instance_(debug_instance), + paint_pixels_(paint_pixels), + paint_negotiation_pixels_(paint_negotiation_pixels) { gui::Gui::get()->registerRenderer(this); } @@ -31,9 +37,10 @@ void Graphics::startPlacement(odb::dbBlock* block) block_ = block; } -void Graphics::placeInstance(odb::dbInst* instance) +void Graphics::drawSelected(odb::dbInst* instance, bool force) { - if (!instance || instance != debug_instance_) { + // When force is true always select and pause + if (!instance || (!force && instance != debug_instance_)) { return; } @@ -123,6 +130,20 @@ void Graphics::drawObjects(gui::Painter& painter) // Check if the instance is selected if (selected_insts.contains(cell->getDbInst())) { line_color = gui::Painter::kYellow; + + // Draw outline of instance at target location + odb::Rect bbox = cell->getDbInst()->getBBox()->getBox(); + int width = bbox.dx(); + int height = bbox.dy(); + odb::Rect target_bbox(final_location.x(), + final_location.y(), + final_location.x() + width, + final_location.y() + height); + auto outline_color = gui::Painter::kCyan; + // outline_color.a = 150; + painter.setPen(outline_color, /* cosmetic */ true); + painter.setBrush(gui::Painter::kTransparent); + painter.drawRect(target_bbox); } else if (std::abs(dx) > std::abs(dy)) { line_color = (dx > 0) ? gui::Painter::kGreen : gui::Painter::kRed; } else { @@ -138,6 +159,7 @@ void Graphics::drawObjects(gui::Painter& painter) painter.drawCircle(final_location.x(), final_location.y(), 100); } + // Diamond search range auto color = gui::Painter::kCyan; color.a = 100; painter.setPen(color); @@ -176,6 +198,121 @@ void Graphics::drawObjects(gui::Painter& painter) } } } + + if (paint_negotiation_pixels_ && !negotiation_pixels_.empty()) { + const int sw = negotiation_site_width_; + for (int gy = 0; gy < negotiation_grid_h_; ++gy) { + const int y_lo = negotiation_die_ylo_ + negotiation_row_y_dbu_[gy]; + const int y_hi = negotiation_die_ylo_ + negotiation_row_y_dbu_[gy + 1]; + for (int gx = 0; gx < negotiation_grid_w_; ++gx) { + const auto state = negotiation_pixels_[gy * negotiation_grid_w_ + gx]; + gui::Painter::Color c; + switch (state) { + case NegotiationPixelState::kNoRow: + c = gui::Painter::kDarkGray; + c.a = 60; + break; + case NegotiationPixelState::kFree: + c = gui::Painter::kGreen; + c.a = 100; + break; + case NegotiationPixelState::kOccupied: + c = gui::Painter::kWhite; + c.a = 100; + break; + case NegotiationPixelState::kOveruse: + c = gui::Painter::kRed; + c.a = 150; + break; + case NegotiationPixelState::kBlocked: + c = gui::Painter::kYellow; + c.a = 80; + break; + case NegotiationPixelState::kInvalid: + c = gui::Painter::kBlack; + c.a = 200; + break; + case NegotiationPixelState::kDrcViolation: + c = gui::Painter::Color{255, 140, 0, 200}; // orange + break; + } + painter.setPen(c); + painter.setBrush(c); + odb::Rect rect(negotiation_die_xlo_ + gx * sw, + y_lo, + negotiation_die_xlo_ + (gx + 1) * sw, + y_hi); + painter.drawRect(rect); + } + } + } + + if (!negotiation_search_windows_.empty()) { + painter.setBrush(gui::Painter::kTransparent); + for (const auto& sel : selection) { + if (!sel.isInst()) { + continue; + } + auto* inst = std::any_cast(sel.getObject()); + auto it = negotiation_search_windows_.find(inst); + if (it == negotiation_search_windows_.end()) { + continue; + } + const auto& [init_win, curr_win] = it->second; + + // Init-position search window + auto init_color = gui::Painter::kCyan; + painter.setPen(init_color, /* cosmetic */ true); + painter.drawRect(init_win); + + // Current-position window (only when the cell is displaced). + if (!curr_win.isInverted() && curr_win.area() > 0) { + auto curr_color = gui::Painter::kWhite; + curr_color.a = 200; + painter.setPen(curr_color, /* cosmetic */ true); + painter.drawRect(curr_win); + } + } + } +} + +void Graphics::setNegotiationPixels( + const std::vector& pixels, + int grid_w, + int grid_h, + int die_xlo, + int die_ylo, + int site_width, + const std::vector& row_y_dbu) +{ + negotiation_pixels_ = pixels; + negotiation_grid_w_ = grid_w; + negotiation_grid_h_ = grid_h; + negotiation_die_xlo_ = die_xlo; + negotiation_die_ylo_ = die_ylo; + negotiation_site_width_ = site_width; + negotiation_row_y_dbu_ = row_y_dbu; +} + +void Graphics::clearNegotiationPixels() +{ + negotiation_pixels_.clear(); + negotiation_row_y_dbu_.clear(); + negotiation_grid_w_ = 0; + negotiation_grid_h_ = 0; + negotiation_search_windows_.clear(); +} + +void Graphics::setNegotiationSearchWindow(odb::dbInst* inst, + const odb::Rect& init_window, + const odb::Rect& curr_window) +{ + negotiation_search_windows_[inst] = {init_window, curr_window}; +} + +void Graphics::clearNegotiationSearchWindows() +{ + negotiation_search_windows_.clear(); } /* static */ diff --git a/src/dpl/src/graphics/Graphics.h b/src/dpl/src/graphics/Graphics.h index b183782887c..81072da5e7d 100644 --- a/src/dpl/src/graphics/Graphics.h +++ b/src/dpl/src/graphics/Graphics.h @@ -3,6 +3,8 @@ #pragma once +#include +#include #include #include "DplObserver.h" @@ -21,16 +23,35 @@ class Graphics : public gui::Renderer, public DplObserver public: Graphics(Opendp* dp, const odb::dbInst* debug_instance, - bool paint_pixels = true); + bool paint_pixels = true, + bool paint_negotiation_pixels = false); ~Graphics() override = default; void startPlacement(odb::dbBlock* block) override; - void placeInstance(odb::dbInst* instance) override; + void drawSelected(odb::dbInst* instance, bool force) override; void binSearch(const Node* cell, GridX xl, GridY yl, GridX xh, GridY yh) override; void redrawAndPause() override; + const odb::dbInst* getDebugInstance() const override + { + return debug_instance_; + } + + // NegotiationLegalizer grid visualisation + void setNegotiationPixels(const std::vector& pixels, + int grid_w, + int grid_h, + int die_xlo, + int die_ylo, + int site_width, + const std::vector& row_y_dbu) override; + void clearNegotiationPixels() override; + void setNegotiationSearchWindow(odb::dbInst* inst, + const odb::Rect& init_window, + const odb::Rect& curr_window) override; + void clearNegotiationSearchWindows() override; // From Renderer API void drawObjects(gui::Painter& painter) override; @@ -42,7 +63,23 @@ class Graphics : public gui::Renderer, public DplObserver const odb::dbInst* debug_instance_; odb::dbBlock* block_ = nullptr; bool paint_pixels_; + bool paint_negotiation_pixels_; std::vector searched_; + + // NegotiationLegalizer grid snapshot for rendering + std::vector negotiation_pixels_; + int negotiation_grid_w_{0}; + int negotiation_grid_h_{0}; + int negotiation_die_xlo_{0}; + int negotiation_die_ylo_{0}; + int negotiation_site_width_{0}; + std::vector negotiation_row_y_dbu_; + + // Per-cell search windows: init window + current-position window (may be + // empty if the cell is not displaced). Keyed by dbInst* so drawObjects() + // can look up whichever instance the user has selected in the GUI. + std::unordered_map> + negotiation_search_windows_; }; } // namespace dpl diff --git a/src/dpl/src/infrastructure/Grid.h b/src/dpl/src/infrastructure/Grid.h index 7bd2b3baba5..c8ae47ed2da 100644 --- a/src/dpl/src/infrastructure/Grid.h +++ b/src/dpl/src/infrastructure/Grid.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include #include @@ -48,6 +49,13 @@ struct Pixel uint8_t blocked_layers = 0; // Cell that reserved this pixel for padding Node* padding_reserved_by = nullptr; + + // Hybrid negotiation data + int capacity = 0; // 1 if site exists, 0 if blockage + int usage = 0; + double hist_cost = 1.0; + + [[nodiscard]] int overuse() const { return std::max(usage - capacity, 0); } }; // Return value for grid searches. diff --git a/src/dpl/test/aes.ok b/src/dpl/test/aes.ok index 779f3cfb25c..754201a45cc 100644 --- a/src/dpl/test/aes.ok +++ b/src/dpl/test/aes.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 391 pins. [INFO ODB-0131] Created 21340 components and 108388 component-terminals. [INFO ODB-0133] Created 19675 nets and 65708 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 289247.87 um^2, Instances area: 24789.07 um^2, Utilization: 8.6% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 18883 diff --git a/src/dpl/test/blockage01.ok b/src/dpl/test/blockage01.ok index 2a577bcb1fc..e63e134560d 100644 --- a/src/dpl/test/blockage01.ok +++ b/src/dpl/test/blockage01.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/cell_on_block1.ok b/src/dpl/test/cell_on_block1.ok index 75808d5afd3..54a59227c45 100644 --- a/src/dpl/test/cell_on_block1.ok +++ b/src/dpl/test/cell_on_block1.ok @@ -4,7 +4,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 5 components and 20 component-terminals. [INFO ODB-0133] Created 2 nets and 0 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 9607.92 um^2, Instances area: 2503.19 um^2, Utilization: 26.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 4 diff --git a/src/dpl/test/cell_on_block2.ok b/src/dpl/test/cell_on_block2.ok index 1f2b6aa32dc..615788ec95f 100644 --- a/src/dpl/test/cell_on_block2.ok +++ b/src/dpl/test/cell_on_block2.ok @@ -5,7 +5,9 @@ [INFO ODB-0130] Created 201 pins. [INFO ODB-0131] Created 11904 components and 90887 component-terminals. [INFO ODB-0133] Created 31790 nets and 67032 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 8048318.98 um^2, Instances area: 52327.69 um^2, Utilization: 0.7% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 2916 diff --git a/src/dpl/test/check1.ok b/src/dpl/test/check1.ok index 79e3729c099..21ec887a2b2 100644 --- a/src/dpl/test/check1.ok +++ b/src/dpl/test/check1.ok @@ -6,5 +6,5 @@ [INFO ODB-0133] Created 2 nets and 2 connections. [WARNING DPL-0006] Site aligned check failed (1). _277_ -[ERROR DPL-0033] detailed placement checks failed. +[ERROR DPL-0033] detailed placement checks failed during check placement. DPL-0033 diff --git a/src/dpl/test/check2.ok b/src/dpl/test/check2.ok index 5d830f935ef..39cf771b488 100644 --- a/src/dpl/test/check2.ok +++ b/src/dpl/test/check2.ok @@ -5,5 +5,5 @@ _285_ (NOR2_X1) overlaps _284_ (NOR2_X1) [WARNING DPL-0011] Padding check failed (1). _285_ -[ERROR DPL-0033] detailed placement checks failed. +[ERROR DPL-0033] detailed placement checks failed during check placement. DPL-0033 diff --git a/src/dpl/test/check3.ok b/src/dpl/test/check3.ok index a7e9d4e5816..3065e2c26ef 100644 --- a/src/dpl/test/check3.ok +++ b/src/dpl/test/check3.ok @@ -3,5 +3,5 @@ [INFO ODB-0131] Created 2 components and 10 component-terminals. [WARNING DPL-0011] Padding check failed (1). _285_ -[ERROR DPL-0033] detailed placement checks failed. +[ERROR DPL-0033] detailed placement checks failed during check placement. DPL-0033 diff --git a/src/dpl/test/check4.ok b/src/dpl/test/check4.ok index 1066c56ed7c..a2890f6f5d0 100644 --- a/src/dpl/test/check4.ok +++ b/src/dpl/test/check4.ok @@ -6,5 +6,5 @@ [INFO ODB-0133] Created 2 nets and 0 connections. [WARNING DPL-0006] Site aligned check failed (1). FILL01 -[ERROR DPL-0033] detailed placement checks failed. +[ERROR DPL-0033] detailed placement checks failed during check placement. DPL-0033 diff --git a/src/dpl/test/check6.ok b/src/dpl/test/check6.ok index d87820a70ad..1101d35d6cf 100644 --- a/src/dpl/test/check6.ok +++ b/src/dpl/test/check6.ok @@ -6,7 +6,9 @@ [INFO ODB-0131] Created 2 components and 11 component-terminals. [INFO ODB-0132] Created 2 special nets and 4 connections. [INFO ODB-0133] Created 2 nets and 0 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 4.80 um^2, Utilization: 14.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/check7.ok b/src/dpl/test/check7.ok index 68b93400401..2fbc90dd4e3 100644 --- a/src/dpl/test/check7.ok +++ b/src/dpl/test/check7.ok @@ -8,5 +8,5 @@ [INFO ODB-0133] Created 2 nets and 0 connections. [WARNING DPL-0011] Padding check failed (1). block1 -[ERROR DPL-0033] detailed placement checks failed. +[ERROR DPL-0033] detailed placement checks failed during check placement. DPL-0033 diff --git a/src/dpl/test/edge_spacing.ok b/src/dpl/test/edge_spacing.ok index 13c283e8ed3..cc1bbfc50fd 100644 --- a/src/dpl/test/edge_spacing.ok +++ b/src/dpl/test/edge_spacing.ok @@ -4,7 +4,9 @@ [INFO ODB-0128] Design: top [INFO ODB-0130] Created 6 pins. [INFO ODB-0131] Created 5 components and 25 component-terminals. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 54.26 um^2, Instances area: 9.58 um^2, Utilization: 17.6% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 5 diff --git a/src/dpl/test/fence01.ok b/src/dpl/test/fence01.ok index f5a051d0a49..a3308f7eb49 100644 --- a/src/dpl/test/fence01.ok +++ b/src/dpl/test/fence01.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 10 components and 45 component-terminals. [INFO ODB-0133] Created 11 nets and 25 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 8.51 um^2, Utilization: 51.6% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 0 diff --git a/src/dpl/test/fence02.ok b/src/dpl/test/fence02.ok index 2a860e784f9..71d32d5a16d 100644 --- a/src/dpl/test/fence02.ok +++ b/src/dpl/test/fence02.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 10 components and 45 component-terminals. [INFO ODB-0133] Created 11 nets and 25 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 8.51 um^2, Utilization: 51.6% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 0 diff --git a/src/dpl/test/fence03.ok b/src/dpl/test/fence03.ok index dca2fddd01c..ed438665ac6 100644 --- a/src/dpl/test/fence03.ok +++ b/src/dpl/test/fence03.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 10 components and 45 component-terminals. [INFO ODB-0133] Created 11 nets and 25 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 8.51 um^2, Utilization: 51.6% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 0 diff --git a/src/dpl/test/fillers1.ok b/src/dpl/test/fillers1.ok index f40fc7aa16b..b96d20a9220 100644 --- a/src/dpl/test/fillers1.ok +++ b/src/dpl/test/fillers1.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/fillers10.ok b/src/dpl/test/fillers10.ok index d6f523dcd31..2b86c3b7a36 100644 --- a/src/dpl/test/fillers10.ok +++ b/src/dpl/test/fillers10.ok @@ -5,7 +5,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 9576.00 um^2, Instances area: 1.86 um^2, Utilization: 0.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/fillers11.ok b/src/dpl/test/fillers11.ok index c5eece86e78..fc0def05166 100644 --- a/src/dpl/test/fillers11.ok +++ b/src/dpl/test/fillers11.ok @@ -6,7 +6,9 @@ [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. [WARNING DPL-0387] BTerm float is unplaced. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 9576.00 um^2, Instances area: 1.86 um^2, Utilization: 0.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/fillers2.ok b/src/dpl/test/fillers2.ok index f40fc7aa16b..b96d20a9220 100644 --- a/src/dpl/test/fillers2.ok +++ b/src/dpl/test/fillers2.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/fillers2_verbose.ok b/src/dpl/test/fillers2_verbose.ok index c535a6db68d..bb0aa4216aa 100644 --- a/src/dpl/test/fillers2_verbose.ok +++ b/src/dpl/test/fillers2_verbose.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/fillers3.ok b/src/dpl/test/fillers3.ok index 99d5bf322a4..207d98b1ad2 100644 --- a/src/dpl/test/fillers3.ok +++ b/src/dpl/test/fillers3.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/fillers4.ok b/src/dpl/test/fillers4.ok index 76a2d367aee..1878ad486a4 100644 --- a/src/dpl/test/fillers4.ok +++ b/src/dpl/test/fillers4.ok @@ -5,7 +5,9 @@ [INFO ODB-0131] Created 2 components and 8 component-terminals. [INFO ODB-0132] Created 2 special nets and 4 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.60 um^2, Utilization: 4.7% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 2 diff --git a/src/dpl/test/fillers5.ok b/src/dpl/test/fillers5.ok index 42f4bda3a12..ec39686ae9c 100644 --- a/src/dpl/test/fillers5.ok +++ b/src/dpl/test/fillers5.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/fillers7.ok b/src/dpl/test/fillers7.ok index f40fc7aa16b..b96d20a9220 100644 --- a/src/dpl/test/fillers7.ok +++ b/src/dpl/test/fillers7.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/fillers8.ok b/src/dpl/test/fillers8.ok index e8929b3dd53..9f9f30fb069 100644 --- a/src/dpl/test/fillers8.ok +++ b/src/dpl/test/fillers8.ok @@ -5,7 +5,9 @@ [INFO ODB-0132] Created 2 special nets and 14 connections. [INFO ODB-0133] Created 2 nets and 2 connections. [WARNING DPL-0037] Use remove_fillers before detailed placement. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 34.05 um^2, Utilization: 100.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 7 diff --git a/src/dpl/test/fragmented_row01.ok b/src/dpl/test/fragmented_row01.ok index 88fdb8897a7..b298628e609 100644 --- a/src/dpl/test/fragmented_row01.ok +++ b/src/dpl/test/fragmented_row01.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 1.86 um^2, Utilization: 11.3% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/fragmented_row02.ok b/src/dpl/test/fragmented_row02.ok index 7055aed340e..6f7b595284f 100644 --- a/src/dpl/test/fragmented_row02.ok +++ b/src/dpl/test/fragmented_row02.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 1.86 um^2, Utilization: 11.3% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/fragmented_row03.ok b/src/dpl/test/fragmented_row03.ok index ce8a92a3933..c512e58b343 100644 --- a/src/dpl/test/fragmented_row03.ok +++ b/src/dpl/test/fragmented_row03.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 4.79 um^2, Instances area: 1.86 um^2, Utilization: 38.9% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 @@ -15,10 +17,10 @@ Total Placement Failures: 1 --------------------------------------- [INFO DPL-0034] Detailed placement failed on the following 1 instances: [INFO DPL-0035] _277_ -[ERROR DPL-0036] Detailed placement failed. +[ERROR DPL-0036] Detailed placement failed inside DPL. DPL-0036 [WARNING DPL-0006] Site aligned check failed (1). _277_ -[ERROR DPL-0033] detailed placement checks failed. +[ERROR DPL-0033] detailed placement checks failed during check placement. DPL-0033 No differences found. diff --git a/src/dpl/test/fragmented_row04.ok b/src/dpl/test/fragmented_row04.ok index 53414317dcb..1779ebee578 100644 --- a/src/dpl/test/fragmented_row04.ok +++ b/src/dpl/test/fragmented_row04.ok @@ -6,9 +6,11 @@ [INFO ODB-0133] Created 2 nets and 2 connections. [WARNING DPL-0004] Placed in rows check failed (1). _277_ -[ERROR DPL-0033] detailed placement checks failed. +[ERROR DPL-0033] detailed placement checks failed during check placement. DPL-0033 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/gcd.ok b/src/dpl/test/gcd.ok index 9e88e00dc75..987222e0f85 100644 --- a/src/dpl/test/gcd.ok +++ b/src/dpl/test/gcd.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 54 pins. [INFO ODB-0131] Created 549 components and 2166 component-terminals. [INFO ODB-0133] Created 364 nets and 1068 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 14266.91 um^2, Instances area: 637.60 um^2, Utilization: 4.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 294 diff --git a/src/dpl/test/gcd_no_one_site_sanity.ok b/src/dpl/test/gcd_no_one_site_sanity.ok index ecb36f4e254..36507e8e5ab 100644 --- a/src/dpl/test/gcd_no_one_site_sanity.ok +++ b/src/dpl/test/gcd_no_one_site_sanity.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 549 components and 2166 component-terminals. [INFO ODB-0133] Created 364 nets and 1068 connections. [WARNING DPL-0037] Use remove_fillers before detailed placement. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 14266.91 um^2, Instances area: 637.60 um^2, Utilization: 4.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 294 @@ -24,7 +26,9 @@ legalized HPWL 7709.4 u delta HPWL 0 % [WARNING DPL-0037] Use remove_fillers before detailed placement. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 14266.91 um^2, Instances area: 637.60 um^2, Utilization: 4.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 294 @@ -44,7 +48,9 @@ legalized HPWL 7709.4 u delta HPWL 0 % [WARNING DPL-0037] Use remove_fillers before detailed placement. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 14266.91 um^2, Instances area: 637.60 um^2, Utilization: 4.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 294 @@ -64,7 +70,9 @@ legalized HPWL 7709.4 u delta HPWL 0 % [WARNING DPL-0037] Use remove_fillers before detailed placement. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 14266.91 um^2, Instances area: 637.60 um^2, Utilization: 4.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 294 @@ -84,7 +92,9 @@ legalized HPWL 7709.4 u delta HPWL 0 % [WARNING DPL-0037] Use remove_fillers before detailed placement. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 14266.91 um^2, Instances area: 637.60 um^2, Utilization: 4.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 294 @@ -104,7 +114,9 @@ legalized HPWL 7709.4 u delta HPWL 0 % [WARNING DPL-0037] Use remove_fillers before detailed placement. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 14266.91 um^2, Instances area: 637.60 um^2, Utilization: 4.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 294 diff --git a/src/dpl/test/hybrid_cells.ok b/src/dpl/test/hybrid_cells.ok index f9ced1fcca5..62209db8d2d 100644 --- a/src/dpl/test/hybrid_cells.ok +++ b/src/dpl/test/hybrid_cells.ok @@ -3,7 +3,9 @@ [INFO ODB-0128] Design: top [INFO ODB-0130] Created 6 pins. [INFO ODB-0131] Created 10 components and 50 component-terminals. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 716992.51 um^2, Instances area: 3.31 um^2, Utilization: 0.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 10 diff --git a/src/dpl/test/hybrid_cells2.ok b/src/dpl/test/hybrid_cells2.ok index eab9ed8558e..2c1647ba784 100644 --- a/src/dpl/test/hybrid_cells2.ok +++ b/src/dpl/test/hybrid_cells2.ok @@ -3,7 +3,9 @@ [INFO ODB-0128] Design: top [INFO ODB-0130] Created 6 pins. [INFO ODB-0131] Created 11 components and 55 component-terminals. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 716992.51 um^2, Instances area: 3.91 um^2, Utilization: 0.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 11 diff --git a/src/dpl/test/ibex.ok b/src/dpl/test/ibex.ok index f516ef3e6b4..c06ee7f7b44 100644 --- a/src/dpl/test/ibex.ok +++ b/src/dpl/test/ibex.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 231 pins. [INFO ODB-0131] Created 34184 components and 173049 component-terminals. [INFO ODB-0133] Created 33171 nets and 104681 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 662017.61 um^2, Instances area: 51034.49 um^2, Utilization: 7.7% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 29301 diff --git a/src/dpl/test/max_disp1.ok b/src/dpl/test/max_disp1.ok index 05deb79a354..58e2562047f 100644 --- a/src/dpl/test/max_disp1.ok +++ b/src/dpl/test/max_disp1.ok @@ -4,7 +4,9 @@ [INFO ODB-0130] Created 65 pins. [INFO ODB-0131] Created 1768 components and 3775 component-terminals. [INFO ODB-0133] Created 130 nets and 195 connections. -[INFO DPL-0005] Max displacement: +/- 1473 sites horizontally, +/- 35 rows vertically. +[INFO DPL-0006] Core area: 396162.58 um^2, Instances area: 504.60 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 1473 sites horizontally, +/- 35 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 65 diff --git a/src/dpl/test/mirror1.ok b/src/dpl/test/mirror1.ok index c1cd8e826d5..357c0fec1f9 100644 --- a/src/dpl/test/mirror1.ok +++ b/src/dpl/test/mirror1.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 54 pins. [INFO ODB-0131] Created 549 components and 2166 component-terminals. [INFO ODB-0133] Created 364 nets and 1068 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 14266.91 um^2, Instances area: 637.60 um^2, Utilization: 4.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 294 diff --git a/src/dpl/test/mirror2.ok b/src/dpl/test/mirror2.ok index 3ab656d9dca..8911c3666fb 100644 --- a/src/dpl/test/mirror2.ok +++ b/src/dpl/test/mirror2.ok @@ -6,7 +6,9 @@ [INFO ODB-0131] Created 2 components and 11 component-terminals. [INFO ODB-0132] Created 2 special nets and 4 connections. [INFO ODB-0133] Created 3 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 4.80 um^2, Utilization: 14.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/multi_height_one_site_gap_disallow.ok b/src/dpl/test/multi_height_one_site_gap_disallow.ok index 324330b362f..4b9a15bb95f 100644 --- a/src/dpl/test/multi_height_one_site_gap_disallow.ok +++ b/src/dpl/test/multi_height_one_site_gap_disallow.ok @@ -5,7 +5,9 @@ [INFO ODB-0131] Created 3 components and 15 component-terminals. [INFO ODB-0133] Created 6 nets and 0 connections. [WARNING DPL-0003] -disallow_one_site_gaps is deprecated -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 54.26 um^2, Instances area: 6.38 um^2, Utilization: 11.8% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 3 diff --git a/src/dpl/test/multi_height_rows.ok b/src/dpl/test/multi_height_rows.ok index fb2e2ca5bdf..93218ec75d0 100644 --- a/src/dpl/test/multi_height_rows.ok +++ b/src/dpl/test/multi_height_rows.ok @@ -3,7 +3,9 @@ [INFO ODB-0128] Design: top [INFO ODB-0130] Created 6 pins. [INFO ODB-0131] Created 5 components and 25 component-terminals. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 54.26 um^2, Instances area: 9.58 um^2, Utilization: 17.6% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 5 diff --git a/src/dpl/test/obstruction1.ok b/src/dpl/test/obstruction1.ok index 180ea32efb0..03a25392089 100644 --- a/src/dpl/test/obstruction1.ok +++ b/src/dpl/test/obstruction1.ok @@ -2,7 +2,9 @@ [INFO ODB-0227] LEF file: obstruction1.lef, created 1 library cells [INFO ODB-0128] Design: aes_cipher_top [INFO ODB-0131] Created 121 components and 621 component-terminals. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 160139.98 um^2, Instances area: 118.10 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 117 diff --git a/src/dpl/test/obstruction2.ok b/src/dpl/test/obstruction2.ok index acf753f2b85..df98ad81d5b 100644 --- a/src/dpl/test/obstruction2.ok +++ b/src/dpl/test/obstruction2.ok @@ -5,24 +5,6 @@ [INFO ODB-0131] Created 32 components and 201 component-terminals. [INFO ODB-0132] Created 2 special nets and 0 connections. [INFO ODB-0133] Created 384 nets and 137 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. -Movements Summary ---------------------------------------- -Total cells: 31 -Diamond Move Success: 31 (100.00%) -Diamond Move Failure: 0 -Rip-up and replace Success: 0 ( 0.00% of diamond failures) -Rip-up and replace Failure: 0 -Total Placement Failures: 0 ---------------------------------------- -Placement Analysis ---------------------------------- -total displacement 73.7 u -average displacement 2.3 u -max displacement 12.4 u -original HPWL 731.0 u -legalized HPWL 737.5 u -delta HPWL 1 % - -[INFO DPL-0001] Placed 257 filler instances. -No differences found. +[INFO DPL-0006] Core area: 1851.36 um^2, Instances area: 3069.11 um^2, Utilization: 165.8% +[ERROR DPL-0038] Utilization greater than 100%, impossible to legalize +DPL-0038 diff --git a/src/dpl/test/obstruction2.py b/src/dpl/test/obstruction2.py index e1523d26a54..cc60af95156 100644 --- a/src/dpl/test/obstruction2.py +++ b/src/dpl/test/obstruction2.py @@ -11,10 +11,7 @@ design = helpers.make_design(tech) design.readDef("obstruction2.def") -dpl_aux.detailed_placement(design) -dpl_aux.filler_placement(design, masters=["FILLCELL.*"]) -design.getOpendp().checkPlacement(False) - -def_file = helpers.make_result_file("obstruction2.def") -design.writeDef(def_file) -helpers.diff_files("obstruction2.defok", def_file) +try: + dpl_aux.detailed_placement(design) +except Exception as inst: + print(inst.args[0]) diff --git a/src/dpl/test/obstruction2.tcl b/src/dpl/test/obstruction2.tcl index d306a15d253..66a16899bc5 100644 --- a/src/dpl/test/obstruction2.tcl +++ b/src/dpl/test/obstruction2.tcl @@ -3,10 +3,5 @@ source "helpers.tcl" read_lef Nangate45/Nangate45.lef read_lef Nangate45/fakeram45_64x7.lef read_def obstruction2.def -detailed_placement -filler_placement FILLCELL* -check_placement - -set def_file [make_result_file obstruction2.def] -write_def $def_file -diff_file obstruction2.defok $def_file +catch { detailed_placement } error +puts $error diff --git a/src/dpl/test/one_site_gap_disallow.ok b/src/dpl/test/one_site_gap_disallow.ok index 0b29420b4c5..e20bdc1b581 100644 --- a/src/dpl/test/one_site_gap_disallow.ok +++ b/src/dpl/test/one_site_gap_disallow.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 4 components and 17 component-terminals. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 3.72 um^2, Utilization: 22.6% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 4 diff --git a/src/dpl/test/pad01.ok b/src/dpl/test/pad01.ok index d53362b859e..97c9b6d1dc9 100644 --- a/src/dpl/test/pad01.ok +++ b/src/dpl/test/pad01.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/pad02.ok b/src/dpl/test/pad02.ok index a450ee5710f..0ad34db506c 100644 --- a/src/dpl/test/pad02.ok +++ b/src/dpl/test/pad02.ok @@ -4,6 +4,8 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. [ERROR DPL-0015] instance _277_ does not fit inside the ROW core area. DPL-0015 diff --git a/src/dpl/test/pad04.ok b/src/dpl/test/pad04.ok index b8691e921d2..0973bc79bcc 100644 --- a/src/dpl/test/pad04.ok +++ b/src/dpl/test/pad04.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 10 components and 45 component-terminals. [INFO ODB-0132] Created 2 special nets and 20 connections. [INFO ODB-0133] Created 11 nets and 25 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 8.51 um^2, Utilization: 25.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 10 diff --git a/src/dpl/test/pad05.ok b/src/dpl/test/pad05.ok index 4aa238b9849..f79facd9107 100644 --- a/src/dpl/test/pad05.ok +++ b/src/dpl/test/pad05.ok @@ -6,7 +6,9 @@ [INFO ODB-0131] Created 2 components and 11 component-terminals. [INFO ODB-0132] Created 2 special nets and 4 connections. [INFO ODB-0133] Created 2 nets and 0 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 4.80 um^2, Utilization: 14.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/pad06.ok b/src/dpl/test/pad06.ok index 4aa238b9849..f79facd9107 100644 --- a/src/dpl/test/pad06.ok +++ b/src/dpl/test/pad06.ok @@ -6,7 +6,9 @@ [INFO ODB-0131] Created 2 components and 11 component-terminals. [INFO ODB-0132] Created 2 special nets and 4 connections. [INFO ODB-0133] Created 2 nets and 0 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 4.80 um^2, Utilization: 14.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/pad07.ok b/src/dpl/test/pad07.ok index d53362b859e..97c9b6d1dc9 100644 --- a/src/dpl/test/pad07.ok +++ b/src/dpl/test/pad07.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/pad08.ok b/src/dpl/test/pad08.ok index d53362b859e..97c9b6d1dc9 100644 --- a/src/dpl/test/pad08.ok +++ b/src/dpl/test/pad08.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/regions1.ok b/src/dpl/test/regions1.ok index 20039bf6096..1bc218c68e4 100644 --- a/src/dpl/test/regions1.ok +++ b/src/dpl/test/regions1.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 5 components and 21 component-terminals. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 2.93 um^2, Utilization: 17.7% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/regions2.ok b/src/dpl/test/regions2.ok index aa04f941b13..321f99b21e5 100644 --- a/src/dpl/test/regions2.ok +++ b/src/dpl/test/regions2.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 4 components and 17 component-terminals. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 2.39 um^2, Utilization: 14.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 0 diff --git a/src/dpl/test/regions3.ok b/src/dpl/test/regions3.ok index 93026b608b9..65922e27dbe 100644 --- a/src/dpl/test/regions3.ok +++ b/src/dpl/test/regions3.ok @@ -2,7 +2,9 @@ [INFO ODB-0227] LEF file: Nangate45/fake_macros.lef, created 10 library cells [INFO ODB-0128] Design: regions3 [INFO ODB-0131] Created 2 components and 10 component-terminals. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 3.19 um^2, Utilization: 19.4% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 0 diff --git a/src/dpl/test/report_failures.ok b/src/dpl/test/report_failures.ok index eb3de4022fb..842dd9a5ed5 100644 --- a/src/dpl/test/report_failures.ok +++ b/src/dpl/test/report_failures.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 18 components and 81 component-terminals. [INFO ODB-0133] Created 11 nets and 25 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 14.36 um^2, Utilization: 87.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 3 @@ -17,6 +19,6 @@ Total Placement Failures: 3 [INFO DPL-0035] f2/_285_ [INFO DPL-0035] f2/_289_ [INFO DPL-0035] f2/_293_ -[ERROR DPL-0036] Detailed placement failed. +[ERROR DPL-0036] Detailed placement failed inside DPL. No differences found. No differences found. diff --git a/src/dpl/test/row_boundary_filter.ok b/src/dpl/test/row_boundary_filter.ok index 94c05ed3ace..583b403cac9 100644 --- a/src/dpl/test/row_boundary_filter.ok +++ b/src/dpl/test/row_boundary_filter.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 2 components and 8 component-terminals. [INFO ODB-0133] Created 2 nets and 3 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 36.71 um^2, Instances area: 0.80 um^2, Utilization: 2.2% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/simple01.ok b/src/dpl/test/simple01.ok index d53362b859e..97c9b6d1dc9 100644 --- a/src/dpl/test/simple01.ok +++ b/src/dpl/test/simple01.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/simple02.ok b/src/dpl/test/simple02.ok index ed54fcf24dd..369e41ac3f1 100644 --- a/src/dpl/test/simple02.ok +++ b/src/dpl/test/simple02.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/simple03.ok b/src/dpl/test/simple03.ok index 013a7adec64..5ef6a386b3a 100644 --- a/src/dpl/test/simple03.ok +++ b/src/dpl/test/simple03.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 1.86 um^2, Utilization: 5.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/simple04.ok b/src/dpl/test/simple04.ok index 8b5f4f75c7d..8485cc0d491 100644 --- a/src/dpl/test/simple04.ok +++ b/src/dpl/test/simple04.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 10 components and 45 component-terminals. [INFO ODB-0132] Created 2 special nets and 20 connections. [INFO ODB-0133] Created 11 nets and 25 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 34.05 um^2, Instances area: 8.51 um^2, Utilization: 25.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 10 diff --git a/src/dpl/test/simple05.ok b/src/dpl/test/simple05.ok index 5c609649955..334b145ef43 100644 --- a/src/dpl/test/simple05.ok +++ b/src/dpl/test/simple05.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 10 components and 45 component-terminals. [INFO ODB-0133] Created 11 nets and 25 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 8.51 um^2, Utilization: 51.6% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 9 diff --git a/src/dpl/test/simple07.ok b/src/dpl/test/simple07.ok index 50b4190596b..baacd0d58a5 100644 --- a/src/dpl/test/simple07.ok +++ b/src/dpl/test/simple07.ok @@ -3,7 +3,9 @@ [INFO ODB-0130] Created 2 pins. [INFO ODB-0131] Created 10 components and 45 component-terminals. [INFO ODB-0133] Created 11 nets and 25 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 8.51 um^2, Utilization: 51.6% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 9 diff --git a/src/dpl/test/simple08.ok b/src/dpl/test/simple08.ok index 73863d69825..9f8f6f5e5c9 100644 --- a/src/dpl/test/simple08.ok +++ b/src/dpl/test/simple08.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 1.86 um^2, Utilization: 11.3% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/simple09.ok b/src/dpl/test/simple09.ok index df8bb6d929f..a2e3d44d0b4 100644 --- a/src/dpl/test/simple09.ok +++ b/src/dpl/test/simple09.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 9576.00 um^2, Instances area: 1.86 um^2, Utilization: 0.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/dpl/test/simple10.ok b/src/dpl/test/simple10.ok index 007df8f7389..2e2c5a712a5 100644 --- a/src/dpl/test/simple10.ok +++ b/src/dpl/test/simple10.ok @@ -4,7 +4,9 @@ [INFO ODB-0131] Created 1 components and 4 component-terminals. [INFO ODB-0132] Created 2 special nets and 2 connections. [INFO ODB-0133] Created 2 nets and 2 connections. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 53.20 um^2, Instances area: 13.03 um^2, Utilization: 24.5% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 1 diff --git a/src/grt/test/repair_antennas_allow_congestion.ok b/src/grt/test/repair_antennas_allow_congestion.ok index d7793c5ece8..ab1d518fdb4 100644 --- a/src/grt/test/repair_antennas_allow_congestion.ok +++ b/src/grt/test/repair_antennas_allow_congestion.ok @@ -11,7 +11,9 @@ [INFO GRT-0012] Found 6 antenna violations. [INFO GRT-0302] Inserted 0 jumpers for 0 nets. [INFO GRT-0012] Found 6 antenna violations. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 78411.11 um^2, Instances area: 6262.53 um^2, Utilization: 8.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 368 diff --git a/src/grt/test/repair_antennas_only_diodes.ok b/src/grt/test/repair_antennas_only_diodes.ok index 5a871a4fa7a..087459e225e 100644 --- a/src/grt/test/repair_antennas_only_diodes.ok +++ b/src/grt/test/repair_antennas_only_diodes.ok @@ -8,7 +8,9 @@ [INFO ANT-0002] Found 8 net violations. [INFO ANT-0001] Found 8 pin violations. [INFO GRT-0012] Found 8 antenna violations. -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 78411.11 um^2, Instances area: 6265.73 um^2, Utilization: 8.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 367 diff --git a/src/odb/test/replace_hier_mod1.ok b/src/odb/test/replace_hier_mod1.ok index 65825e9866e..ec4afb3ab00 100644 --- a/src/odb/test/replace_hier_mod1.ok +++ b/src/odb/test/replace_hier_mod1.ok @@ -48,7 +48,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000007 HPWL: 79932 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000001 HPWL: 80607 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000004 HPWL: 80632 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 60.38 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 21 @@ -232,7 +234,9 @@ Iteration | Overflow | HPWL (um) | HPWL(%) | Penalty | Group [INFO GPL-1008] - For 80% usage of free space: 0.0014 [INFO GPL-1009] - For 50% usage of free space: 0.0023 [INFO GPL-1014] Final placement area: 54.55 (+0.00%) -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 59.85 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 21 @@ -440,7 +444,9 @@ Iteration | Overflow | HPWL (um) | HPWL(%) | Penalty | Group [INFO GPL-1008] - For 80% usage of free space: 0.0014 [INFO GPL-1009] - For 50% usage of free space: 0.0023 [INFO GPL-1014] Final placement area: 55.08 (+0.00%) -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 60.38 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 21 @@ -648,7 +654,9 @@ Iteration | Overflow | HPWL (um) | HPWL(%) | Penalty | Group [INFO GPL-1008] - For 80% usage of free space: 0.0014 [INFO GPL-1009] - For 50% usage of free space: 0.0023 [INFO GPL-1014] Final placement area: 54.55 (+0.00%) -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 59.85 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 21 diff --git a/src/rsz/test/pinswap_flat.ok b/src/rsz/test/pinswap_flat.ok index 602dda243bb..6df620d5062 100644 --- a/src/rsz/test/pinswap_flat.ok +++ b/src/rsz/test/pinswap_flat.ok @@ -47,7 +47,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000000 HPWL: 54697 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000003 HPWL: 54468 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000001 HPWL: 54373 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 6.92 um^2, Utilization: 0.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 4 diff --git a/src/rsz/test/pinswap_hier.ok b/src/rsz/test/pinswap_hier.ok index 68911ba2b9b..4ceff3fef4a 100644 --- a/src/rsz/test/pinswap_hier.ok +++ b/src/rsz/test/pinswap_hier.ok @@ -48,7 +48,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000000 HPWL: 54697 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000003 HPWL: 54468 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000001 HPWL: 54373 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 6.92 um^2, Utilization: 0.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 4 diff --git a/src/rsz/test/remove_buffers6.ok b/src/rsz/test/remove_buffers6.ok index f4ea59ae4eb..84be19dae42 100644 --- a/src/rsz/test/remove_buffers6.ok +++ b/src/rsz/test/remove_buffers6.ok @@ -11,7 +11,9 @@ [INFO IFP-0103] Total instances area: 58.254 um^2 [INFO IFP-0104] Effective utilization: 0.001 [INFO IFP-0105] Number of instances: 17 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 58.25 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 17 diff --git a/src/rsz/test/repair_fanout1_hier.ok b/src/rsz/test/repair_fanout1_hier.ok index ebaf0b259d6..cd26de2f73e 100644 --- a/src/rsz/test/repair_fanout1_hier.ok +++ b/src/rsz/test/repair_fanout1_hier.ok @@ -48,7 +48,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000004 HPWL: 33512 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000006 HPWL: 34116 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000000 HPWL: 34042 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 162.79 um^2, Utilization: 0.3% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 36 diff --git a/src/rsz/test/repair_fanout2_hier.ok b/src/rsz/test/repair_fanout2_hier.ok index 82f57d14252..d0c18414de7 100644 --- a/src/rsz/test/repair_fanout2_hier.ok +++ b/src/rsz/test/repair_fanout2_hier.ok @@ -48,7 +48,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000000 HPWL: 33616 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000007 HPWL: 34236 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000000 HPWL: 34076 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 321.06 um^2, Utilization: 0.7% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 71 diff --git a/src/rsz/test/repair_fanout3_hier.ok b/src/rsz/test/repair_fanout3_hier.ok index f66e98ecdc0..a040f2648cb 100644 --- a/src/rsz/test/repair_fanout3_hier.ok +++ b/src/rsz/test/repair_fanout3_hier.ok @@ -48,7 +48,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000004 HPWL: 31300 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000005 HPWL: 31350 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000004 HPWL: 30416 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 321.06 um^2, Utilization: 0.7% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 71 diff --git a/src/rsz/test/repair_hold10.ok b/src/rsz/test/repair_hold10.ok index 464d4606d2e..35323dd95c7 100644 --- a/src/rsz/test/repair_hold10.ok +++ b/src/rsz/test/repair_hold10.ok @@ -14,7 +14,9 @@ Iteration | Resized | Buffers | Cloned Gates | Area | WNS | TNS | En [INFO RSZ-0032] Inserted 6 hold buffers. Repair timing output passed/skipped equivalence test worst slack min 0.21 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 231206.75 um^2, Instances area: 210.20 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 21 diff --git a/src/rsz/test/repair_setup4_flat.ok b/src/rsz/test/repair_setup4_flat.ok index ca3adb6634c..8080da815b1 100644 --- a/src/rsz/test/repair_setup4_flat.ok +++ b/src/rsz/test/repair_setup4_flat.ok @@ -47,7 +47,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000008 HPWL: 59941 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000009 HPWL: 60406 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000011 HPWL: 60484 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 58.25 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 17 diff --git a/src/rsz/test/repair_setup4_hier.ok b/src/rsz/test/repair_setup4_hier.ok index 37b7abe78a4..6ee7113a58b 100644 --- a/src/rsz/test/repair_setup4_hier.ok +++ b/src/rsz/test/repair_setup4_hier.ok @@ -48,7 +48,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000008 HPWL: 59941 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000009 HPWL: 60406 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000011 HPWL: 60484 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 58.25 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 17 diff --git a/src/rsz/test/repair_setup6.ok b/src/rsz/test/repair_setup6.ok index 2578ad69916..ff62b688b80 100644 --- a/src/rsz/test/repair_setup6.ok +++ b/src/rsz/test/repair_setup6.ok @@ -11,7 +11,9 @@ [INFO IFP-0103] Total instances area: 58.254 um^2 [INFO IFP-0104] Effective utilization: 0.001 [INFO IFP-0105] Number of instances: 17 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 58.25 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 17 diff --git a/src/rsz/test/repair_setup6_multi.ok b/src/rsz/test/repair_setup6_multi.ok index 4c9d38d18aa..5a0d259cec5 100644 --- a/src/rsz/test/repair_setup6_multi.ok +++ b/src/rsz/test/repair_setup6_multi.ok @@ -11,7 +11,9 @@ [INFO IFP-0103] Total instances area: 58.254 um^2 [INFO IFP-0104] Effective utilization: 0.001 [INFO IFP-0105] Number of instances: 17 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 58.25 um^2, Utilization: 0.1% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 17 diff --git a/src/rsz/test/repair_slew16.ok b/src/rsz/test/repair_slew16.ok index 4d6edab6b6b..c63f140cfcd 100644 --- a/src/rsz/test/repair_slew16.ok +++ b/src/rsz/test/repair_slew16.ok @@ -11,7 +11,9 @@ [INFO IFP-0103] Total instances area: 94.962 um^2 [INFO IFP-0104] Effective utilization: 0.012 [INFO IFP-0105] Number of instances: 21 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 7635.80 um^2, Instances area: 94.96 um^2, Utilization: 1.2% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 21 diff --git a/src/rsz/test/repair_wire10.ok b/src/rsz/test/repair_wire10.ok index 2fc5397e162..d76eba1eda8 100644 --- a/src/rsz/test/repair_wire10.ok +++ b/src/rsz/test/repair_wire10.ok @@ -11,7 +11,9 @@ [INFO IFP-0103] Total instances area: 2.394 um^2 [INFO IFP-0104] Effective utilization: 0.000 [INFO IFP-0105] Number of instances: 3 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 417456.14 um^2, Instances area: 2.39 um^2, Utilization: 0.0% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 3 diff --git a/src/rsz/test/split_load_hier.ok b/src/rsz/test/split_load_hier.ok index 5d3e9c7bf1c..7be24a686bc 100644 --- a/src/rsz/test/split_load_hier.ok +++ b/src/rsz/test/split_load_hier.ok @@ -48,7 +48,9 @@ Using 2 tracks default min distance between IO pins. [InitialPlace] Iter: 3 conjugate gradient residual: 0.00000010 HPWL: 203741 [InitialPlace] Iter: 4 conjugate gradient residual: 0.00000010 HPWL: 204306 [InitialPlace] Iter: 5 conjugate gradient residual: 0.00000010 HPWL: 204308 -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 47872.02 um^2, Instances area: 138.05 um^2, Utilization: 0.3% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 47 diff --git a/test/commands_without_load.ok b/test/commands_without_load.ok new file mode 100644 index 00000000000..29c1117a02e --- /dev/null +++ b/test/commands_without_load.ok @@ -0,0 +1,190 @@ +TEST: set_logic_zero +[ERROR STA-1570] No network has been linked. +TEST: write_spef +[ERROR STA-0565] write_spef requires one positional argument. +[ERROR RCX-0497] No design is loaded. +[ERROR STA-0565] write_spef requires one positional argument. +[ERROR STA-0565] write_spef requires one positional argument. +TEST: set_max_dynamic_power +TEST: set_max_time_borrow +[ERROR STA-0572] borrow_limit '/workspace/9ORFS/tools/OpenROAD/test/results/commands_without_load-tcl' is not a positive float. +TEST: draw_route_segments +[ERROR STA-0565] draw_route_segments requires one positional argument. +[ERROR GRT-0223] Missing dbBlock. +[ERROR STA-0565] draw_route_segments requires one positional argument. +[ERROR STA-0565] draw_route_segments requires one positional argument. +TEST: balance_row_usage +[ERROR STA-0564] balance_row_usage positional arguments not supported. +[ERROR STA-0564] balance_row_usage positional arguments not supported. +[ERROR STA-0564] balance_row_usage positional arguments not supported. +TEST: subst +TEST: set_ndr_rules +TEST: generate_ram +[ERROR STA-0564] generate_ram positional arguments not supported. +[ERROR STA-0564] generate_ram positional arguments not supported. +[ERROR STA-0564] generate_ram positional arguments not supported. +TEST: read_def +[ERROR STA-0565] read_def requires one positional argument. +[ERROR ORD-0003] /workspace/9ORFS/tools/OpenROAD/test/results/commands_without_load-tcl does not exist. +[ERROR STA-0565] read_def requires one positional argument. +[ERROR STA-0565] read_def requires one positional argument. +TEST: pwd +TEST: write_abstract_lef +[ERROR STA-0565] write_abstract_lef requires one positional argument. +[ERROR ORD-0053] No block is loaded. +[ERROR STA-0565] write_abstract_lef requires one positional argument. +[ERROR STA-0565] write_abstract_lef requires one positional argument. +TEST: read_saif +[ERROR STA-0565] read_saif requires one positional argument. +[ERROR STA-1571] No network has been linked. +[ERROR STA-0565] read_saif requires one positional argument. +[ERROR STA-0565] read_saif requires one positional argument. +TEST: set_dft_config +[ERROR STA-0564] set_dft_config positional arguments not supported. +[ERROR STA-0564] set_dft_config positional arguments not supported. +[ERROR STA-0564] set_dft_config positional arguments not supported. +TEST: adjust_rc +[ERROR RCX-0004] Design not loaded. +[ERROR RCX-0004] Design not loaded. +[ERROR RCX-0004] Design not loaded. +[ERROR RCX-0004] Design not loaded. +TEST: report_path +[ERROR STA-0567] report_path requires two positional arguments. +[ERROR STA-0567] report_path requires two positional arguments. +[ERROR STA-0567] report_path requires two positional arguments. +TEST: report_timing_histogram +[ERROR STA-1570] No network has been linked. +[ERROR STA-0564] report_timing_histogram positional arguments not supported. +[ERROR STA-0564] report_timing_histogram positional arguments not supported. +[ERROR STA-0564] report_timing_histogram positional arguments not supported. +TEST: example_instance +[INFO EXA-0001] Making an example instance named example +[ERROR EXA-0002] No chip exists. +[ERROR STA-0564] example_instance positional arguments not supported. +[ERROR STA-0564] example_instance positional arguments not supported. +[ERROR STA-0564] example_instance positional arguments not supported. +TEST: unknown +TEST: set_sense +TEST: lrange +TEST: read_partitioning +[ERROR PAR-0051] Missing mandatory argument -read_file +[ERROR PAR-0051] Missing mandatory argument -read_file +[ERROR PAR-0051] Missing mandatory argument -read_file +[ERROR PAR-0051] Missing mandatory argument -read_file +TEST: auto_import +TEST: case +TEST: analyze_power_grid +[ERROR PSM-0058] Argument -net not specified. +[ERROR PSM-0058] Argument -net not specified. +[ERROR PSM-0058] Argument -net not specified. +[ERROR PSM-0058] Argument -net not specified. +TEST: cluster_flops +[ERROR GPL-0113] No design block found. +[ERROR GPL-0113] No design block found. +[ERROR GPL-0113] No design block found. +[ERROR GPL-0113] No design block found. +TEST: break +TEST: set_macro_guidance_region +[ERROR MPL-0043] -macro_name is required. +[ERROR STA-0564] set_macro_guidance_region positional arguments not supported. +[ERROR STA-0564] set_macro_guidance_region positional arguments not supported. +[ERROR STA-0564] set_macro_guidance_region positional arguments not supported. +TEST: auto_execok +TEST: make_rows +[ERROR IFP-0035] use -site to add placement rows. +[ERROR IFP-0035] use -site to add placement rows. +[ERROR IFP-0035] use -site to add placement rows. +[ERROR IFP-0035] use -site to add placement rows. +TEST: user_run_time +TEST: linsert +TEST: create_toolbar_button +[ERROR GUI-0020] The -text argument must be specified. +[ERROR GUI-0020] The -text argument must be specified. +[ERROR GUI-0020] The -text argument must be specified. +[ERROR GUI-0020] The -text argument must be specified. +TEST: make_result_dir +TEST: set_multicycle_path +[ERROR STA-0444] missing path multiplier argument. +[ERROR STA-0573] path multiplier '/workspace/9ORFS/tools/OpenROAD/test/results/commands_without_load-tcl' is not an integer. +[WARNING STA-0445] '/workspace/9ORFS/tools/OpenROAD/test/results/commands_without_load-tcl /workspace/9ORFS/tools/OpenROAD/test/results/commands_without_load-tcl' ignored. +[WARNING STA-0445] '/workspace/9ORFS/tools/OpenROAD/test/results/commands_without_load-tcl /workspace/9ORFS/tools/OpenROAD/test/results/commands_without_load-tcl /workspace/9ORFS/tools/OpenROAD/test/results/commands_without_load-tcl' ignored. +TEST: set_logic_one +[ERROR STA-1570] No network has been linked. +TEST: report_design_area_metrics +TEST: catch +TEST: delete_voltage_domain +[ERROR STA-0565] delete_voltage_domain requires one positional argument. +[ERROR ODB-0323] please load the design before trying to use this command +[ERROR STA-0565] delete_voltage_domain requires one positional argument. +[ERROR STA-0565] delete_voltage_domain requires one positional argument. +TEST: unset_clock_transition +[ERROR STA-0565] unset_clock_transition requires one positional argument. +[WARNING STA-0351] clock '/workspace/9ORFS/tools/OpenROAD/test/results/commands_without_load-tcl' not found. +[ERROR STA-0565] unset_clock_transition requires one positional argument. +[ERROR STA-0565] unset_clock_transition requires one positional argument. +TEST: set_nets_to_route +[ERROR STA-0565] set_nets_to_route requires one positional argument. +[ERROR GRT-0252] Missing dbBlock. +[ERROR STA-0565] set_nets_to_route requires one positional argument. +[ERROR STA-0565] set_nets_to_route requires one positional argument. +TEST: write_verilog_for_eqy +[ERROR STA-1570] No network has been linked. +TEST: check_placement +[ERROR DPL-0103] No design block found. +[ERROR DPL-0103] No design block found. +[ERROR DPL-0103] No design block found. +[ERROR DPL-0103] No design block found. +TEST: set_logic_dc +[ERROR STA-1570] No network has been linked. +TEST: get_modes +TEST: if +TEST: all_registers +[ERROR STA-1571] No network has been linked. +[ERROR STA-0564] all_registers positional arguments not supported. +[ERROR STA-0564] all_registers positional arguments not supported. +[ERROR STA-0564] all_registers positional arguments not supported. +TEST: join +TEST: define_pdn_grid +[ERROR PDN-1022] Design must be loaded before calling define_pdn_grid. +[ERROR STA-0564] define_pdn_grid positional arguments not supported. +[ERROR STA-0564] define_pdn_grid positional arguments not supported. +[ERROR STA-0564] define_pdn_grid positional arguments not supported. +TEST: get_cells +[ERROR STA-1570] No network has been linked. +[ERROR STA-1570] No network has been linked. +[ERROR STA-0566] get_cells requires zero or one positional arguments. +[ERROR STA-0566] get_cells requires zero or one positional arguments. +TEST: write_timing_model +[ERROR STA-0565] write_timing_model requires one positional argument. +[ERROR STA-1570] No network has been linked. +[ERROR STA-0565] write_timing_model requires one positional argument. +[ERROR STA-0565] write_timing_model requires one positional argument. +TEST: get_fanin +[ERROR STA-0161] Usage: get_fanin -to sink_list [-flat] [-only_cells] [-startpoints_only] [-levels level_count] [-pin_levels pin_count] [-trace_arcs timing|enabled|all] +[ERROR STA-0161] Usage: get_fanin -to sink_list [-flat] [-only_cells] [-startpoints_only] [-levels level_count] [-pin_levels pin_count] [-trace_arcs timing|enabled|all] +[ERROR STA-0161] Usage: get_fanin -to sink_list [-flat] [-only_cells] [-startpoints_only] [-levels level_count] [-pin_levels pin_count] [-trace_arcs timing|enabled|all] +[ERROR STA-0161] Usage: get_fanin -to sink_list [-flat] [-only_cells] [-startpoints_only] [-levels level_count] [-pin_levels pin_count] [-trace_arcs timing|enabled|all] +TEST: report_dont_use +[ERROR STA-0564] report_dont_use positional arguments not supported. +[ERROR STA-0564] report_dont_use positional arguments not supported. +[ERROR STA-0564] report_dont_use positional arguments not supported. +TEST: negotiation_legalize +Signal 11 received +Stack trace: + 0# 0x0000000000D7F906 in /workspace/9ORFS/tools/OpenROAD/build/bin/openroad + 1# 0x0000000000045330 in /lib/x86_64-linux-gnu/libc.so.6 + 2# odb::dbChip::getBlock() in /workspace/9ORFS/tools/OpenROAD/build/bin/openroad + 3# dpl::Opendp::importDb() in /workspace/9ORFS/tools/OpenROAD/build/bin/openroad + 4# dpl::Opendp::negotiationLegalize(bool) in /workspace/9ORFS/tools/OpenROAD/build/bin/openroad + 5# 0x0000000000E4DF40 in /workspace/9ORFS/tools/OpenROAD/build/bin/openroad + 6# TclNRRunCallbacks in /lib/x86_64-linux-gnu/libtcl8.6.so + 7# 0x000000000003F6BC in /lib/x86_64-linux-gnu/libtcl8.6.so + 8# Tcl_EvalEx in /lib/x86_64-linux-gnu/libtcl8.6.so + 9# Tcl_Eval in /lib/x86_64-linux-gnu/libtcl8.6.so +10# sta::sourceTclFile(char const*, bool, bool, Tcl_Interp*) in /workspace/9ORFS/tools/OpenROAD/build/bin/openroad +11# 0x0000000003567A31 in /workspace/9ORFS/tools/OpenROAD/build/bin/openroad +12# Tcl_MainEx in /lib/x86_64-linux-gnu/libtcl8.6.so +13# main in /workspace/9ORFS/tools/OpenROAD/build/bin/openroad +14# 0x000000000002A1CA in /lib/x86_64-linux-gnu/libc.so.6 +15# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6 +16# _start in /workspace/9ORFS/tools/OpenROAD/build/bin/openroad diff --git a/test/upf_aes.ok b/test/upf_aes.ok index c33edfb11d2..03f3f3ad119 100644 --- a/test/upf_aes.ok +++ b/test/upf_aes.ok @@ -1123,7 +1123,9 @@ Divergence occured in 2 regions. [INFO GPL-1012] Total routability artificial inflation: 6798.17 (+1.62%) [INFO GPL-1013] Total timing-driven delta area: -27509.56 (-6.55%) [INFO GPL-1014] Final placement area: 399199.60 (-4.93%) -[INFO DPL-0005] Max displacement: +/- 1413 sites horizontally, +/- 238 rows vertically. +[INFO DPL-0006] Core area: 878902.94 um^2, Instances area: 341319.85 um^2, Utilization: 38.8% +[INFO DPL-0005] Diamond search max displacement: +/- 1413 sites horizontally, +/- 238 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 16901 diff --git a/test/upf_test.ok b/test/upf_test.ok index 5bd141c6884..319520f9a66 100644 --- a/test/upf_test.ok +++ b/test/upf_test.ok @@ -144,7 +144,9 @@ Iteration | Overflow | HPWL (um) | HPWL(%) | Penalty | Group [INFO GPL-1008] - For 80% usage of free space: 0.0664 [INFO GPL-1009] - For 50% usage of free space: 0.1063 [INFO GPL-1014] Final placement area: 175.05 (+0.00%) -[INFO DPL-0005] Max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-0006] Core area: 11467.25 um^2, Instances area: 158.90 um^2, Utilization: 1.4% +[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically. +[INFO DPL-1101] Legalizing using diamond search. Movements Summary --------------------------------------- Total cells: 13