Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
37bf65b
grt/cugr: model via demand from real via enclosure geometry
eder-matheus Jul 2, 2026
836430a
grt/cugr: update CUGR test goldens for geometry-based via demand
eder-matheus Jul 2, 2026
512a2b6
grt/cugr: add via_geometry_cugr regression test
eder-matheus Jul 2, 2026
87eba10
grt/cugr: fall back to drt-style via selection when no default via
eder-matheus Jul 2, 2026
48cf181
grt/cugr: harden via-demand spacing fallback, warn on missing via, dr…
eder-matheus Jul 2, 2026
d5fd3d3
grt/cugr: rank candidate vias by priority instead of arbitrary db-ord…
eder-matheus Jul 3, 2026
ba01782
grt/cugr: add via_priority_cugr test for db-order-independent via ran…
eder-matheus Jul 3, 2026
1d75d37
grt/cugr: union all via boxes per layer for the demand footprint
eder-matheus Jul 3, 2026
c8ec166
grt/cugr: add via_multirect_cugr test for compound-via footprint union
eder-matheus Jul 3, 2026
6ac1f5e
grt/cugr: include Layers.h directly for MetalLayer (include-cleaner)
eder-matheus Jul 3, 2026
3209d3f
grt/cugr: ceil perpendicular track blockage in via demand
eder-matheus Jul 3, 2026
63bd0c5
grt/cugr: update CUGR goldens for integer via track blockage
eder-matheus Jul 3, 2026
19820be
grt/cugr: prefer single-cut vias before LEF default in via ranking
eder-matheus Jul 4, 2026
abdeb88
grt/cugr: extend via_priority test to cover single-cut over default m…
eder-matheus Jul 4, 2026
835ac63
grt/cugr: check written guides in via geometry tests
eder-matheus Jul 6, 2026
58b735b
grt/cugr: tidy via-demand comments and fix stale wording
eder-matheus Jul 6, 2026
352c666
Merge branch 'master' of https://github.com/The-OpenROAD-Project/Open…
eder-matheus Jul 6, 2026
b18ebbc
Merge branch 'master' of https://github.com/The-OpenROAD-Project/Open…
eder-matheus Jul 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions src/grt/src/cugr/src/Design.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
#include "Design.h"

#include <cmath>
#include <cstdint>
#include <iostream>
#include <set>
#include <tuple>
#include <utility>
#include <vector>

#include "CUGR.h"
#include "GeoTypes.h"
#include "Layers.h"
#include "Netlist.h"
#include "db_sta/dbSta.hh"
#include "odb/PtrSetMap.h"
Expand Down Expand Up @@ -57,6 +60,8 @@ void Design::read()

computeGrid();

computeViaDemandLengths();

if (verbose_) {
logger_->report("Design statistics");
logger_->report("Nets: {}", nets_.size());
Expand Down Expand Up @@ -347,6 +352,135 @@ void Design::setUnitCosts()
}
}

odb::dbTechVia* Design::chooseViaForPair(odb::dbTechLayer* lower_tl,
odb::dbTechLayer* upper_tl) const
{
// Rank vias connecting the pair by a drt-like priority: OR_DEFAULT, then
// fewest cuts, then LEF-default, then smallest enclosure.
odb::dbTechLayer* cut_tl = lower_tl->getUpperLayer();
odb::dbTechVia* best = nullptr;
std::tuple<bool, int, bool, int64_t> best_key;
for (odb::dbTechVia* via : tech_->getVias()) {
if (via->getBottomLayer() != lower_tl || via->getTopLayer() != upper_tl) {
continue;
}
int cuts = 0;
int64_t enc_area = 0;
for (odb::dbBox* box : via->getBoxes()) {
odb::dbTechLayer* bl = box->getTechLayer();
if (bl == cut_tl) {
cuts++;
} else if (bl == lower_tl || bl == upper_tl) {
enc_area += box->getBox().area();
}
}
const bool or_default
= odb::dbStringProperty::find(via, "OR_DEFAULT") != nullptr;
const std::tuple<bool, int, bool, int64_t> key{
!or_default, cuts, !via->isDefault(), enc_area};
if (best == nullptr || key < best_key) {
best = via;
best_key = key;
}
}
return best;
}

void Design::computeViaDemandLengths()
{
const int num_layers = getNumLayers();
// Fallback proxy (min-area stub x via_multiplier) for pairs with no via.
via_demand_length_lower_.assign(num_layers, 0.0);
via_demand_length_upper_.assign(num_layers, 0.0);

const bool debug = logger_->debugCheck(utl::GRT, "via_geom", 1);
int fallback_pairs = 0;
for (int i = 0; i + 1 < num_layers; i++) {
const MetalLayer& lower = layers_[i];
const MetalLayer& upper = layers_[i + 1];
odb::dbTechLayer* lower_tl = lower.getTechLayer();
odb::dbTechLayer* upper_tl = upper.getTechLayer();
odb::dbTechVia* via = chooseViaForPair(lower_tl, upper_tl);
if (via == nullptr) {
fallback_pairs++;
}

double num_lower = lower.getMinLength() * constants_.via_multiplier;
double num_upper = upper.getMinLength() * constants_.via_multiplier;
// Union the boxes on each layer; a via may have several rects per layer.
odb::Rect lo_box, up_box;
lo_box.mergeInit();
up_box.mergeInit();
if (via != nullptr) {
for (odb::dbBox* box : via->getBoxes()) {
if (box->getTechLayer() == lower_tl) {
lo_box.merge(box->getBox());
} else if (box->getTechLayer() == upper_tl) {
up_box.merge(box->getBox());
}
}
if (!lo_box.isInverted() && lo_box.dx() > 0 && lo_box.dy() > 0) {
num_lower = viaDemandLength(lower, lo_box.dx(), lo_box.dy());
}
if (!up_box.isInverted() && up_box.dx() > 0 && up_box.dy() > 0) {
num_upper = viaDemandLength(upper, up_box.dx(), up_box.dy());
}
}
via_demand_length_lower_[i] = num_lower;
via_demand_length_upper_[i] = num_upper;

if (debug) {
// Report enclosures, lengths, and per-track demand for each pair.
const int gcell = default_gridline_spacing_;
const std::string via_src
= via != nullptr ? via->getName() : std::string("min_area-fallback");
debugPrint(
logger_,
utl::GRT,
"via_geom",
1,
"via {}->{} [{}]: encl lower={}x{} upper={}x{} -> len "
"lower={:.1f} upper={:.1f} -> demand lower={:.4f} upper={:.4f}",
lower.getName(),
upper.getName(),
via_src,
lo_box.isInverted() ? 0 : lo_box.dx(),
lo_box.isInverted() ? 0 : lo_box.dy(),
up_box.isInverted() ? 0 : up_box.dx(),
up_box.isInverted() ? 0 : up_box.dy(),
num_lower,
num_upper,
gcell > 0 ? num_lower / gcell : 0.0,
gcell > 0 ? num_upper / gcell : 0.0);
}
}

if (fallback_pairs > 0) {
logger_->warn(utl::GRT,
173,
"{} layer pair(s) have no via; using min-area via demand.",
fallback_pairs);
}
}

double Design::viaDemandLength(const MetalLayer& layer,
const int dx,
const int dy) const
{
const int pitch = layer.getPitch();
// getSpacing() is 0 on parallel-table-only techs; use default spacing then.
const int spacing
= layer.getSpacing() > 0 ? layer.getSpacing() : layer.getDefaultSpacing();
// Split the pad into extent along the routing direction and across tracks.
const int along = (layer.getDirection() == MetalLayer::H) ? dx : dy;
const int perp = (layer.getDirection() == MetalLayer::H) ? dy : dx;
// A via blocks whole tracks; ceil the keep-out to an integer track count.
const double tracks_blocked
= pitch > 0 ? std::ceil(static_cast<double>(perp + 2 * spacing) / pitch)
: 1.0;
return along * tracks_blocked;
}

void Design::getAllObstacles(std::vector<std::vector<BoxT>>& all_obstacles,
const bool skip_m1) const
{
Expand Down
21 changes: 21 additions & 0 deletions src/grt/src/cugr/src/Design.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class dbDatabase;
class dbITerm;
class dbNet;
class dbTech;
class dbTechLayer;
class dbTechVia;
} // namespace odb

namespace sta {
Expand Down Expand Up @@ -56,6 +58,15 @@ class Design
{
return layers_[layer_index];
}
// Effective via demand length charged to the lower / upper layer of via i.
double getViaDemandLengthLower(int i) const
{
return via_demand_length_lower_[i];
}
double getViaDemandLengthUpper(int i) const
{
return via_demand_length_upper_[i];
}

// For global routing
const std::vector<std::vector<int>>& getGridlines() const
Expand Down Expand Up @@ -85,6 +96,13 @@ class Design
void readDesignObstructions();
void computeGrid();
void setUnitCosts();
// Fill via_demand_length_{lower,upper}_ from each pair's via geometry.
void computeViaDemandLengths();
// Pick the via for a layer pair, ranked to approximate drt's choice.
odb::dbTechVia* chooseViaForPair(odb::dbTechLayer* lower_tl,
odb::dbTechLayer* upper_tl) const;
// Via pad demand length: extent along routing dir x tracks blocked across.
double viaDemandLength(const MetalLayer& layer, int dx, int dy) const;

// debug functions
void printNets() const;
Expand All @@ -93,6 +111,9 @@ class Design
int lib_dbu_;
BoxT die_region_;
std::vector<MetalLayer> layers_;
// Effective via demand length per lower layer i (lower_ = i, upper_ = i+1).
std::vector<double> via_demand_length_lower_;
std::vector<double> via_demand_length_upper_;
std::vector<CUGRNet> nets_;
std::unordered_map<odb::dbNet*, int> db_net_to_id_;
std::vector<BoxOnLayer> obstacles_;
Expand Down
23 changes: 15 additions & 8 deletions src/grt/src/cugr/src/GridGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,10 @@ GridGraph::GridGraph(const Design* design,

layer_names_.resize(num_layers_);
layer_directions_.resize(num_layers_);
layer_min_lengths_.resize(num_layers_);
for (int layer_index = 0; layer_index < num_layers_; layer_index++) {
const auto& layer = design->getLayer(layer_index);
layer_names_[layer_index] = layer.getName();
layer_directions_[layer_index] = layer.getDirection();
layer_min_lengths_[layer_index] = layer.getMinLength();
// First non-zero sheet/via resistance is the res-aware cost reference.
if (ref_resistance_ <= 0.0 && layer.getResistance() > 0.0) {
ref_resistance_ = layer.getResistance();
Expand Down Expand Up @@ -295,6 +293,17 @@ GridGraph::GridGraph(const Design* design,
}
}

CapacityT GridGraph::viaDemand(const int layer_index,
const int l,
const int edge_sum) const
{
// Spread the layer's precomputed via demand length over its two edges.
const double via_num = (l == layer_index)
? design_->getViaDemandLengthLower(layer_index)
: design_->getViaDemandLengthUpper(layer_index);
return edge_sum > 0 ? (CapacityT) via_num / edge_sum : (CapacityT) 0;
}

void GridGraph::computeCongestionInformation()
{
if (!congestion_info_dirty_) {
Expand Down Expand Up @@ -508,9 +517,8 @@ CostT GridGraph::getViaCost(const int layer_index,

// Prevent division by zero
if (lower_edge_length > 0 || higher_edge_length > 0) {
const CapacityT demand = (CapacityT) layer_min_lengths_[l]
/ (lower_edge_length + higher_edge_length)
* constants_.via_multiplier;
const CapacityT demand
= viaDemand(layer_index, l, lower_edge_length + higher_edge_length);
const double layer_factor
= std::cmp_less(l, net_costs.size()) ? net_costs[l] : 1.0;
if (lower_edge_length > 0) {
Expand Down Expand Up @@ -870,9 +878,8 @@ void GridGraph::commitVia(const int layer_index,

// Prevent division by zero
if (lower_edge_length > 0 || higher_edge_length > 0) {
const CapacityT demand = (CapacityT) layer_min_lengths_[l]
/ (lower_edge_length + higher_edge_length)
* constants_.via_multiplier;
const CapacityT demand
= viaDemand(layer_index, l, lower_edge_length + higher_edge_length);
// Use the per-layer NDR factor for `l`, not a net-wide value.
const double layer_factor
= std::cmp_less(l, net_costs.size()) ? net_costs[l] : 1.0;
Expand Down
3 changes: 2 additions & 1 deletion src/grt/src/cugr/src/GridGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,13 +354,14 @@ class GridGraph
void commitTree(const std::shared_ptr<GRTreeNode>& tree,
bool rip_up = false,
const std::vector<double>& net_costs = {});
// Per-via demand on layer `l` of via `layer_index`, spread over `edge_sum`.
CapacityT viaDemand(int layer_index, int l, int edge_sum) const;

utl::Logger* logger_;
const std::vector<std::vector<int>> gridlines_;
std::vector<std::vector<int>> grid_centers_;
std::vector<std::string> layer_names_;
std::vector<int> layer_directions_;
std::vector<int> layer_min_lengths_;

const int lib_dbu_;
const int m2_pitch_;
Expand Down
2 changes: 2 additions & 0 deletions src/grt/src/cugr/src/Layers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ namespace grt {
MetalLayer::MetalLayer(odb::dbTechLayer* tech_layer,
odb::dbTrackGrid* track_grid)
{
tech_layer_ = tech_layer;
name_ = tech_layer->getName();
index_ = tech_layer->getRoutingLevel() - 1;
direction_
= tech_layer->getDirection() == odb::dbTechLayerDir::HORIZONTAL ? H : V;
width_ = tech_layer->getWidth();
min_width_ = tech_layer->getMinWidth();
spacing_ = tech_layer->getSpacing();

// Sheet R and the via-cut R above (for the res-aware cost); 0 when the
// tech leaves them undefined.
Expand Down
5 changes: 5 additions & 0 deletions src/grt/src/cugr/src/Layers.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ class MetalLayer
int getDirection() const { return direction_; }
int getWidth() const { return width_; }
int getPitch() const { return pitch_; }
// Min spacing to a neighbour on this layer; used for the via-demand model.
int getSpacing() const { return spacing_; }
odb::dbTechLayer* getTechLayer() const { return tech_layer_; }
// Sheet resistance (ohms/square) of this routing layer.
double getResistance() const { return resistance_; }
// Per-cut resistance (ohms) of the via layer just above this routing
Expand All @@ -39,11 +42,13 @@ class MetalLayer
void setAdjustment(float adjustment) { adjustment_ = adjustment; }

private:
odb::dbTechLayer* tech_layer_ = nullptr;
std::string name_;
int index_;
int direction_;
int width_;
int min_width_;
int spacing_ = 0;
double resistance_ = 0.0;
double via_resistance_ = 0.0;

Expand Down
3 changes: 3 additions & 0 deletions src/grt/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ TESTS = [
"tracks3",
"unplaced_inst",
"upper_layer_net",
"via_geometry_cugr",
"via_multirect_cugr",
"via_priority_cugr",
"write_segments1",
"write_segments2",
]
Expand Down
3 changes: 3 additions & 0 deletions src/grt/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ or_integration_tests(
tracks3
unplaced_inst
upper_layer_net
via_geometry_cugr
via_multirect_cugr
via_priority_cugr
write_segments1
write_segments2
PASSFAIL_TESTS
Expand Down
8 changes: 4 additions & 4 deletions src/grt/test/clock_route_cugr.ok
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ Bottleneck: (5, 0, 0)
Layer Resource Demand Usage (%) Max H / Max V / Total Congestion
---------------------------------------------------------------------------------------
li1 0 0 0.00% 0 / 0 / 0
met1 27555 74 0.27% 0 / 0 / 0
met1 27555 68 0.25% 0 / 0 / 0
met2 21571 63 0.29% 0 / 0 / 0
met3 14023 25 0.18% 0 / 0 / 0
met4 10804 13 0.12% 0 / 0 / 0
met3 14023 24 0.17% 0 / 0 / 0
met4 10804 12 0.11% 0 / 0 / 0
met5 3108 0 0.00% 0 / 0 / 0
---------------------------------------------------------------------------------------
Total 77061 175 0.23% 0 / 0 / 0
Total 77061 167 0.22% 0 / 0 / 0

[INFO GRT-0018] Total wirelength: 1641 um
[INFO GRT-0014] Routed nets: 15
Expand Down
Loading
Loading