From 257f72fbc80b05619d3607dd60ba113484e4943f Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Thu, 16 Jul 2026 15:48:17 -0300 Subject: [PATCH 01/17] est: key layer RC table by tech layer instead of layer number Signed-off-by: Eder Monteiro --- src/est/include/est/EstimateParasitics.h | 9 +++-- src/est/src/EstimateParasitics.cpp | 48 ++++++++++++------------ 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/est/include/est/EstimateParasitics.h b/src/est/include/est/EstimateParasitics.h index 997a1b2748..cf50113c52 100644 --- a/src/est/include/est/EstimateParasitics.h +++ b/src/est/include/est/EstimateParasitics.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -260,9 +261,11 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService std::vector signal_layers_; std::vector clk_layers_; - // Layer RC per wire length indexed by layer->getNumber(), corner->index - std::vector> layer_res_; // ohms/meter - std::vector> layer_cap_; // Farads/meter + // Layer RC per wire length keyed by layer, indexed by corner->index() + std::unordered_map> + layer_res_; // ohms/meter + std::unordered_map> + layer_cap_; // Farads/meter // Signal wire RC indexed by corner->index std::vector wire_signal_res_; // ohms/metre std::vector wire_signal_cap_; // Farads/meter diff --git a/src/est/src/EstimateParasitics.cpp b/src/est/src/EstimateParasitics.cpp index 06dbb3ae73..caf6c9c3d9 100644 --- a/src/est/src/EstimateParasitics.cpp +++ b/src/est/src/EstimateParasitics.cpp @@ -115,19 +115,13 @@ void EstimateParasitics::setLayerRC(odb::dbTechLayer* layer, double res, double cap) { - if (layer_res_.empty()) { - int layer_count = layer->getTech()->getLayerCount(); - int corner_count = sta_->scenes().size(); - layer_res_.resize(layer_count); - layer_cap_.resize(layer_count); - for (int i = 0; i < layer_count; i++) { - layer_res_[i].resize(corner_count); - layer_cap_[i].resize(corner_count); - } - } - - layer_res_[layer->getNumber()][corner->index()] = res; - layer_cap_[layer->getNumber()][corner->index()] = cap; + const size_t corner_count = sta_->scenes().size(); + std::vector& layer_res = layer_res_[layer]; + std::vector& layer_cap = layer_cap_[layer]; + layer_res.resize(corner_count, 0.0); + layer_cap.resize(corner_count, 0.0); + layer_res[corner->index()] = res; + layer_cap[corner->index()] = cap; } void EstimateParasitics::layerRC(odb::dbTechLayer* layer, @@ -136,13 +130,13 @@ void EstimateParasitics::layerRC(odb::dbTechLayer* layer, double& res, double& cap) const { - if (layer_res_.empty()) { + const auto res_it = layer_res_.find(layer); + if (res_it == layer_res_.end()) { res = 0.0; cap = 0.0; } else { - const int layer_level = layer->getNumber(); - res = layer_res_[layer_level][corner->index()]; - cap = layer_cap_[layer_level][corner->index()]; + res = res_it->second[corner->index()]; + cap = layer_cap_.at(layer)[corner->index()]; } } @@ -957,8 +951,9 @@ double EstimateParasitics::computeAverageCutResistance(sta::Scene* scene) layer_idx++) { odb::dbTechLayer* layer = tech->findLayer(layer_idx); if (layer && layer->getType() == odb::dbTechLayerType::CUT) { - const float resistance = layer_res_[layer_idx][scene->index()]; - total_resistance += resistance; + double res, cap; + layerRC(layer, scene, res, cap); + total_resistance += res; count++; } } @@ -1029,6 +1024,7 @@ void EstimateParasitics::insertViaResistances(odb::dbTechLayer* pin_layer, { sta::ParasiticNode* prev_node = nullptr; + odb::dbTech* tech = pin_layer->getTech(); const int pin_layer_idx = pin_layer->getNumber(); const int tree_layer_idx = tree_layer->getNumber(); if (std::abs(pin_layer_idx - tree_layer->getNumber()) == 2) { @@ -1036,8 +1032,12 @@ void EstimateParasitics::insertViaResistances(odb::dbTechLayer* pin_layer, const int cut_layer_idx = pin_layer_idx < tree_layer_idx ? pin_layer_idx + 1 : pin_layer_idx - 1; - const double cut_res - = std::max(layer_res_[cut_layer_idx][corner->index()], 1.0e-3); + double res = 0.0; + double cap = 0.0; + if (odb::dbTechLayer* cut_layer = tech->findLayer(cut_layer_idx)) { + layerRC(cut_layer, corner, res, cap); + } + const double cut_res = std::max(res, 1.0e-3); parasitics->makeResistor(parasitic, resistor_id++, cut_res, pin_node, node); } else if (pin_layer_idx == tree_layer_idx) { // Add a small resistor between the pin node and tree node to keep @@ -1047,15 +1047,15 @@ void EstimateParasitics::insertViaResistances(odb::dbTechLayer* pin_layer, const auto [start_idx, end_idx] = std::minmax(pin_layer_idx, tree_layer_idx); const bool pin_is_below = (pin_layer_idx < tree_layer_idx); - odb::dbTech* tech = pin_layer->getTech(); for (int layer_idx = start_idx; layer_idx < end_idx; layer_idx++) { odb::dbTechLayer* cut_layer = tech->findLayer(layer_idx); if (cut_layer->getType() != odb::dbTechLayerType::CUT) { continue; } - const double cut_res - = std::max(layer_res_[layer_idx][corner->index()], 1.0e-3); + double res, cap; + layerRC(cut_layer, corner, res, cap); + const double cut_res = std::max(res, 1.0e-3); // Resolve from/to endpoints first, so we only allocate a new mid_node // when this iteration actually needs one. On the terminal iteration the From 8ca1f2280404a647645e663013e2e1aeab587a78 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Thu, 16 Jul 2026 17:56:03 -0300 Subject: [PATCH 02/17] est: add -tech, -chip and -redistribution_layer to set_wire_rc with per-chip wire RC Signed-off-by: Eder Monteiro --- src/est/include/est/EstimateParasitics.h | 43 ++++-- src/est/src/EstimateParasitics.cpp | 177 ++++++++++++++--------- src/est/src/EstimateParasitics.i | 30 ++-- src/est/src/EstimateParasitics.tcl | 142 +++++++++++++----- 4 files changed, 261 insertions(+), 131 deletions(-) diff --git a/src/est/include/est/EstimateParasitics.h b/src/est/include/est/EstimateParasitics.h index cf50113c52..ac2787857e 100644 --- a/src/est/include/est/EstimateParasitics.h +++ b/src/est/include/est/EstimateParasitics.h @@ -100,25 +100,31 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService // Return values. double& res, double& cap) const; - void addClkLayer(odb::dbTechLayer* layer); - void addSignalLayer(odb::dbTechLayer* layer); + // A null chip in the setters below writes the default values used by + // chips without chip-specific values. + void addClkLayer(odb::dbChip* chip, odb::dbTechLayer* layer); + void addSignalLayer(odb::dbChip* chip, odb::dbTechLayer* layer); void sortClkAndSignalLayers(); // Set the resistance and capacitance used for horizontal parasitics on signal // nets. - void setHWireSignalRC(const sta::Scene* scene, + void setHWireSignalRC(odb::dbChip* chip, + const sta::Scene* scene, double res, // ohms/meter double cap); // farads/meter // Set the resistance and capacitance used for vertical wires parasitics on // signal nets. - void setVWireSignalRC(const sta::Scene* scene, + void setVWireSignalRC(odb::dbChip* chip, + const sta::Scene* scene, double res, // ohms/meter double cap); // farads/meter // Set the resistance and capacitance used for parasitics on clock nets. - void setHWireClkRC(const sta::Scene* scene, + void setHWireClkRC(odb::dbChip* chip, + const sta::Scene* scene, double res, double cap); // farads/meter // Set the resistance and capacitance used for parasitics on clock nets. - void setVWireClkRC(const sta::Scene* scene, + void setVWireClkRC(odb::dbChip* chip, + const sta::Scene* scene, double res, double cap); // farads/meter // ohms/meter, farads/meter @@ -211,6 +217,20 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService utl::Logger* getLogger() { return logger_; } private: + // Wire RC values and layers of one chip, indexed by corner->index() + struct WireRC + { + std::vector signal_layers; + std::vector clk_layers; + std::vector signal_res; // ohms/meter + std::vector signal_cap; // Farads/meter + std::vector clk_res; // ohms/meter + std::vector clk_cap; // Farads/meter + }; + + odb::dbChip* currentChip() const; + WireRC& wireRC(odb::dbChip* chip) { return wire_rc_[chip]; } + const WireRC* findWireRC() const; void ensureParasitics(); bool isIdealClockPin(const sta::Pin* pin) const; bool isIdealClockNet(const sta::Net* net) const; @@ -259,19 +279,14 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService odb::dbBlock* block_ = nullptr; std::unique_ptr db_cbk_; - std::vector signal_layers_; - std::vector clk_layers_; // Layer RC per wire length keyed by layer, indexed by corner->index() std::unordered_map> layer_res_; // ohms/meter std::unordered_map> layer_cap_; // Farads/meter - // Signal wire RC indexed by corner->index - std::vector wire_signal_res_; // ohms/metre - std::vector wire_signal_cap_; // Farads/meter - // Clock wire RC. - std::vector wire_clk_res_; // ohms/metre - std::vector wire_clk_cap_; // Farads/meter + // Wire RC per chip; the nullptr entry holds the defaults used by chips + // without chip-specific values + std::unordered_map wire_rc_; ParasiticsSrc parasitics_src_ = ParasiticsSrc::kNone; diff --git a/src/est/src/EstimateParasitics.cpp b/src/est/src/EstimateParasitics.cpp index caf6c9c3d9..6279bc23ee 100644 --- a/src/est/src/EstimateParasitics.cpp +++ b/src/est/src/EstimateParasitics.cpp @@ -74,11 +74,7 @@ EstimateParasitics::EstimateParasitics(utl::Logger* logger, global_router_(global_router), db_network_(sta->getDbNetwork()), db_(db), - db_cbk_(std::make_unique(this, network_, db_network_)), - wire_signal_res_(0.0), - wire_signal_cap_(0.0), - wire_clk_res_(0.0), - wire_clk_cap_(0.0) + db_cbk_(std::make_unique(this, network_, db_network_)) { dbStaState::init(sta); db_cbk_ = std::make_unique(this, network_, db_network_); @@ -142,14 +138,32 @@ void EstimateParasitics::layerRC(odb::dbTechLayer* layer, //////////////////////////////////////////////////////////////// -void EstimateParasitics::addClkLayer(odb::dbTechLayer* layer) +odb::dbChip* EstimateParasitics::currentChip() const { - clk_layers_.push_back(layer); + if (block_ != nullptr) { + return block_->getChip(); + } + return db_->getChip(); +} + +const EstimateParasitics::WireRC* EstimateParasitics::findWireRC() const +{ + auto it = wire_rc_.find(currentChip()); + if (it == wire_rc_.end()) { + it = wire_rc_.find(nullptr); + } + return it == wire_rc_.end() ? nullptr : &it->second; } -void EstimateParasitics::addSignalLayer(odb::dbTechLayer* layer) +void EstimateParasitics::addClkLayer(odb::dbChip* chip, odb::dbTechLayer* layer) { - signal_layers_.push_back(layer); + wireRC(chip).clk_layers.push_back(layer); +} + +void EstimateParasitics::addSignalLayer(odb::dbChip* chip, + odb::dbTechLayer* layer) +{ + wireRC(chip).signal_layers.push_back(layer); } void EstimateParasitics::sortClkAndSignalLayers() @@ -158,81 +172,94 @@ void EstimateParasitics::sortClkAndSignalLayers() return a->getNumber() < b->getNumber(); }; - std::ranges::sort(clk_layers_, sort_layers); - std::ranges::sort(signal_layers_, sort_layers); + for (auto& [chip, wire_rc] : wire_rc_) { + std::ranges::sort(wire_rc.clk_layers, sort_layers); + std::ranges::sort(wire_rc.signal_layers, sort_layers); + } } -void EstimateParasitics::setHWireSignalRC(const sta::Scene* scene, +void EstimateParasitics::setHWireSignalRC(odb::dbChip* chip, + const sta::Scene* scene, double res, double cap) { - wire_signal_res_.resize(sta_->scenes().size()); - wire_signal_cap_.resize(sta_->scenes().size()); - wire_signal_res_[scene->index()].h_res = res; - wire_signal_cap_[scene->index()].h_cap = cap; + WireRC& wire_rc = wireRC(chip); + wire_rc.signal_res.resize(sta_->scenes().size()); + wire_rc.signal_cap.resize(sta_->scenes().size()); + wire_rc.signal_res[scene->index()].h_res = res; + wire_rc.signal_cap[scene->index()].h_cap = cap; } -void EstimateParasitics::setVWireSignalRC(const sta::Scene* scene, + +void EstimateParasitics::setVWireSignalRC(odb::dbChip* chip, + const sta::Scene* scene, double res, double cap) { - wire_signal_res_.resize(sta_->scenes().size()); - wire_signal_cap_.resize(sta_->scenes().size()); - wire_signal_res_[scene->index()].v_res = res; - wire_signal_cap_[scene->index()].v_cap = cap; + WireRC& wire_rc = wireRC(chip); + wire_rc.signal_res.resize(sta_->scenes().size()); + wire_rc.signal_cap.resize(sta_->scenes().size()); + wire_rc.signal_res[scene->index()].v_res = res; + wire_rc.signal_cap[scene->index()].v_cap = cap; } double EstimateParasitics::wireSignalResistance(const sta::Scene* scene) const { - if (wire_signal_res_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->signal_res.empty()) { return 0.0; } - return (wire_signal_res_[scene->index()].h_res - + wire_signal_res_[scene->index()].v_res) + return (wire_rc->signal_res[scene->index()].h_res + + wire_rc->signal_res[scene->index()].v_res) / 2; } double EstimateParasitics::wireSignalHResistance(const sta::Scene* scene) const { - if (wire_signal_res_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->signal_res.empty()) { return 0.0; } - return wire_signal_res_[scene->index()].h_res; + return wire_rc->signal_res[scene->index()].h_res; } double EstimateParasitics::wireSignalVResistance(const sta::Scene* scene) const { - if (wire_signal_res_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->signal_res.empty()) { return 0.0; } - return wire_signal_res_[scene->index()].v_res; + return wire_rc->signal_res[scene->index()].v_res; } double EstimateParasitics::wireSignalCapacitance(const sta::Scene* scene) const { - if (wire_signal_cap_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->signal_cap.empty()) { return 0.0; } - return (wire_signal_cap_[scene->index()].h_cap - + wire_signal_cap_[scene->index()].v_cap) + return (wire_rc->signal_cap[scene->index()].h_cap + + wire_rc->signal_cap[scene->index()].v_cap) / 2; } double EstimateParasitics::wireSignalHCapacitance(const sta::Scene* scene) const { - if (wire_signal_cap_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->signal_cap.empty()) { return 0.0; } - return wire_signal_cap_[scene->index()].h_cap; + return wire_rc->signal_cap[scene->index()].h_cap; } double EstimateParasitics::wireSignalVCapacitance(const sta::Scene* scene) const { - if (wire_signal_cap_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->signal_cap.empty()) { return 0.0; } - return wire_signal_cap_[scene->index()].v_cap; + return wire_rc->signal_cap[scene->index()].v_cap; } void EstimateParasitics::wireSignalRC(const sta::Scene* scene, @@ -240,96 +267,107 @@ void EstimateParasitics::wireSignalRC(const sta::Scene* scene, double& res, double& cap) const { - if (wire_signal_res_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->signal_res.empty()) { res = 0.0; } else { - auto resistance = wire_signal_res_[scene->index()]; + auto resistance = wire_rc->signal_res[scene->index()]; res = (resistance.h_res + resistance.v_res) / 2; } - if (wire_signal_cap_.empty()) { + if (wire_rc == nullptr || wire_rc->signal_cap.empty()) { cap = 0.0; } else { - auto capacitance = wire_signal_cap_[scene->index()]; + auto capacitance = wire_rc->signal_cap[scene->index()]; cap = (capacitance.h_cap + capacitance.v_cap) / 2; } } -void EstimateParasitics::setHWireClkRC(const sta::Scene* scene, +void EstimateParasitics::setHWireClkRC(odb::dbChip* chip, + const sta::Scene* scene, double res, double cap) { - wire_clk_res_.resize(sta_->scenes().size()); - wire_clk_cap_.resize(sta_->scenes().size()); - wire_clk_res_[scene->index()].h_res = res; - wire_clk_cap_[scene->index()].h_cap = cap; + WireRC& wire_rc = wireRC(chip); + wire_rc.clk_res.resize(sta_->scenes().size()); + wire_rc.clk_cap.resize(sta_->scenes().size()); + wire_rc.clk_res[scene->index()].h_res = res; + wire_rc.clk_cap[scene->index()].h_cap = cap; } -void EstimateParasitics::setVWireClkRC(const sta::Scene* scene, +void EstimateParasitics::setVWireClkRC(odb::dbChip* chip, + const sta::Scene* scene, double res, double cap) { - wire_clk_res_.resize(sta_->scenes().size()); - wire_clk_cap_.resize(sta_->scenes().size()); - wire_clk_res_[scene->index()].v_res = res; - wire_clk_cap_[scene->index()].v_cap = cap; + WireRC& wire_rc = wireRC(chip); + wire_rc.clk_res.resize(sta_->scenes().size()); + wire_rc.clk_cap.resize(sta_->scenes().size()); + wire_rc.clk_res[scene->index()].v_res = res; + wire_rc.clk_cap[scene->index()].v_cap = cap; } double EstimateParasitics::wireClkResistance(const sta::Scene* scene) const { - if (wire_clk_res_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->clk_res.empty()) { return 0.0; } - return (wire_clk_res_[scene->index()].h_res - + wire_clk_res_[scene->index()].v_res) + return (wire_rc->clk_res[scene->index()].h_res + + wire_rc->clk_res[scene->index()].v_res) / 2; } double EstimateParasitics::wireClkHResistance(const sta::Scene* scene) const { - if (wire_clk_res_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->clk_res.empty()) { return 0.0; } - return wire_clk_res_[scene->index()].h_res; + return wire_rc->clk_res[scene->index()].h_res; } double EstimateParasitics::wireClkVResistance(const sta::Scene* scene) const { - if (wire_clk_res_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->clk_res.empty()) { return 0.0; } - return wire_clk_res_[scene->index()].v_res; + return wire_rc->clk_res[scene->index()].v_res; } double EstimateParasitics::wireClkCapacitance(const sta::Scene* scene) const { - if (wire_clk_cap_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->clk_cap.empty()) { return 0.0; } - return (wire_clk_cap_[scene->index()].h_cap - + wire_clk_cap_[scene->index()].v_cap) + return (wire_rc->clk_cap[scene->index()].h_cap + + wire_rc->clk_cap[scene->index()].v_cap) / 2; } double EstimateParasitics::wireClkHCapacitance(const sta::Scene* scene) const { - if (wire_clk_cap_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->clk_cap.empty()) { return 0.0; } - return wire_clk_cap_[scene->index()].h_cap; + return wire_rc->clk_cap[scene->index()].h_cap; } double EstimateParasitics::wireClkVCapacitance(const sta::Scene* scene) const { - if (wire_clk_cap_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc == nullptr || wire_rc->clk_cap.empty()) { return 0.0; } - return wire_clk_cap_[scene->index()].v_cap; + return wire_rc->clk_cap[scene->index()].v_cap; } //////////////////////////////////////////////////////////////// @@ -618,7 +656,8 @@ void EstimateParasitics::clearParasitics() void EstimateParasitics::estimateWireParasitics(sta::SpefWriter* spef_writer) { initBlock(); - if (!wire_signal_cap_.empty()) { + const WireRC* wire_rc = findWireRC(); + if (wire_rc != nullptr && !wire_rc->signal_cap.empty()) { for (auto mode : sta_->modes()) { sta_->ensureClkNetwork(mode); } @@ -976,11 +1015,11 @@ void EstimateParasitics::parasiticNodeConnectPins( { const sta::PinSeq* pins = tree->pins(pt); if (pins) { - odb::dbTechLayer* tree_layer; - if (is_clk) { - tree_layer = clk_layers_.empty() ? nullptr : clk_layers_[0]; - } else { - tree_layer = signal_layers_.empty() ? nullptr : signal_layers_[0]; + odb::dbTechLayer* tree_layer = nullptr; + if (const WireRC* wire_rc = findWireRC()) { + const auto& layers + = is_clk ? wire_rc->clk_layers : wire_rc->signal_layers; + tree_layer = layers.empty() ? nullptr : layers[0]; } for (const sta::Pin* pin : *pins) { diff --git a/src/est/src/EstimateParasitics.i b/src/est/src/EstimateParasitics.i index 923be09ce1..e97d21490b 100644 --- a/src/est/src/EstimateParasitics.i +++ b/src/est/src/EstimateParasitics.i @@ -130,17 +130,19 @@ set_layer_rc_cmd(odb::dbTechLayer *layer, } void -add_clk_layer_cmd(odb::dbTechLayer *layer) +add_clk_layer_cmd(odb::dbChip *chip, + odb::dbTechLayer *layer) { est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->addClkLayer(layer); + estimate_parasitics->addClkLayer(chip, layer); } void -add_signal_layer_cmd(odb::dbTechLayer *layer) +add_signal_layer_cmd(odb::dbChip *chip, + odb::dbTechLayer *layer) { est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->addSignalLayer(layer); + estimate_parasitics->addSignalLayer(chip, layer); } double @@ -164,43 +166,47 @@ layer_capacitance(odb::dbTechLayer *layer, } void -set_h_wire_signal_rc_cmd(const Scene *corner, +set_h_wire_signal_rc_cmd(odb::dbChip *chip, + const Scene *corner, float res, float cap) { ensureLinked(); est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->setHWireSignalRC(corner, res, cap); + estimate_parasitics->setHWireSignalRC(chip, corner, res, cap); } void -set_v_wire_signal_rc_cmd(const Scene *corner, +set_v_wire_signal_rc_cmd(odb::dbChip *chip, + const Scene *corner, float res, float cap) { ensureLinked(); est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->setVWireSignalRC(corner, res, cap); + estimate_parasitics->setVWireSignalRC(chip, corner, res, cap); } void -set_h_wire_clk_rc_cmd(const Scene *corner, +set_h_wire_clk_rc_cmd(odb::dbChip *chip, + const Scene *corner, float res, float cap) { ensureLinked(); est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->setHWireClkRC(corner, res, cap); + estimate_parasitics->setHWireClkRC(chip, corner, res, cap); } void -set_v_wire_clk_rc_cmd(const Scene *corner, +set_v_wire_clk_rc_cmd(odb::dbChip *chip, + const Scene *corner, float res, float cap) { ensureLinked(); est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->setVWireClkRC(corner, res, cap); + estimate_parasitics->setVWireClkRC(chip, corner, res, cap); } // ohms/meter diff --git a/src/est/src/EstimateParasitics.tcl b/src/est/src/EstimateParasitics.tcl index 0af39a918d..606e49daac 100644 --- a/src/est/src/EstimateParasitics.tcl +++ b/src/est/src/EstimateParasitics.tcl @@ -185,6 +185,80 @@ proc report_layer_rc { args } { puts "----------------------------" } +namespace eval est { +# Chips targeted by -chip/-tech/-redistribution_layer; empty with +# has_selector unset means the default values shared by chips without +# specific values, empty with has_selector set means nothing to do. +proc parse_wire_rc_chips { keys_var flags_var selector_var } { + upvar 1 $keys_var keys + upvar 1 $flags_var flags + upvar 1 $selector_var has_selector + + set selector_count [expr { + [info exists keys(-tech)] + [info exists keys(-chip)] + + [info exists flags(-redistribution_layer)] + }] + if { $selector_count > 1 } { + utl::error EST 28 "Use only one of -tech, -chip or -redistribution_layer." + } + set has_selector [expr { $selector_count > 0 }] + + set db [ord::get_db] + set target_chips {} + if { [info exists keys(-chip)] } { + set chip [$db findChip $keys(-chip)] + if { $chip == "NULL" } { + utl::error EST 29 "chip $keys(-chip) not found." + } + lappend target_chips $chip + } elseif { [info exists keys(-tech)] } { + foreach chip [$db getChips] { + set chip_tech [$chip getTech] + if { $chip_tech != "NULL" && [$chip_tech getName] == $keys(-tech) } { + lappend target_chips $chip + } + } + if { [llength $target_chips] == 0 } { + utl::warn EST 30 "no chip uses technology $keys(-tech); values ignored." + } + } elseif { [info exists flags(-redistribution_layer)] } { + foreach chip [$db getChips] { + if { [$chip getChipType] == "RDL" } { + lappend target_chips $chip + } + } + if { [llength $target_chips] == 0 } { + utl::warn EST 31 "design has no RDL chip; values ignored." + } + } + return $target_chips +} + +# Layer lookups use the targeted chips' technology when one is selected. +proc wire_rc_tech { chips } { + if { [llength $chips] > 0 } { + set tech [[lindex $chips 0] getTech] + if { $tech != "NULL" } { + return $tech + } + } + return [est::get_db_tech_checked] +} + +proc add_wire_rc_layers { chips clk signal layer } { + foreach chip $chips { + if { $clk || !$signal } { + est::add_clk_layer_cmd $chip $layer + } + if { $signal || !$clk } { + est::add_signal_layer_cmd $chip $layer + } + } +} + +# namespace eval est +} + sta::define_cmd_args "set_wire_rc" {[-clock] [-signal] [-data]\ [-layers layers]\ [-layer layer]\ @@ -194,16 +268,29 @@ sta::define_cmd_args "set_wire_rc" {[-clock] [-signal] [-data]\ [-v_capacitance v_cap]\ [-resistance res]\ [-capacitance cap]\ - [-corner corner]} + [-corner corner]\ + [-tech tech]\ + [-chip chip]\ + [-redistribution_layer]} proc set_wire_rc { args } { sta::parse_key_args "set_wire_rc" args \ keys {-layer -layers -resistance -capacitance -corner \ - -h_resistance -h_capacitance -v_resistance -v_capacitance} \ - flags {-clock -signal -data} + -h_resistance -h_capacitance -v_resistance -v_capacitance \ + -tech -chip} \ + flags {-clock -signal -data -redistribution_layer} set corner [sta::parse_scene_or_null keys] + set target_chips [est::parse_wire_rc_chips keys flags has_selector] + if { $has_selector && [llength $target_chips] == 0 } { + return + } + set chip_args $target_chips + if { [llength $chip_args] == 0 } { + set chip_args {NULL} + } + set h_wire_res 0.0 set h_wire_cap 0.0 set v_wire_res 0.0 @@ -230,9 +317,10 @@ proc set_wire_rc { args } { set v_layers 0 set layers $keys(-layers) + set tech [est::wire_rc_tech $target_chips] foreach layer_name $layers { - set tec_layer [[est::get_db_tech_checked] findLayer $layer_name] + set tec_layer [$tech findLayer $layer_name] if { $tec_layer == "NULL" } { utl::error EST 2 "layer $layer_name not found." } @@ -260,18 +348,8 @@ proc set_wire_rc { args } { incr v_layers } - if { [info exists flags(-clock)] } { - est::add_clk_layer_cmd $tec_layer - } - - if { [info exists flags(-signal)] } { - est::add_signal_layer_cmd $tec_layer - } - - if { ![info exists flags(-clock)] && ![info exists flags(-signal)] } { - est::add_clk_layer_cmd $tec_layer - est::add_signal_layer_cmd $tec_layer - } + est::add_wire_rc_layers $chip_args [info exists flags(-clock)] \ + [info exists flags(-signal)] $tec_layer } if { $h_layers == 0 } { utl::error EST 16 "No horizontal layer specified." @@ -286,7 +364,7 @@ proc set_wire_rc { args } { set v_wire_cap [expr $total_v_wire_cap / $v_layers] } elseif { [info exists keys(-layer)] } { set layer_name $keys(-layer) - set tec_layer [[est::get_db_tech_checked] findLayer $layer_name] + set tec_layer [[est::wire_rc_tech $target_chips] findLayer $layer_name] if { $tec_layer == "NULL" } { utl::error EST 15 "layer $tec_layer not found." } @@ -301,18 +379,8 @@ proc set_wire_rc { args } { set v_wire_cap [est::layer_capacitance $tec_layer $corner] } - if { [info exists flags(-clock)] } { - est::add_clk_layer_cmd $tec_layer - } - - if { [info exists flags(-signal)] } { - est::add_signal_layer_cmd $tec_layer - } - - if { ![info exists flags(-clock)] && ![info exists flags(-signal)] } { - est::add_clk_layer_cmd $tec_layer - est::add_signal_layer_cmd $tec_layer - } + est::add_wire_rc_layers $chip_args [info exists flags(-clock)] \ + [info exists flags(-signal)] $tec_layer } else { ord::ensure_units_initialized if { [info exists keys(-resistance)] } { @@ -389,13 +457,15 @@ proc set_wire_rc { args } { set corners [sta::scenes] } foreach corner $corners { - if { $signal } { - est::set_h_wire_signal_rc_cmd $corner $h_wire_res $h_wire_cap - est::set_v_wire_signal_rc_cmd $corner $v_wire_res $v_wire_cap - } - if { $clk } { - est::set_h_wire_clk_rc_cmd $corner $h_wire_res $h_wire_cap - est::set_v_wire_clk_rc_cmd $corner $v_wire_res $v_wire_cap + foreach chip $chip_args { + if { $signal } { + est::set_h_wire_signal_rc_cmd $chip $corner $h_wire_res $h_wire_cap + est::set_v_wire_signal_rc_cmd $chip $corner $v_wire_res $v_wire_cap + } + if { $clk } { + est::set_h_wire_clk_rc_cmd $chip $corner $h_wire_res $h_wire_cap + est::set_v_wire_clk_rc_cmd $chip $corner $v_wire_res $v_wire_cap + } } } } From 19c81588089ac6187bb9b3a5a845f837b41fae37 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Thu, 16 Jul 2026 17:56:03 -0300 Subject: [PATCH 03/17] est: test set_wire_rc chip and tech selectors Signed-off-by: Eder Monteiro --- src/est/test/BUILD | 1 + src/est/test/CMakeLists.txt | 1 + src/est/test/cpp/TestEstimateParasitics.cc | 44 ++++++++++++++++++++++ src/est/test/set_wire_rc_chip.ok | 42 +++++++++++++++++++++ src/est/test/set_wire_rc_chip.tcl | 37 ++++++++++++++++++ 5 files changed, 125 insertions(+) create mode 100644 src/est/test/set_wire_rc_chip.ok create mode 100644 src/est/test/set_wire_rc_chip.tcl diff --git a/src/est/test/BUILD b/src/est/test/BUILD index 3e1e5201e6..6c16d24607 100644 --- a/src/est/test/BUILD +++ b/src/est/test/BUILD @@ -14,6 +14,7 @@ TESTS = [ "make_parasitics5", "make_parasitics6", "make_parasitics7", + "set_wire_rc_chip", ] filegroup( diff --git a/src/est/test/CMakeLists.txt b/src/est/test/CMakeLists.txt index ed999bd4d1..b84a5abde4 100644 --- a/src/est/test/CMakeLists.txt +++ b/src/est/test/CMakeLists.txt @@ -10,6 +10,7 @@ or_integration_tests( make_parasitics5 make_parasitics6 make_parasitics7 + set_wire_rc_chip ) add_executable(TestEstimateParasitics cpp/TestEstimateParasitics.cc) diff --git a/src/est/test/cpp/TestEstimateParasitics.cc b/src/est/test/cpp/TestEstimateParasitics.cc index 1110feb644..643c395bda 100644 --- a/src/est/test/cpp/TestEstimateParasitics.cc +++ b/src/est/test/cpp/TestEstimateParasitics.cc @@ -197,4 +197,48 @@ TEST_F(TestEstimateParasitics, ScanClockIdealOnlyInTestMode) ep_.setIncrementalParasiticsEnabled(false); } +// Verifies that wire RC values are stored per chip: chip-specific values take +// precedence over the defaults, and chips without an entry use the defaults. +TEST_F(TestEstimateParasitics, WireRcPerChip) +{ + readVerilogAndSetup("TestEstimateParasitics.v"); + + sta::Scene* scene = sta_->scenes().front(); + odb::dbChip* chip1 = db_->getChip(); + ASSERT_NE(chip1, nullptr); + + // A null chip sets the default values used by chips without an entry. + ep_.initChip(chip1); + ep_.setHWireSignalRC(nullptr, scene, 1.0e3, 1.0e-10); + ep_.setVWireSignalRC(nullptr, scene, 2.0e3, 2.0e-10); + EXPECT_DOUBLE_EQ(ep_.wireSignalHResistance(scene), 1.0e3); + EXPECT_DOUBLE_EQ(ep_.wireSignalVCapacitance(scene), 2.0e-10); + + // A second chip on its own technology with chip-specific values. + loadTechAndLib( + "tech2", "lib2", getFilePath("_main/test/Nangate45/Nangate45.lef")); + odb::dbTech* tech2 = db_->findTech("tech2"); + ASSERT_NE(tech2, nullptr); + odb::dbChip* chip2 = odb::dbChip::create( + db_.get(), tech2, "chip2", odb::dbChip::ChipType::DIE); + ASSERT_NE(chip2, nullptr); + odb::dbBlock::create(chip2, "chip2_block"); + ep_.setHWireSignalRC(chip2, scene, 3.0e3, 3.0e-10); + ep_.setVWireSignalRC(chip2, scene, 4.0e3, 4.0e-10); + + // The chip-specific values do not leak into the default-valued chip. + EXPECT_DOUBLE_EQ(ep_.wireSignalHResistance(scene), 1.0e3); + + // Rebinding to the second chip resolves its chip-specific values. + ep_.initChip(chip2); + EXPECT_DOUBLE_EQ(ep_.wireSignalHResistance(scene), 3.0e3); + EXPECT_DOUBLE_EQ(ep_.wireSignalVCapacitance(scene), 4.0e-10); + EXPECT_DOUBLE_EQ(ep_.wireClkHResistance(scene), 0.0); + + // Rebinding back to a chip without an entry falls back to the defaults. + ep_.initChip(chip1); + EXPECT_DOUBLE_EQ(ep_.wireSignalHResistance(scene), 1.0e3); + EXPECT_DOUBLE_EQ(ep_.wireSignalVResistance(scene), 2.0e3); +} + } // namespace est diff --git a/src/est/test/set_wire_rc_chip.ok b/src/est/test/set_wire_rc_chip.ok new file mode 100644 index 0000000000..dddd052101 --- /dev/null +++ b/src/est/test/set_wire_rc_chip.ok @@ -0,0 +1,42 @@ +[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias, 135 library cells +[INFO ODB-0128] Design: reg1 +[INFO ODB-0130] Created 4 pins. +[INFO ODB-0131] Created 5 components and 27 component-terminals. +[INFO ODB-0132] Created 2 special nets and 10 connections. +[INFO ODB-0133] Created 8 nets and 14 connections. +[ERROR EST-0029] chip no_such_chip not found. +EST-0029 +[ERROR EST-0028] Use only one of -tech, -chip or -redistribution_layer. +EST-0028 +[WARNING EST-0030] no chip uses technology no_such_tech; values ignored. +[WARNING EST-0031] design has no RDL chip; values ignored. +[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias +Startpoint: r2 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +--------------------------------------------------------- + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 ^ r2/CK (DFF_X1) + 0.14 0.14 ^ r2/Q (DFF_X1) + 0.22 0.36 ^ u1/Z (BUF_X1) + 0.15 0.52 ^ u2/ZN (AND2_X1) + 0.00 0.52 ^ r3/D (DFF_X1) + 0.52 data arrival time + + 10.00 10.00 clock clk (rise edge) + 0.00 10.00 clock network delay (ideal) + 0.00 10.00 clock reconvergence pessimism + 10.00 ^ r3/CK (DFF_X1) + -0.05 9.95 library setup time + 9.95 data required time +--------------------------------------------------------- + 9.95 data required time + -0.52 data arrival time +--------------------------------------------------------- + 9.44 slack (MET) + + diff --git a/src/est/test/set_wire_rc_chip.tcl b/src/est/test/set_wire_rc_chip.tcl new file mode 100644 index 0000000000..980765f99b --- /dev/null +++ b/src/est/test/set_wire_rc_chip.tcl @@ -0,0 +1,37 @@ +# set_wire_rc -tech/-chip/-redistribution_layer chip selectors +source "helpers.tcl" +read_lef Nangate45/Nangate45.lef +read_liberty Nangate45/Nangate45_typ.lib +read_def reg3.def + +create_clock -period 10 clk +set_input_delay -clock clk 0 in1 + +# unknown chip name is an error +catch { set_wire_rc -chip no_such_chip -resistance 1e-3 -capacitance 1e-1 } msg +puts $msg +# selectors are mutually exclusive +catch { set_wire_rc -tech Nangate45 -chip chip1 -resistance 1e-3 -capacitance 1e-1 } msg +puts $msg +# selectors matching no chip warn and are ignored +set_wire_rc -tech no_such_tech -resistance 1e-3 -capacitance 1e-1 +set_wire_rc -redistribution_layer -resistance 1e-3 -capacitance 1e-1 + +# a second tech makes the database multi-tech; tech-targeted values still work +read_lef -tech -tech_name tech2 Nangate45/Nangate45.lef + +# same wire RC values as make_parasitics1 +set lambda .12 +# kohm/square. +set m1_res_sq .08e-3 +# ff/micron^2 +set m1_area_cap 39e-3 +# ff/micron. +set m1_edge_cap 57e-3 +# 4 lambda wide wire +set wire_cap [expr { $m1_area_cap * $lambda * 4 + $m1_edge_cap * 2 }] +set wire_res [expr { $m1_res_sq / ($lambda * 4) }] +set_wire_rc -tech Nangate45 -resistance $wire_res -capacitance $wire_cap +estimate_parasitics -placement + +report_checks From 272d6c292b54a949412fe41ac7e472e40666f802 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Thu, 16 Jul 2026 17:56:03 -0300 Subject: [PATCH 04/17] est: document set_wire_rc chip and tech selectors Signed-off-by: Eder Monteiro --- src/est/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/est/README.md b/src/est/README.md index f5bf5b3128..aeb8959ef7 100644 --- a/src/est/README.md +++ b/src/est/README.md @@ -66,6 +66,12 @@ set_wire_rc | `-h_capacitance` | Capacitance per unit length for horizontal wires, units are from the first Liberty file read. | | `-v_resistance` | Resistance per unit length for vertical wires, units are from the first Liberty file read. | | `-v_capacitance` | Capacitance per unit length for vertical wires, units are from the first Liberty file read. | +| `-tech` | Apply the values to all chips using this technology (3D designs). Layers given with `-layer`/`-layers` are looked up in this technology. | +| `-chip` | Apply the values to the named chip only (3D designs). | +| `-redistribution_layer` | Apply the values to all RDL chips. Warns and does nothing when the design has no RDL chip, so shared scripts work across designs. | + +Without `-tech`, `-chip` or `-redistribution_layer` the values are the defaults +used by every chip that has no chip-specific values. ### Set Layer RC From 1eae7954e9c04638db988eeb4575627c5c95a072 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 11:51:11 -0300 Subject: [PATCH 05/17] est: address review comments on RC lookups and callback construction Signed-off-by: Eder Monteiro --- src/est/src/EstimateParasitics.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/est/src/EstimateParasitics.cpp b/src/est/src/EstimateParasitics.cpp index 6279bc23ee..6696c4c9e3 100644 --- a/src/est/src/EstimateParasitics.cpp +++ b/src/est/src/EstimateParasitics.cpp @@ -73,8 +73,7 @@ EstimateParasitics::EstimateParasitics(utl::Logger* logger, stt_builder_(stt_builder), global_router_(global_router), db_network_(sta->getDbNetwork()), - db_(db), - db_cbk_(std::make_unique(this, network_, db_network_)) + db_(db) { dbStaState::init(sta); db_cbk_ = std::make_unique(this, network_, db_network_); @@ -127,13 +126,14 @@ void EstimateParasitics::layerRC(odb::dbTechLayer* layer, double& cap) const { const auto res_it = layer_res_.find(layer); - if (res_it == layer_res_.end()) { - res = 0.0; - cap = 0.0; - } else { - res = res_it->second[corner->index()]; - cap = layer_cap_.at(layer)[corner->index()]; - } + const auto cap_it = layer_cap_.find(layer); + const size_t corner_idx = corner->index(); + res = res_it != layer_res_.end() && corner_idx < res_it->second.size() + ? res_it->second[corner_idx] + : 0.0; + cap = cap_it != layer_cap_.end() && corner_idx < cap_it->second.size() + ? cap_it->second[corner_idx] + : 0.0; } //////////////////////////////////////////////////////////////// @@ -148,8 +148,9 @@ odb::dbChip* EstimateParasitics::currentChip() const const EstimateParasitics::WireRC* EstimateParasitics::findWireRC() const { - auto it = wire_rc_.find(currentChip()); - if (it == wire_rc_.end()) { + odb::dbChip* chip = currentChip(); + auto it = wire_rc_.find(chip); + if (it == wire_rc_.end() && chip != nullptr) { it = wire_rc_.find(nullptr); } return it == wire_rc_.end() ? nullptr : &it->second; From efe9f69b0899c60e9dcbe879e797e766231f52d7 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 12:10:33 -0300 Subject: [PATCH 06/17] est: fall back to default wire RC per category instead of per chip Signed-off-by: Eder Monteiro --- src/est/README.md | 4 +- src/est/include/est/EstimateParasitics.h | 20 +++- src/est/src/EstimateParasitics.cpp | 133 ++++++++------------- src/est/test/cpp/TestEstimateParasitics.cc | 7 +- 4 files changed, 77 insertions(+), 87 deletions(-) diff --git a/src/est/README.md b/src/est/README.md index aeb8959ef7..2bbf0ed73b 100644 --- a/src/est/README.md +++ b/src/est/README.md @@ -71,7 +71,9 @@ set_wire_rc | `-redistribution_layer` | Apply the values to all RDL chips. Warns and does nothing when the design has no RDL chip, so shared scripts work across designs. | Without `-tech`, `-chip` or `-redistribution_layer` the values are the defaults -used by every chip that has no chip-specific values. +used by every chip that has no chip-specific values. Signal values, clock +values and routing layers fall back to the defaults independently, so a chip +with only chip-specific signal values still uses the default clock values. ### Set Layer RC diff --git a/src/est/include/est/EstimateParasitics.h b/src/est/include/est/EstimateParasitics.h index ac2787857e..f957c83cf4 100644 --- a/src/est/include/est/EstimateParasitics.h +++ b/src/est/include/est/EstimateParasitics.h @@ -230,7 +230,25 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService odb::dbChip* currentChip() const; WireRC& wireRC(odb::dbChip* chip) { return wire_rc_[chip]; } - const WireRC* findWireRC() const; + // Resolve one WireRC category for the current chip; a category left unset + // for a chip falls back to the defaults (nullptr entry) independently. + template + const std::vector& wireRCVector(std::vector WireRC::*member) const + { + static const std::vector empty; + odb::dbChip* chip = currentChip(); + auto it = wire_rc_.find(chip); + if (it != wire_rc_.end() && !(it->second.*member).empty()) { + return it->second.*member; + } + if (chip != nullptr) { + it = wire_rc_.find(nullptr); + if (it != wire_rc_.end() && !(it->second.*member).empty()) { + return it->second.*member; + } + } + return empty; + } void ensureParasitics(); bool isIdealClockPin(const sta::Pin* pin) const; bool isIdealClockNet(const sta::Net* net) const; diff --git a/src/est/src/EstimateParasitics.cpp b/src/est/src/EstimateParasitics.cpp index 6696c4c9e3..16f2bb2d35 100644 --- a/src/est/src/EstimateParasitics.cpp +++ b/src/est/src/EstimateParasitics.cpp @@ -146,16 +146,6 @@ odb::dbChip* EstimateParasitics::currentChip() const return db_->getChip(); } -const EstimateParasitics::WireRC* EstimateParasitics::findWireRC() const -{ - odb::dbChip* chip = currentChip(); - auto it = wire_rc_.find(chip); - if (it == wire_rc_.end() && chip != nullptr) { - it = wire_rc_.find(nullptr); - } - return it == wire_rc_.end() ? nullptr : &it->second; -} - void EstimateParasitics::addClkLayer(odb::dbChip* chip, odb::dbTechLayer* layer) { wireRC(chip).clk_layers.push_back(layer); @@ -205,62 +195,56 @@ void EstimateParasitics::setVWireSignalRC(odb::dbChip* chip, double EstimateParasitics::wireSignalResistance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->signal_res.empty()) { + const auto& values = wireRCVector(&WireRC::signal_res); + if (values.empty()) { return 0.0; } - - return (wire_rc->signal_res[scene->index()].h_res - + wire_rc->signal_res[scene->index()].v_res) - / 2; + return (values[scene->index()].h_res + values[scene->index()].v_res) / 2; } double EstimateParasitics::wireSignalHResistance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->signal_res.empty()) { + const auto& values = wireRCVector(&WireRC::signal_res); + if (values.empty()) { return 0.0; } - return wire_rc->signal_res[scene->index()].h_res; + return values[scene->index()].h_res; } double EstimateParasitics::wireSignalVResistance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->signal_res.empty()) { + const auto& values = wireRCVector(&WireRC::signal_res); + if (values.empty()) { return 0.0; } - return wire_rc->signal_res[scene->index()].v_res; + return values[scene->index()].v_res; } double EstimateParasitics::wireSignalCapacitance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->signal_cap.empty()) { + const auto& values = wireRCVector(&WireRC::signal_cap); + if (values.empty()) { return 0.0; } - - return (wire_rc->signal_cap[scene->index()].h_cap - + wire_rc->signal_cap[scene->index()].v_cap) - / 2; + return (values[scene->index()].h_cap + values[scene->index()].v_cap) / 2; } double EstimateParasitics::wireSignalHCapacitance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->signal_cap.empty()) { + const auto& values = wireRCVector(&WireRC::signal_cap); + if (values.empty()) { return 0.0; } - return wire_rc->signal_cap[scene->index()].h_cap; + return values[scene->index()].h_cap; } double EstimateParasitics::wireSignalVCapacitance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->signal_cap.empty()) { + const auto& values = wireRCVector(&WireRC::signal_cap); + if (values.empty()) { return 0.0; } - return wire_rc->signal_cap[scene->index()].v_cap; + return values[scene->index()].v_cap; } void EstimateParasitics::wireSignalRC(const sta::Scene* scene, @@ -268,19 +252,16 @@ void EstimateParasitics::wireSignalRC(const sta::Scene* scene, double& res, double& cap) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->signal_res.empty()) { - res = 0.0; - } else { - auto resistance = wire_rc->signal_res[scene->index()]; - res = (resistance.h_res + resistance.v_res) / 2; - } - if (wire_rc == nullptr || wire_rc->signal_cap.empty()) { - cap = 0.0; - } else { - auto capacitance = wire_rc->signal_cap[scene->index()]; - cap = (capacitance.h_cap + capacitance.v_cap) / 2; - } + const auto& resistance = wireRCVector(&WireRC::signal_res); + const auto& capacitance = wireRCVector(&WireRC::signal_cap); + res = resistance.empty() ? 0.0 + : (resistance[scene->index()].h_res + + resistance[scene->index()].v_res) + / 2; + cap = capacitance.empty() ? 0.0 + : (capacitance[scene->index()].h_cap + + capacitance[scene->index()].v_cap) + / 2; } void EstimateParasitics::setHWireClkRC(odb::dbChip* chip, @@ -309,66 +290,56 @@ void EstimateParasitics::setVWireClkRC(odb::dbChip* chip, double EstimateParasitics::wireClkResistance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->clk_res.empty()) { + const auto& values = wireRCVector(&WireRC::clk_res); + if (values.empty()) { return 0.0; } - - return (wire_rc->clk_res[scene->index()].h_res - + wire_rc->clk_res[scene->index()].v_res) - / 2; + return (values[scene->index()].h_res + values[scene->index()].v_res) / 2; } double EstimateParasitics::wireClkHResistance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->clk_res.empty()) { + const auto& values = wireRCVector(&WireRC::clk_res); + if (values.empty()) { return 0.0; } - - return wire_rc->clk_res[scene->index()].h_res; + return values[scene->index()].h_res; } double EstimateParasitics::wireClkVResistance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->clk_res.empty()) { + const auto& values = wireRCVector(&WireRC::clk_res); + if (values.empty()) { return 0.0; } - - return wire_rc->clk_res[scene->index()].v_res; + return values[scene->index()].v_res; } double EstimateParasitics::wireClkCapacitance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->clk_cap.empty()) { + const auto& values = wireRCVector(&WireRC::clk_cap); + if (values.empty()) { return 0.0; } - - return (wire_rc->clk_cap[scene->index()].h_cap - + wire_rc->clk_cap[scene->index()].v_cap) - / 2; + return (values[scene->index()].h_cap + values[scene->index()].v_cap) / 2; } double EstimateParasitics::wireClkHCapacitance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->clk_cap.empty()) { + const auto& values = wireRCVector(&WireRC::clk_cap); + if (values.empty()) { return 0.0; } - - return wire_rc->clk_cap[scene->index()].h_cap; + return values[scene->index()].h_cap; } double EstimateParasitics::wireClkVCapacitance(const sta::Scene* scene) const { - const WireRC* wire_rc = findWireRC(); - if (wire_rc == nullptr || wire_rc->clk_cap.empty()) { + const auto& values = wireRCVector(&WireRC::clk_cap); + if (values.empty()) { return 0.0; } - - return wire_rc->clk_cap[scene->index()].v_cap; + return values[scene->index()].v_cap; } //////////////////////////////////////////////////////////////// @@ -657,8 +628,7 @@ void EstimateParasitics::clearParasitics() void EstimateParasitics::estimateWireParasitics(sta::SpefWriter* spef_writer) { initBlock(); - const WireRC* wire_rc = findWireRC(); - if (wire_rc != nullptr && !wire_rc->signal_cap.empty()) { + if (!wireRCVector(&WireRC::signal_cap).empty()) { for (auto mode : sta_->modes()) { sta_->ensureClkNetwork(mode); } @@ -1016,12 +986,9 @@ void EstimateParasitics::parasiticNodeConnectPins( { const sta::PinSeq* pins = tree->pins(pt); if (pins) { - odb::dbTechLayer* tree_layer = nullptr; - if (const WireRC* wire_rc = findWireRC()) { - const auto& layers - = is_clk ? wire_rc->clk_layers : wire_rc->signal_layers; - tree_layer = layers.empty() ? nullptr : layers[0]; - } + const auto& layers + = wireRCVector(is_clk ? &WireRC::clk_layers : &WireRC::signal_layers); + odb::dbTechLayer* tree_layer = layers.empty() ? nullptr : layers[0]; for (const sta::Pin* pin : *pins) { sta::ParasiticNode* pin_node diff --git a/src/est/test/cpp/TestEstimateParasitics.cc b/src/est/test/cpp/TestEstimateParasitics.cc index 643c395bda..374ba6a56f 100644 --- a/src/est/test/cpp/TestEstimateParasitics.cc +++ b/src/est/test/cpp/TestEstimateParasitics.cc @@ -211,6 +211,8 @@ TEST_F(TestEstimateParasitics, WireRcPerChip) ep_.initChip(chip1); ep_.setHWireSignalRC(nullptr, scene, 1.0e3, 1.0e-10); ep_.setVWireSignalRC(nullptr, scene, 2.0e3, 2.0e-10); + ep_.setHWireClkRC(nullptr, scene, 5.0e3, 5.0e-10); + ep_.setVWireClkRC(nullptr, scene, 5.0e3, 5.0e-10); EXPECT_DOUBLE_EQ(ep_.wireSignalHResistance(scene), 1.0e3); EXPECT_DOUBLE_EQ(ep_.wireSignalVCapacitance(scene), 2.0e-10); @@ -229,11 +231,12 @@ TEST_F(TestEstimateParasitics, WireRcPerChip) // The chip-specific values do not leak into the default-valued chip. EXPECT_DOUBLE_EQ(ep_.wireSignalHResistance(scene), 1.0e3); - // Rebinding to the second chip resolves its chip-specific values. + // Rebinding to the second chip resolves its chip-specific signal values; + // its unset clock values fall back to the defaults independently. ep_.initChip(chip2); EXPECT_DOUBLE_EQ(ep_.wireSignalHResistance(scene), 3.0e3); EXPECT_DOUBLE_EQ(ep_.wireSignalVCapacitance(scene), 4.0e-10); - EXPECT_DOUBLE_EQ(ep_.wireClkHResistance(scene), 0.0); + EXPECT_DOUBLE_EQ(ep_.wireClkHResistance(scene), 5.0e3); // Rebinding back to a chip without an entry falls back to the defaults. ep_.initChip(chip1); From 140a59d74a16e9baee52b041013da37308b73784 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 12:10:33 -0300 Subject: [PATCH 07/17] est: fix layer selection for chips with different technologies Signed-off-by: Eder Monteiro --- src/est/src/EstimateParasitics.tcl | 15 ++++++++++++--- src/est/test/set_wire_rc_chip.ok | 2 ++ src/est/test/set_wire_rc_chip.tcl | 13 +++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/est/src/EstimateParasitics.tcl b/src/est/src/EstimateParasitics.tcl index 606e49daac..9dac33fd32 100644 --- a/src/est/src/EstimateParasitics.tcl +++ b/src/est/src/EstimateParasitics.tcl @@ -234,10 +234,17 @@ proc parse_wire_rc_chips { keys_var flags_var selector_var } { return $target_chips } -# Layer lookups use the targeted chips' technology when one is selected. +# Layer lookups use the targeted chips' technology when one is selected; +# layers cannot be resolved for chips with different technologies. proc wire_rc_tech { chips } { if { [llength $chips] > 0 } { set tech [[lindex $chips 0] getTech] + foreach chip $chips { + if { [$chip getTech] != $tech } { + utl::error EST 32 "-layer and -layers require chips that share one\ + technology; set each chip separately with -chip." + } + } if { $tech != "NULL" } { return $tech } @@ -491,7 +498,8 @@ proc check_parasitics { } { proc dblayer_wire_rc { layer } { set layer_width_dbu [$layer getWidth] - set layer_width_micron [ord::dbu_to_microns $layer_width_dbu] + set dbu_per_micron [[$layer getTech] getDbUnitsPerMicron] + set layer_width_micron [expr { double($layer_width_dbu) / $dbu_per_micron }] set res_ohm_per_sq [$layer getResistance] set res_ohm_per_micron [expr $res_ohm_per_sq / $layer_width_micron] set cap_area_pf_per_sq_micron [$layer getCapacitance] @@ -509,7 +517,8 @@ proc dblayer_wire_rc { layer } { proc set_dblayer_wire_rc { layer res cap } { # Zero the edge cap and just use the user given value $layer setEdgeCapacitance 0 - set wire_width [ord::dbu_to_microns [$layer getWidth]] + set dbu_per_micron [[$layer getTech] getDbUnitsPerMicron] + set wire_width [expr { double([$layer getWidth]) / $dbu_per_micron }] # Convert wire capacitance/wire_length to capacitance/area (pF/um) set cap_per_square [expr $cap * 1e+6 / $wire_width] $layer setCapacitance $cap_per_square diff --git a/src/est/test/set_wire_rc_chip.ok b/src/est/test/set_wire_rc_chip.ok index dddd052101..1406d2fc1e 100644 --- a/src/est/test/set_wire_rc_chip.ok +++ b/src/est/test/set_wire_rc_chip.ok @@ -11,6 +11,8 @@ EST-0028 [WARNING EST-0030] no chip uses technology no_such_tech; values ignored. [WARNING EST-0031] design has no RDL chip; values ignored. [INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias +[ERROR EST-0032] -layer and -layers require chips that share one technology; set each chip separately with -chip. +EST-0032 Startpoint: r2 (rising edge-triggered flip-flop clocked by clk) Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) Path Group: clk diff --git a/src/est/test/set_wire_rc_chip.tcl b/src/est/test/set_wire_rc_chip.tcl index 980765f99b..cfab329936 100644 --- a/src/est/test/set_wire_rc_chip.tcl +++ b/src/est/test/set_wire_rc_chip.tcl @@ -20,6 +20,19 @@ set_wire_rc -redistribution_layer -resistance 1e-3 -capacitance 1e-1 # a second tech makes the database multi-tech; tech-targeted values still work read_lef -tech -tech_name tech2 Nangate45/Nangate45.lef +# a second chip on its own technology: -chip, -tech and RDL selectors succeed +set db [ord::get_db] +odb::dbChip_create $db [$db findTech tech2] "chip2" "RDL" +set_wire_rc -chip chip2 -resistance 1e-3 -capacitance 1e-1 +set_wire_rc -tech tech2 -layer metal3 +set_wire_rc -redistribution_layer -resistance 2e-3 -capacitance 2e-1 + +# heterogeneous RDL technologies cannot resolve a shared layer +odb::dbChip_create $db [$db findTech Nangate45] "chip3" "RDL" +set_wire_rc -redistribution_layer -resistance 2e-3 -capacitance 2e-1 +catch { set_wire_rc -redistribution_layer -layer metal3 } msg +puts $msg + # same wire RC values as make_parasitics1 set lambda .12 # kohm/square. From 911afac2be1270717594e50b0ac0edb30976501d Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 12:25:12 -0300 Subject: [PATCH 08/17] est: add chip selectors to set_wire_rc synopsis in README Signed-off-by: Eder Monteiro --- src/est/README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/est/README.md b/src/est/README.md index 2bbf0ed73b..2e2ec9c44a 100644 --- a/src/est/README.md +++ b/src/est/README.md @@ -15,6 +15,9 @@ The `set_wire_rc` command sets the resistance and capacitance used to estimate delay of routing wires. Separate values can be specified for clock and data nets with the `-signal` and `-clock` flags. Without either `-signal` or `-clock` the resistance and capacitance for clocks and data nets are set. +In 3D designs the values can be targeted at specific chips with the `-tech`, +`-chip` and `-redistribution_layer` selectors; without a selector the values +are the defaults used by chips that have no chip-specific values. ``` # Either run @@ -31,6 +34,9 @@ set_wire_rc [-data] [-corner corner] [-layers layers_list] + [-tech tech] + [-chip chip] + [-redistribution_layer] or set_wire_rc @@ -38,6 +44,9 @@ set_wire_rc [-h_capacitance cap] [-v_resistance res] [-v_capacitance cap] + [-tech tech] + [-chip chip] + [-redistribution_layer] or set_wire_rc @@ -46,10 +55,16 @@ set_wire_rc [-data] [-corner corner] [-layer layer_name] + [-tech tech] + [-chip chip] + [-redistribution_layer] or set_wire_rc [-resistance res] [-capacitance cap] + [-tech tech] + [-chip chip] + [-redistribution_layer] ``` #### Options @@ -68,7 +83,7 @@ set_wire_rc | `-v_capacitance` | Capacitance per unit length for vertical wires, units are from the first Liberty file read. | | `-tech` | Apply the values to all chips using this technology (3D designs). Layers given with `-layer`/`-layers` are looked up in this technology. | | `-chip` | Apply the values to the named chip only (3D designs). | -| `-redistribution_layer` | Apply the values to all RDL chips. Warns and does nothing when the design has no RDL chip, so shared scripts work across designs. | +| `-redistribution_layer` | Apply the values to every RDL chip in the design, however many there are. Warns and does nothing when the design has none, so shared scripts work across designs. `-layer`/`-layers` require the selected RDL chips to share one technology; with mixed RDL technologies set each chip separately with `-chip`. | Without `-tech`, `-chip` or `-redistribution_layer` the values are the defaults used by every chip that has no chip-specific values. Signal values, clock From 83349112305128aecf1301a11226e609e63a7bf3 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 12:38:05 -0300 Subject: [PATCH 09/17] est: split set_wire_rc chip selector tests into self-contained cases Signed-off-by: Eder Monteiro --- src/est/test/BUILD | 4 ++++ src/est/test/CMakeLists.txt | 4 ++++ src/est/test/set_wire_rc_chip.ok | 8 ------- src/est/test/set_wire_rc_chip.tcl | 25 +-------------------- src/est/test/set_wire_rc_chip_errors.ok | 10 +++++++++ src/est/test/set_wire_rc_chip_errors.tcl | 11 +++++++++ src/est/test/set_wire_rc_chip_ignored.ok | 8 +++++++ src/est/test/set_wire_rc_chip_ignored.tcl | 7 ++++++ src/est/test/set_wire_rc_chip_select.ok | 8 +++++++ src/est/test/set_wire_rc_chip_select.tcl | 14 ++++++++++++ src/est/test/set_wire_rc_rdl_mixed_tech.ok | 9 ++++++++ src/est/test/set_wire_rc_rdl_mixed_tech.tcl | 16 +++++++++++++ 12 files changed, 92 insertions(+), 32 deletions(-) create mode 100644 src/est/test/set_wire_rc_chip_errors.ok create mode 100644 src/est/test/set_wire_rc_chip_errors.tcl create mode 100644 src/est/test/set_wire_rc_chip_ignored.ok create mode 100644 src/est/test/set_wire_rc_chip_ignored.tcl create mode 100644 src/est/test/set_wire_rc_chip_select.ok create mode 100644 src/est/test/set_wire_rc_chip_select.tcl create mode 100644 src/est/test/set_wire_rc_rdl_mixed_tech.ok create mode 100644 src/est/test/set_wire_rc_rdl_mixed_tech.tcl diff --git a/src/est/test/BUILD b/src/est/test/BUILD index 6c16d24607..cb822fe22b 100644 --- a/src/est/test/BUILD +++ b/src/est/test/BUILD @@ -15,6 +15,10 @@ TESTS = [ "make_parasitics6", "make_parasitics7", "set_wire_rc_chip", + "set_wire_rc_chip_errors", + "set_wire_rc_chip_ignored", + "set_wire_rc_chip_select", + "set_wire_rc_rdl_mixed_tech", ] filegroup( diff --git a/src/est/test/CMakeLists.txt b/src/est/test/CMakeLists.txt index b84a5abde4..484b1edc13 100644 --- a/src/est/test/CMakeLists.txt +++ b/src/est/test/CMakeLists.txt @@ -11,6 +11,10 @@ or_integration_tests( make_parasitics6 make_parasitics7 set_wire_rc_chip + set_wire_rc_chip_errors + set_wire_rc_chip_ignored + set_wire_rc_chip_select + set_wire_rc_rdl_mixed_tech ) add_executable(TestEstimateParasitics cpp/TestEstimateParasitics.cc) diff --git a/src/est/test/set_wire_rc_chip.ok b/src/est/test/set_wire_rc_chip.ok index 1406d2fc1e..1ecd49b941 100644 --- a/src/est/test/set_wire_rc_chip.ok +++ b/src/est/test/set_wire_rc_chip.ok @@ -4,15 +4,7 @@ [INFO ODB-0131] Created 5 components and 27 component-terminals. [INFO ODB-0132] Created 2 special nets and 10 connections. [INFO ODB-0133] Created 8 nets and 14 connections. -[ERROR EST-0029] chip no_such_chip not found. -EST-0029 -[ERROR EST-0028] Use only one of -tech, -chip or -redistribution_layer. -EST-0028 -[WARNING EST-0030] no chip uses technology no_such_tech; values ignored. -[WARNING EST-0031] design has no RDL chip; values ignored. [INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias -[ERROR EST-0032] -layer and -layers require chips that share one technology; set each chip separately with -chip. -EST-0032 Startpoint: r2 (rising edge-triggered flip-flop clocked by clk) Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) Path Group: clk diff --git a/src/est/test/set_wire_rc_chip.tcl b/src/est/test/set_wire_rc_chip.tcl index cfab329936..425addee13 100644 --- a/src/est/test/set_wire_rc_chip.tcl +++ b/src/est/test/set_wire_rc_chip.tcl @@ -1,4 +1,4 @@ -# set_wire_rc -tech/-chip/-redistribution_layer chip selectors +# estimate_parasitics with tech-targeted wire RC in a multi-tech database source "helpers.tcl" read_lef Nangate45/Nangate45.lef read_liberty Nangate45/Nangate45_typ.lib @@ -7,32 +7,9 @@ read_def reg3.def create_clock -period 10 clk set_input_delay -clock clk 0 in1 -# unknown chip name is an error -catch { set_wire_rc -chip no_such_chip -resistance 1e-3 -capacitance 1e-1 } msg -puts $msg -# selectors are mutually exclusive -catch { set_wire_rc -tech Nangate45 -chip chip1 -resistance 1e-3 -capacitance 1e-1 } msg -puts $msg -# selectors matching no chip warn and are ignored -set_wire_rc -tech no_such_tech -resistance 1e-3 -capacitance 1e-1 -set_wire_rc -redistribution_layer -resistance 1e-3 -capacitance 1e-1 - # a second tech makes the database multi-tech; tech-targeted values still work read_lef -tech -tech_name tech2 Nangate45/Nangate45.lef -# a second chip on its own technology: -chip, -tech and RDL selectors succeed -set db [ord::get_db] -odb::dbChip_create $db [$db findTech tech2] "chip2" "RDL" -set_wire_rc -chip chip2 -resistance 1e-3 -capacitance 1e-1 -set_wire_rc -tech tech2 -layer metal3 -set_wire_rc -redistribution_layer -resistance 2e-3 -capacitance 2e-1 - -# heterogeneous RDL technologies cannot resolve a shared layer -odb::dbChip_create $db [$db findTech Nangate45] "chip3" "RDL" -set_wire_rc -redistribution_layer -resistance 2e-3 -capacitance 2e-1 -catch { set_wire_rc -redistribution_layer -layer metal3 } msg -puts $msg - # same wire RC values as make_parasitics1 set lambda .12 # kohm/square. diff --git a/src/est/test/set_wire_rc_chip_errors.ok b/src/est/test/set_wire_rc_chip_errors.ok new file mode 100644 index 0000000000..0af2b50288 --- /dev/null +++ b/src/est/test/set_wire_rc_chip_errors.ok @@ -0,0 +1,10 @@ +[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias, 135 library cells +[INFO ODB-0128] Design: reg1 +[INFO ODB-0130] Created 4 pins. +[INFO ODB-0131] Created 5 components and 27 component-terminals. +[INFO ODB-0132] Created 2 special nets and 10 connections. +[INFO ODB-0133] Created 8 nets and 14 connections. +[ERROR EST-0029] chip no_such_chip not found. +EST-0029 +[ERROR EST-0028] Use only one of -tech, -chip or -redistribution_layer. +EST-0028 diff --git a/src/est/test/set_wire_rc_chip_errors.tcl b/src/est/test/set_wire_rc_chip_errors.tcl new file mode 100644 index 0000000000..48621eaef1 --- /dev/null +++ b/src/est/test/set_wire_rc_chip_errors.tcl @@ -0,0 +1,11 @@ +# set_wire_rc chip selector misuse errors +source "helpers.tcl" +read_lef Nangate45/Nangate45.lef +read_def reg3.def + +# unknown chip name is an error +catch { set_wire_rc -chip no_such_chip -resistance 1e-3 -capacitance 1e-1 } msg +puts $msg +# selectors are mutually exclusive +catch { set_wire_rc -tech Nangate45 -chip chip1 -resistance 1e-3 -capacitance 1e-1 } msg +puts $msg diff --git a/src/est/test/set_wire_rc_chip_ignored.ok b/src/est/test/set_wire_rc_chip_ignored.ok new file mode 100644 index 0000000000..b53f94391c --- /dev/null +++ b/src/est/test/set_wire_rc_chip_ignored.ok @@ -0,0 +1,8 @@ +[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias, 135 library cells +[INFO ODB-0128] Design: reg1 +[INFO ODB-0130] Created 4 pins. +[INFO ODB-0131] Created 5 components and 27 component-terminals. +[INFO ODB-0132] Created 2 special nets and 10 connections. +[INFO ODB-0133] Created 8 nets and 14 connections. +[WARNING EST-0030] no chip uses technology no_such_tech; values ignored. +[WARNING EST-0031] design has no RDL chip; values ignored. diff --git a/src/est/test/set_wire_rc_chip_ignored.tcl b/src/est/test/set_wire_rc_chip_ignored.tcl new file mode 100644 index 0000000000..1c14efb7c8 --- /dev/null +++ b/src/est/test/set_wire_rc_chip_ignored.tcl @@ -0,0 +1,7 @@ +# set_wire_rc selectors matching no chip warn and are ignored +source "helpers.tcl" +read_lef Nangate45/Nangate45.lef +read_def reg3.def + +set_wire_rc -tech no_such_tech -resistance 1e-3 -capacitance 1e-1 +set_wire_rc -redistribution_layer -resistance 1e-3 -capacitance 1e-1 diff --git a/src/est/test/set_wire_rc_chip_select.ok b/src/est/test/set_wire_rc_chip_select.ok new file mode 100644 index 0000000000..5e2c8e6124 --- /dev/null +++ b/src/est/test/set_wire_rc_chip_select.ok @@ -0,0 +1,8 @@ +[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias, 135 library cells +[INFO ODB-0128] Design: reg1 +[INFO ODB-0130] Created 4 pins. +[INFO ODB-0131] Created 5 components and 27 component-terminals. +[INFO ODB-0132] Created 2 special nets and 10 connections. +[INFO ODB-0133] Created 8 nets and 14 connections. +[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias +selectors applied diff --git a/src/est/test/set_wire_rc_chip_select.tcl b/src/est/test/set_wire_rc_chip_select.tcl new file mode 100644 index 0000000000..e98605fe87 --- /dev/null +++ b/src/est/test/set_wire_rc_chip_select.tcl @@ -0,0 +1,14 @@ +# set_wire_rc -chip/-tech/-redistribution_layer select chips in a multi-chip db +source "helpers.tcl" +read_lef Nangate45/Nangate45.lef +read_liberty Nangate45/Nangate45_typ.lib +read_def reg3.def + +read_lef -tech -tech_name tech2 Nangate45/Nangate45.lef +set db [ord::get_db] +odb::dbChip_create $db [$db findTech tech2] "chip2" "RDL" + +set_wire_rc -chip chip2 -resistance 1e-3 -capacitance 1e-1 +set_wire_rc -tech tech2 -layer metal3 +set_wire_rc -redistribution_layer -resistance 2e-3 -capacitance 2e-1 +puts "selectors applied" diff --git a/src/est/test/set_wire_rc_rdl_mixed_tech.ok b/src/est/test/set_wire_rc_rdl_mixed_tech.ok new file mode 100644 index 0000000000..a128f18d4f --- /dev/null +++ b/src/est/test/set_wire_rc_rdl_mixed_tech.ok @@ -0,0 +1,9 @@ +[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias, 135 library cells +[INFO ODB-0128] Design: reg1 +[INFO ODB-0130] Created 4 pins. +[INFO ODB-0131] Created 5 components and 27 component-terminals. +[INFO ODB-0132] Created 2 special nets and 10 connections. +[INFO ODB-0133] Created 8 nets and 14 connections. +[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias +[ERROR EST-0032] -layer and -layers require chips that share one technology; set each chip separately with -chip. +EST-0032 diff --git a/src/est/test/set_wire_rc_rdl_mixed_tech.tcl b/src/est/test/set_wire_rc_rdl_mixed_tech.tcl new file mode 100644 index 0000000000..5dc2055aef --- /dev/null +++ b/src/est/test/set_wire_rc_rdl_mixed_tech.tcl @@ -0,0 +1,16 @@ +# set_wire_rc -redistribution_layer with RDL chips on different technologies +source "helpers.tcl" +read_lef Nangate45/Nangate45.lef +read_liberty Nangate45/Nangate45_typ.lib +read_def reg3.def + +read_lef -tech -tech_name tech2 Nangate45/Nangate45.lef +set db [ord::get_db] +odb::dbChip_create $db [$db findTech tech2] "rdl_a" "RDL" +odb::dbChip_create $db [$db findTech Nangate45] "rdl_b" "RDL" + +# explicit values apply to both RDL chips +set_wire_rc -redistribution_layer -resistance 2e-3 -capacitance 2e-1 +# a shared layer cannot be resolved across different technologies +catch { set_wire_rc -redistribution_layer -layer metal3 } msg +puts $msg From 28d6b90143bb02f9f747560fb09589242b260b5f Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 14:39:10 -0300 Subject: [PATCH 10/17] est: rename wireRCVector to resolveWireRC Signed-off-by: Eder Monteiro --- src/est/include/est/EstimateParasitics.h | 10 ++++---- src/est/src/EstimateParasitics.cpp | 32 ++++++++++++------------ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/est/include/est/EstimateParasitics.h b/src/est/include/est/EstimateParasitics.h index f957c83cf4..cd64d5fe81 100644 --- a/src/est/include/est/EstimateParasitics.h +++ b/src/est/include/est/EstimateParasitics.h @@ -233,18 +233,18 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService // Resolve one WireRC category for the current chip; a category left unset // for a chip falls back to the defaults (nullptr entry) independently. template - const std::vector& wireRCVector(std::vector WireRC::*member) const + const std::vector& resolveWireRC(std::vector WireRC::*category) const { static const std::vector empty; odb::dbChip* chip = currentChip(); auto it = wire_rc_.find(chip); - if (it != wire_rc_.end() && !(it->second.*member).empty()) { - return it->second.*member; + if (it != wire_rc_.end() && !(it->second.*category).empty()) { + return it->second.*category; } if (chip != nullptr) { it = wire_rc_.find(nullptr); - if (it != wire_rc_.end() && !(it->second.*member).empty()) { - return it->second.*member; + if (it != wire_rc_.end() && !(it->second.*category).empty()) { + return it->second.*category; } } return empty; diff --git a/src/est/src/EstimateParasitics.cpp b/src/est/src/EstimateParasitics.cpp index 16f2bb2d35..eee654de5c 100644 --- a/src/est/src/EstimateParasitics.cpp +++ b/src/est/src/EstimateParasitics.cpp @@ -195,7 +195,7 @@ void EstimateParasitics::setVWireSignalRC(odb::dbChip* chip, double EstimateParasitics::wireSignalResistance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::signal_res); + const auto& values = resolveWireRC(&WireRC::signal_res); if (values.empty()) { return 0.0; } @@ -204,7 +204,7 @@ double EstimateParasitics::wireSignalResistance(const sta::Scene* scene) const double EstimateParasitics::wireSignalHResistance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::signal_res); + const auto& values = resolveWireRC(&WireRC::signal_res); if (values.empty()) { return 0.0; } @@ -213,7 +213,7 @@ double EstimateParasitics::wireSignalHResistance(const sta::Scene* scene) const double EstimateParasitics::wireSignalVResistance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::signal_res); + const auto& values = resolveWireRC(&WireRC::signal_res); if (values.empty()) { return 0.0; } @@ -222,7 +222,7 @@ double EstimateParasitics::wireSignalVResistance(const sta::Scene* scene) const double EstimateParasitics::wireSignalCapacitance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::signal_cap); + const auto& values = resolveWireRC(&WireRC::signal_cap); if (values.empty()) { return 0.0; } @@ -231,7 +231,7 @@ double EstimateParasitics::wireSignalCapacitance(const sta::Scene* scene) const double EstimateParasitics::wireSignalHCapacitance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::signal_cap); + const auto& values = resolveWireRC(&WireRC::signal_cap); if (values.empty()) { return 0.0; } @@ -240,7 +240,7 @@ double EstimateParasitics::wireSignalHCapacitance(const sta::Scene* scene) const double EstimateParasitics::wireSignalVCapacitance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::signal_cap); + const auto& values = resolveWireRC(&WireRC::signal_cap); if (values.empty()) { return 0.0; } @@ -252,8 +252,8 @@ void EstimateParasitics::wireSignalRC(const sta::Scene* scene, double& res, double& cap) const { - const auto& resistance = wireRCVector(&WireRC::signal_res); - const auto& capacitance = wireRCVector(&WireRC::signal_cap); + const auto& resistance = resolveWireRC(&WireRC::signal_res); + const auto& capacitance = resolveWireRC(&WireRC::signal_cap); res = resistance.empty() ? 0.0 : (resistance[scene->index()].h_res + resistance[scene->index()].v_res) @@ -290,7 +290,7 @@ void EstimateParasitics::setVWireClkRC(odb::dbChip* chip, double EstimateParasitics::wireClkResistance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::clk_res); + const auto& values = resolveWireRC(&WireRC::clk_res); if (values.empty()) { return 0.0; } @@ -299,7 +299,7 @@ double EstimateParasitics::wireClkResistance(const sta::Scene* scene) const double EstimateParasitics::wireClkHResistance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::clk_res); + const auto& values = resolveWireRC(&WireRC::clk_res); if (values.empty()) { return 0.0; } @@ -308,7 +308,7 @@ double EstimateParasitics::wireClkHResistance(const sta::Scene* scene) const double EstimateParasitics::wireClkVResistance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::clk_res); + const auto& values = resolveWireRC(&WireRC::clk_res); if (values.empty()) { return 0.0; } @@ -317,7 +317,7 @@ double EstimateParasitics::wireClkVResistance(const sta::Scene* scene) const double EstimateParasitics::wireClkCapacitance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::clk_cap); + const auto& values = resolveWireRC(&WireRC::clk_cap); if (values.empty()) { return 0.0; } @@ -326,7 +326,7 @@ double EstimateParasitics::wireClkCapacitance(const sta::Scene* scene) const double EstimateParasitics::wireClkHCapacitance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::clk_cap); + const auto& values = resolveWireRC(&WireRC::clk_cap); if (values.empty()) { return 0.0; } @@ -335,7 +335,7 @@ double EstimateParasitics::wireClkHCapacitance(const sta::Scene* scene) const double EstimateParasitics::wireClkVCapacitance(const sta::Scene* scene) const { - const auto& values = wireRCVector(&WireRC::clk_cap); + const auto& values = resolveWireRC(&WireRC::clk_cap); if (values.empty()) { return 0.0; } @@ -628,7 +628,7 @@ void EstimateParasitics::clearParasitics() void EstimateParasitics::estimateWireParasitics(sta::SpefWriter* spef_writer) { initBlock(); - if (!wireRCVector(&WireRC::signal_cap).empty()) { + if (!resolveWireRC(&WireRC::signal_cap).empty()) { for (auto mode : sta_->modes()) { sta_->ensureClkNetwork(mode); } @@ -987,7 +987,7 @@ void EstimateParasitics::parasiticNodeConnectPins( const sta::PinSeq* pins = tree->pins(pt); if (pins) { const auto& layers - = wireRCVector(is_clk ? &WireRC::clk_layers : &WireRC::signal_layers); + = resolveWireRC(is_clk ? &WireRC::clk_layers : &WireRC::signal_layers); odb::dbTechLayer* tree_layer = layers.empty() ? nullptr : layers[0]; for (const sta::Pin* pin : *pins) { From 9bb6cc3b6253f469539e6ebbd182154c78c57467 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 14:46:22 -0300 Subject: [PATCH 11/17] est: move resolveWireRC definition out of the header Signed-off-by: Eder Monteiro --- src/est/include/est/EstimateParasitics.h | 17 +---------------- src/est/src/EstimateParasitics.cpp | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/est/include/est/EstimateParasitics.h b/src/est/include/est/EstimateParasitics.h index cd64d5fe81..29416e829d 100644 --- a/src/est/include/est/EstimateParasitics.h +++ b/src/est/include/est/EstimateParasitics.h @@ -233,22 +233,7 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService // Resolve one WireRC category for the current chip; a category left unset // for a chip falls back to the defaults (nullptr entry) independently. template - const std::vector& resolveWireRC(std::vector WireRC::*category) const - { - static const std::vector empty; - odb::dbChip* chip = currentChip(); - auto it = wire_rc_.find(chip); - if (it != wire_rc_.end() && !(it->second.*category).empty()) { - return it->second.*category; - } - if (chip != nullptr) { - it = wire_rc_.find(nullptr); - if (it != wire_rc_.end() && !(it->second.*category).empty()) { - return it->second.*category; - } - } - return empty; - } + const std::vector& resolveWireRC(std::vector WireRC::*category) const; void ensureParasitics(); bool isIdealClockPin(const sta::Pin* pin) const; bool isIdealClockNet(const sta::Net* net) const; diff --git a/src/est/src/EstimateParasitics.cpp b/src/est/src/EstimateParasitics.cpp index eee654de5c..0229d9cb61 100644 --- a/src/est/src/EstimateParasitics.cpp +++ b/src/est/src/EstimateParasitics.cpp @@ -193,6 +193,26 @@ void EstimateParasitics::setVWireSignalRC(odb::dbChip* chip, wire_rc.signal_cap[scene->index()].v_cap = cap; } +// Defined outside the header; all instantiations live in this file. +template +const std::vector& EstimateParasitics::resolveWireRC( + std::vector WireRC::*category) const +{ + static const std::vector empty; + odb::dbChip* chip = currentChip(); + auto it = wire_rc_.find(chip); + if (it != wire_rc_.end() && !(it->second.*category).empty()) { + return it->second.*category; + } + if (chip != nullptr) { + it = wire_rc_.find(nullptr); + if (it != wire_rc_.end() && !(it->second.*category).empty()) { + return it->second.*category; + } + } + return empty; +} + double EstimateParasitics::wireSignalResistance(const sta::Scene* scene) const { const auto& values = resolveWireRC(&WireRC::signal_res); From 87e16b304a8965af4fd8469e3902d648aa0c88c5 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 15:00:35 -0300 Subject: [PATCH 12/17] est: consolidate helper procs into one namespace eval block Signed-off-by: Eder Monteiro --- src/est/src/EstimateParasitics.tcl | 178 ++++++++++++++--------------- 1 file changed, 85 insertions(+), 93 deletions(-) diff --git a/src/est/src/EstimateParasitics.tcl b/src/est/src/EstimateParasitics.tcl index 9dac33fd32..b685b9be63 100644 --- a/src/est/src/EstimateParasitics.tcl +++ b/src/est/src/EstimateParasitics.tcl @@ -1,18 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2019-2025, The OpenROAD Authors -namespace eval est { -proc get_db_tech_checked { } { - set tech [ord::get_db_tech] - if { $tech == "NULL" } { - utl::error EST 210 "No technology loaded." - } - return $tech -} - -# namespace eval est -} - sta::define_cmd_args "estimate_parasitics" { -placement|-global_routing \ [-spef_file filename]} @@ -185,87 +173,6 @@ proc report_layer_rc { args } { puts "----------------------------" } -namespace eval est { -# Chips targeted by -chip/-tech/-redistribution_layer; empty with -# has_selector unset means the default values shared by chips without -# specific values, empty with has_selector set means nothing to do. -proc parse_wire_rc_chips { keys_var flags_var selector_var } { - upvar 1 $keys_var keys - upvar 1 $flags_var flags - upvar 1 $selector_var has_selector - - set selector_count [expr { - [info exists keys(-tech)] + [info exists keys(-chip)] - + [info exists flags(-redistribution_layer)] - }] - if { $selector_count > 1 } { - utl::error EST 28 "Use only one of -tech, -chip or -redistribution_layer." - } - set has_selector [expr { $selector_count > 0 }] - - set db [ord::get_db] - set target_chips {} - if { [info exists keys(-chip)] } { - set chip [$db findChip $keys(-chip)] - if { $chip == "NULL" } { - utl::error EST 29 "chip $keys(-chip) not found." - } - lappend target_chips $chip - } elseif { [info exists keys(-tech)] } { - foreach chip [$db getChips] { - set chip_tech [$chip getTech] - if { $chip_tech != "NULL" && [$chip_tech getName] == $keys(-tech) } { - lappend target_chips $chip - } - } - if { [llength $target_chips] == 0 } { - utl::warn EST 30 "no chip uses technology $keys(-tech); values ignored." - } - } elseif { [info exists flags(-redistribution_layer)] } { - foreach chip [$db getChips] { - if { [$chip getChipType] == "RDL" } { - lappend target_chips $chip - } - } - if { [llength $target_chips] == 0 } { - utl::warn EST 31 "design has no RDL chip; values ignored." - } - } - return $target_chips -} - -# Layer lookups use the targeted chips' technology when one is selected; -# layers cannot be resolved for chips with different technologies. -proc wire_rc_tech { chips } { - if { [llength $chips] > 0 } { - set tech [[lindex $chips 0] getTech] - foreach chip $chips { - if { [$chip getTech] != $tech } { - utl::error EST 32 "-layer and -layers require chips that share one\ - technology; set each chip separately with -chip." - } - } - if { $tech != "NULL" } { - return $tech - } - } - return [est::get_db_tech_checked] -} - -proc add_wire_rc_layers { chips clk signal layer } { - foreach chip $chips { - if { $clk || !$signal } { - est::add_clk_layer_cmd $chip $layer - } - if { $signal || !$clk } { - est::add_signal_layer_cmd $chip $layer - } - } -} - -# namespace eval est -} - sta::define_cmd_args "set_wire_rc" {[-clock] [-signal] [-data]\ [-layers layers]\ [-layer layer]\ @@ -478,6 +385,14 @@ proc set_wire_rc { args } { } namespace eval est { +proc get_db_tech_checked { } { + set tech [ord::get_db_tech] + if { $tech == "NULL" } { + utl::error EST 210 "No technology loaded." + } + return $tech +} + proc check_corner_wire_caps { } { set have_rc 1 foreach corner [sta::scenes] { @@ -532,5 +447,82 @@ proc set_dbvia_wire_r { layer res } { $layer setResistance $res } +# Chips targeted by -chip/-tech/-redistribution_layer; empty with +# has_selector unset means the default values shared by chips without +# specific values, empty with has_selector set means nothing to do. +proc parse_wire_rc_chips { keys_var flags_var selector_var } { + upvar 1 $keys_var keys + upvar 1 $flags_var flags + upvar 1 $selector_var has_selector + + set selector_count [expr { + [info exists keys(-tech)] + [info exists keys(-chip)] + + [info exists flags(-redistribution_layer)] + }] + if { $selector_count > 1 } { + utl::error EST 28 "Use only one of -tech, -chip or -redistribution_layer." + } + set has_selector [expr { $selector_count > 0 }] + + set db [ord::get_db] + set target_chips {} + if { [info exists keys(-chip)] } { + set chip [$db findChip $keys(-chip)] + if { $chip == "NULL" } { + utl::error EST 29 "chip $keys(-chip) not found." + } + lappend target_chips $chip + } elseif { [info exists keys(-tech)] } { + foreach chip [$db getChips] { + set chip_tech [$chip getTech] + if { $chip_tech != "NULL" && [$chip_tech getName] == $keys(-tech) } { + lappend target_chips $chip + } + } + if { [llength $target_chips] == 0 } { + utl::warn EST 30 "no chip uses technology $keys(-tech); values ignored." + } + } elseif { [info exists flags(-redistribution_layer)] } { + foreach chip [$db getChips] { + if { [$chip getChipType] == "RDL" } { + lappend target_chips $chip + } + } + if { [llength $target_chips] == 0 } { + utl::warn EST 31 "design has no RDL chip; values ignored." + } + } + return $target_chips +} + +# Layer lookups use the targeted chips' technology when one is selected; +# layers cannot be resolved for chips with different technologies. +proc wire_rc_tech { chips } { + if { [llength $chips] > 0 } { + set tech [[lindex $chips 0] getTech] + foreach chip $chips { + if { [$chip getTech] != $tech } { + utl::error EST 32 "-layer and -layers require chips that share one\ + technology; set each chip separately with -chip." + } + } + if { $tech != "NULL" } { + return $tech + } + } + return [est::get_db_tech_checked] +} + +proc add_wire_rc_layers { chips clk signal layer } { + foreach chip $chips { + if { $clk || !$signal } { + est::add_clk_layer_cmd $chip $layer + } + if { $signal || !$clk } { + est::add_signal_layer_cmd $chip $layer + } + } +} + # namespace } From a64f5761c0c164297dfd7b674225d260707fbb0f Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 15:10:24 -0300 Subject: [PATCH 13/17] est: clarify the parse_wire_rc_chips comment Signed-off-by: Eder Monteiro --- src/est/src/EstimateParasitics.tcl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/est/src/EstimateParasitics.tcl b/src/est/src/EstimateParasitics.tcl index b685b9be63..177644b1b9 100644 --- a/src/est/src/EstimateParasitics.tcl +++ b/src/est/src/EstimateParasitics.tcl @@ -447,9 +447,9 @@ proc set_dbvia_wire_r { layer res } { $layer setResistance $res } -# Chips targeted by -chip/-tech/-redistribution_layer; empty with -# has_selector unset means the default values shared by chips without -# specific values, empty with has_selector set means nothing to do. +# Return the chips selected by -chip/-tech/-redistribution_layer, setting +# has_selector in the caller. An empty result means "set the shared +# defaults" when no selector was given and "nothing to do" when one was. proc parse_wire_rc_chips { keys_var flags_var selector_var } { upvar 1 $keys_var keys upvar 1 $flags_var flags From 2140f52d0c22a91f7be2d04de0d64a20234f5755 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 15:25:51 -0300 Subject: [PATCH 14/17] est: name wire RC getter locals after their category Signed-off-by: Eder Monteiro --- src/est/src/EstimateParasitics.cpp | 80 ++++++++++++++++-------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/src/est/src/EstimateParasitics.cpp b/src/est/src/EstimateParasitics.cpp index 0229d9cb61..4ceaf6ae49 100644 --- a/src/est/src/EstimateParasitics.cpp +++ b/src/est/src/EstimateParasitics.cpp @@ -148,13 +148,15 @@ odb::dbChip* EstimateParasitics::currentChip() const void EstimateParasitics::addClkLayer(odb::dbChip* chip, odb::dbTechLayer* layer) { - wireRC(chip).clk_layers.push_back(layer); + WireRC& wire_rc = wireRC(chip); + wire_rc.clk_layers.push_back(layer); } void EstimateParasitics::addSignalLayer(odb::dbChip* chip, odb::dbTechLayer* layer) { - wireRC(chip).signal_layers.push_back(layer); + WireRC& wire_rc = wireRC(chip); + wire_rc.signal_layers.push_back(layer); } void EstimateParasitics::sortClkAndSignalLayers() @@ -215,56 +217,58 @@ const std::vector& EstimateParasitics::resolveWireRC( double EstimateParasitics::wireSignalResistance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::signal_res); - if (values.empty()) { + const auto& signal_res = resolveWireRC(&WireRC::signal_res); + if (signal_res.empty()) { return 0.0; } - return (values[scene->index()].h_res + values[scene->index()].v_res) / 2; + return (signal_res[scene->index()].h_res + signal_res[scene->index()].v_res) + / 2; } double EstimateParasitics::wireSignalHResistance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::signal_res); - if (values.empty()) { + const auto& signal_res = resolveWireRC(&WireRC::signal_res); + if (signal_res.empty()) { return 0.0; } - return values[scene->index()].h_res; + return signal_res[scene->index()].h_res; } double EstimateParasitics::wireSignalVResistance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::signal_res); - if (values.empty()) { + const auto& signal_res = resolveWireRC(&WireRC::signal_res); + if (signal_res.empty()) { return 0.0; } - return values[scene->index()].v_res; + return signal_res[scene->index()].v_res; } double EstimateParasitics::wireSignalCapacitance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::signal_cap); - if (values.empty()) { + const auto& signal_cap = resolveWireRC(&WireRC::signal_cap); + if (signal_cap.empty()) { return 0.0; } - return (values[scene->index()].h_cap + values[scene->index()].v_cap) / 2; + return (signal_cap[scene->index()].h_cap + signal_cap[scene->index()].v_cap) + / 2; } double EstimateParasitics::wireSignalHCapacitance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::signal_cap); - if (values.empty()) { + const auto& signal_cap = resolveWireRC(&WireRC::signal_cap); + if (signal_cap.empty()) { return 0.0; } - return values[scene->index()].h_cap; + return signal_cap[scene->index()].h_cap; } double EstimateParasitics::wireSignalVCapacitance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::signal_cap); - if (values.empty()) { + const auto& signal_cap = resolveWireRC(&WireRC::signal_cap); + if (signal_cap.empty()) { return 0.0; } - return values[scene->index()].v_cap; + return signal_cap[scene->index()].v_cap; } void EstimateParasitics::wireSignalRC(const sta::Scene* scene, @@ -310,56 +314,56 @@ void EstimateParasitics::setVWireClkRC(odb::dbChip* chip, double EstimateParasitics::wireClkResistance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::clk_res); - if (values.empty()) { + const auto& clk_res = resolveWireRC(&WireRC::clk_res); + if (clk_res.empty()) { return 0.0; } - return (values[scene->index()].h_res + values[scene->index()].v_res) / 2; + return (clk_res[scene->index()].h_res + clk_res[scene->index()].v_res) / 2; } double EstimateParasitics::wireClkHResistance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::clk_res); - if (values.empty()) { + const auto& clk_res = resolveWireRC(&WireRC::clk_res); + if (clk_res.empty()) { return 0.0; } - return values[scene->index()].h_res; + return clk_res[scene->index()].h_res; } double EstimateParasitics::wireClkVResistance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::clk_res); - if (values.empty()) { + const auto& clk_res = resolveWireRC(&WireRC::clk_res); + if (clk_res.empty()) { return 0.0; } - return values[scene->index()].v_res; + return clk_res[scene->index()].v_res; } double EstimateParasitics::wireClkCapacitance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::clk_cap); - if (values.empty()) { + const auto& clk_cap = resolveWireRC(&WireRC::clk_cap); + if (clk_cap.empty()) { return 0.0; } - return (values[scene->index()].h_cap + values[scene->index()].v_cap) / 2; + return (clk_cap[scene->index()].h_cap + clk_cap[scene->index()].v_cap) / 2; } double EstimateParasitics::wireClkHCapacitance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::clk_cap); - if (values.empty()) { + const auto& clk_cap = resolveWireRC(&WireRC::clk_cap); + if (clk_cap.empty()) { return 0.0; } - return values[scene->index()].h_cap; + return clk_cap[scene->index()].h_cap; } double EstimateParasitics::wireClkVCapacitance(const sta::Scene* scene) const { - const auto& values = resolveWireRC(&WireRC::clk_cap); - if (values.empty()) { + const auto& clk_cap = resolveWireRC(&WireRC::clk_cap); + if (clk_cap.empty()) { return 0.0; } - return values[scene->index()].v_cap; + return clk_cap[scene->index()].v_cap; } //////////////////////////////////////////////////////////////// From bb93e33e4eec948567cf64c7ce5f0657ac0edcd4 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 19:53:28 -0300 Subject: [PATCH 15/17] est: key wire RC by technology instead of by chip Signed-off-by: Eder Monteiro --- src/est/README.md | 25 +++--- src/est/include/est/EstimateParasitics.h | 32 +++---- src/est/src/EstimateParasitics.cpp | 39 ++++---- src/est/src/EstimateParasitics.i | 24 ++--- src/est/src/EstimateParasitics.tcl | 109 ++++++++++------------- 5 files changed, 106 insertions(+), 123 deletions(-) diff --git a/src/est/README.md b/src/est/README.md index 2e2ec9c44a..e865245e0d 100644 --- a/src/est/README.md +++ b/src/est/README.md @@ -15,9 +15,9 @@ The `set_wire_rc` command sets the resistance and capacitance used to estimate delay of routing wires. Separate values can be specified for clock and data nets with the `-signal` and `-clock` flags. Without either `-signal` or `-clock` the resistance and capacitance for clocks and data nets are set. -In 3D designs the values can be targeted at specific chips with the `-tech`, -`-chip` and `-redistribution_layer` selectors; without a selector the values -are the defaults used by chips that have no chip-specific values. +In 3D designs the values can be targeted at a technology with the `-tech` and +`-redistribution_layer` selectors; without a selector the values are the +defaults used by chips whose technology has no specific values. ``` # Either run @@ -35,7 +35,6 @@ set_wire_rc [-corner corner] [-layers layers_list] [-tech tech] - [-chip chip] [-redistribution_layer] or @@ -45,7 +44,6 @@ set_wire_rc [-v_resistance res] [-v_capacitance cap] [-tech tech] - [-chip chip] [-redistribution_layer] or @@ -56,14 +54,12 @@ set_wire_rc [-corner corner] [-layer layer_name] [-tech tech] - [-chip chip] [-redistribution_layer] or set_wire_rc [-resistance res] [-capacitance cap] [-tech tech] - [-chip chip] [-redistribution_layer] ``` @@ -81,14 +77,13 @@ set_wire_rc | `-h_capacitance` | Capacitance per unit length for horizontal wires, units are from the first Liberty file read. | | `-v_resistance` | Resistance per unit length for vertical wires, units are from the first Liberty file read. | | `-v_capacitance` | Capacitance per unit length for vertical wires, units are from the first Liberty file read. | -| `-tech` | Apply the values to all chips using this technology (3D designs). Layers given with `-layer`/`-layers` are looked up in this technology. | -| `-chip` | Apply the values to the named chip only (3D designs). | -| `-redistribution_layer` | Apply the values to every RDL chip in the design, however many there are. Warns and does nothing when the design has none, so shared scripts work across designs. `-layer`/`-layers` require the selected RDL chips to share one technology; with mixed RDL technologies set each chip separately with `-chip`. | - -Without `-tech`, `-chip` or `-redistribution_layer` the values are the defaults -used by every chip that has no chip-specific values. Signal values, clock -values and routing layers fall back to the defaults independently, so a chip -with only chip-specific signal values still uses the default clock values. +| `-tech` | Apply the values to the named technology (3D designs). Layers given with `-layer`/`-layers` are looked up in this technology. | +| `-redistribution_layer` | Apply the values to the technology of every RDL chip in the design. Warns and does nothing when the design has none, so shared scripts work across designs. `-layer`/`-layers` require the RDL chips to share one technology; with mixed RDL technologies set each one separately with `-tech`. | + +Without `-tech` or `-redistribution_layer` the values are the defaults used by +every chip whose technology has no specific values. Signal values, clock values +and routing layers fall back to the defaults independently, so a technology with +only specific signal values still uses the default clock values. ### Set Layer RC diff --git a/src/est/include/est/EstimateParasitics.h b/src/est/include/est/EstimateParasitics.h index 29416e829d..7da2e624c3 100644 --- a/src/est/include/est/EstimateParasitics.h +++ b/src/est/include/est/EstimateParasitics.h @@ -100,30 +100,30 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService // Return values. double& res, double& cap) const; - // A null chip in the setters below writes the default values used by - // chips without chip-specific values. - void addClkLayer(odb::dbChip* chip, odb::dbTechLayer* layer); - void addSignalLayer(odb::dbChip* chip, odb::dbTechLayer* layer); + // A null tech in the setters below writes the default values used by + // chips whose technology has no specific values. + void addClkLayer(odb::dbTech* tech, odb::dbTechLayer* layer); + void addSignalLayer(odb::dbTech* tech, odb::dbTechLayer* layer); void sortClkAndSignalLayers(); // Set the resistance and capacitance used for horizontal parasitics on signal // nets. - void setHWireSignalRC(odb::dbChip* chip, + void setHWireSignalRC(odb::dbTech* tech, const sta::Scene* scene, double res, // ohms/meter double cap); // farads/meter // Set the resistance and capacitance used for vertical wires parasitics on // signal nets. - void setVWireSignalRC(odb::dbChip* chip, + void setVWireSignalRC(odb::dbTech* tech, const sta::Scene* scene, double res, // ohms/meter double cap); // farads/meter // Set the resistance and capacitance used for parasitics on clock nets. - void setHWireClkRC(odb::dbChip* chip, + void setHWireClkRC(odb::dbTech* tech, const sta::Scene* scene, double res, double cap); // farads/meter // Set the resistance and capacitance used for parasitics on clock nets. - void setVWireClkRC(odb::dbChip* chip, + void setVWireClkRC(odb::dbTech* tech, const sta::Scene* scene, double res, double cap); // farads/meter @@ -217,7 +217,7 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService utl::Logger* getLogger() { return logger_; } private: - // Wire RC values and layers of one chip, indexed by corner->index() + // Wire RC values and layers of one technology, indexed by corner->index() struct WireRC { std::vector signal_layers; @@ -228,10 +228,10 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService std::vector clk_cap; // Farads/meter }; - odb::dbChip* currentChip() const; - WireRC& wireRC(odb::dbChip* chip) { return wire_rc_[chip]; } - // Resolve one WireRC category for the current chip; a category left unset - // for a chip falls back to the defaults (nullptr entry) independently. + odb::dbTech* currentTech() const; + WireRC& wireRC(odb::dbTech* tech) { return wire_rc_[tech]; } + // Resolve one WireRC category for the current technology; a category left + // unset for a tech falls back to the defaults (nullptr entry) independently. template const std::vector& resolveWireRC(std::vector WireRC::*category) const; void ensureParasitics(); @@ -287,9 +287,9 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService layer_res_; // ohms/meter std::unordered_map> layer_cap_; // Farads/meter - // Wire RC per chip; the nullptr entry holds the defaults used by chips - // without chip-specific values - std::unordered_map wire_rc_; + // Wire RC per technology; the nullptr entry holds the defaults used by + // chips whose technology has no specific values + std::unordered_map wire_rc_; ParasiticsSrc parasitics_src_ = ParasiticsSrc::kNone; diff --git a/src/est/src/EstimateParasitics.cpp b/src/est/src/EstimateParasitics.cpp index 4ceaf6ae49..97ad69ce80 100644 --- a/src/est/src/EstimateParasitics.cpp +++ b/src/est/src/EstimateParasitics.cpp @@ -138,24 +138,25 @@ void EstimateParasitics::layerRC(odb::dbTechLayer* layer, //////////////////////////////////////////////////////////////// -odb::dbChip* EstimateParasitics::currentChip() const +odb::dbTech* EstimateParasitics::currentTech() const { if (block_ != nullptr) { - return block_->getChip(); + return block_->getTech(); } - return db_->getChip(); + odb::dbChip* chip = db_->getChip(); + return chip != nullptr ? chip->getTech() : nullptr; } -void EstimateParasitics::addClkLayer(odb::dbChip* chip, odb::dbTechLayer* layer) +void EstimateParasitics::addClkLayer(odb::dbTech* tech, odb::dbTechLayer* layer) { - WireRC& wire_rc = wireRC(chip); + WireRC& wire_rc = wireRC(tech); wire_rc.clk_layers.push_back(layer); } -void EstimateParasitics::addSignalLayer(odb::dbChip* chip, +void EstimateParasitics::addSignalLayer(odb::dbTech* tech, odb::dbTechLayer* layer) { - WireRC& wire_rc = wireRC(chip); + WireRC& wire_rc = wireRC(tech); wire_rc.signal_layers.push_back(layer); } @@ -165,30 +166,30 @@ void EstimateParasitics::sortClkAndSignalLayers() return a->getNumber() < b->getNumber(); }; - for (auto& [chip, wire_rc] : wire_rc_) { + for (auto& [tech, wire_rc] : wire_rc_) { std::ranges::sort(wire_rc.clk_layers, sort_layers); std::ranges::sort(wire_rc.signal_layers, sort_layers); } } -void EstimateParasitics::setHWireSignalRC(odb::dbChip* chip, +void EstimateParasitics::setHWireSignalRC(odb::dbTech* tech, const sta::Scene* scene, double res, double cap) { - WireRC& wire_rc = wireRC(chip); + WireRC& wire_rc = wireRC(tech); wire_rc.signal_res.resize(sta_->scenes().size()); wire_rc.signal_cap.resize(sta_->scenes().size()); wire_rc.signal_res[scene->index()].h_res = res; wire_rc.signal_cap[scene->index()].h_cap = cap; } -void EstimateParasitics::setVWireSignalRC(odb::dbChip* chip, +void EstimateParasitics::setVWireSignalRC(odb::dbTech* tech, const sta::Scene* scene, double res, double cap) { - WireRC& wire_rc = wireRC(chip); + WireRC& wire_rc = wireRC(tech); wire_rc.signal_res.resize(sta_->scenes().size()); wire_rc.signal_cap.resize(sta_->scenes().size()); wire_rc.signal_res[scene->index()].v_res = res; @@ -201,12 +202,12 @@ const std::vector& EstimateParasitics::resolveWireRC( std::vector WireRC::*category) const { static const std::vector empty; - odb::dbChip* chip = currentChip(); - auto it = wire_rc_.find(chip); + odb::dbTech* tech = currentTech(); + auto it = wire_rc_.find(tech); if (it != wire_rc_.end() && !(it->second.*category).empty()) { return it->second.*category; } - if (chip != nullptr) { + if (tech != nullptr) { it = wire_rc_.find(nullptr); if (it != wire_rc_.end() && !(it->second.*category).empty()) { return it->second.*category; @@ -288,24 +289,24 @@ void EstimateParasitics::wireSignalRC(const sta::Scene* scene, / 2; } -void EstimateParasitics::setHWireClkRC(odb::dbChip* chip, +void EstimateParasitics::setHWireClkRC(odb::dbTech* tech, const sta::Scene* scene, double res, double cap) { - WireRC& wire_rc = wireRC(chip); + WireRC& wire_rc = wireRC(tech); wire_rc.clk_res.resize(sta_->scenes().size()); wire_rc.clk_cap.resize(sta_->scenes().size()); wire_rc.clk_res[scene->index()].h_res = res; wire_rc.clk_cap[scene->index()].h_cap = cap; } -void EstimateParasitics::setVWireClkRC(odb::dbChip* chip, +void EstimateParasitics::setVWireClkRC(odb::dbTech* tech, const sta::Scene* scene, double res, double cap) { - WireRC& wire_rc = wireRC(chip); + WireRC& wire_rc = wireRC(tech); wire_rc.clk_res.resize(sta_->scenes().size()); wire_rc.clk_cap.resize(sta_->scenes().size()); wire_rc.clk_res[scene->index()].v_res = res; diff --git a/src/est/src/EstimateParasitics.i b/src/est/src/EstimateParasitics.i index e97d21490b..bb95049138 100644 --- a/src/est/src/EstimateParasitics.i +++ b/src/est/src/EstimateParasitics.i @@ -130,19 +130,19 @@ set_layer_rc_cmd(odb::dbTechLayer *layer, } void -add_clk_layer_cmd(odb::dbChip *chip, +add_clk_layer_cmd(odb::dbTech *tech, odb::dbTechLayer *layer) { est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->addClkLayer(chip, layer); + estimate_parasitics->addClkLayer(tech, layer); } void -add_signal_layer_cmd(odb::dbChip *chip, +add_signal_layer_cmd(odb::dbTech *tech, odb::dbTechLayer *layer) { est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->addSignalLayer(chip, layer); + estimate_parasitics->addSignalLayer(tech, layer); } double @@ -166,47 +166,47 @@ layer_capacitance(odb::dbTechLayer *layer, } void -set_h_wire_signal_rc_cmd(odb::dbChip *chip, +set_h_wire_signal_rc_cmd(odb::dbTech *tech, const Scene *corner, float res, float cap) { ensureLinked(); est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->setHWireSignalRC(chip, corner, res, cap); + estimate_parasitics->setHWireSignalRC(tech, corner, res, cap); } void -set_v_wire_signal_rc_cmd(odb::dbChip *chip, +set_v_wire_signal_rc_cmd(odb::dbTech *tech, const Scene *corner, float res, float cap) { ensureLinked(); est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->setVWireSignalRC(chip, corner, res, cap); + estimate_parasitics->setVWireSignalRC(tech, corner, res, cap); } void -set_h_wire_clk_rc_cmd(odb::dbChip *chip, +set_h_wire_clk_rc_cmd(odb::dbTech *tech, const Scene *corner, float res, float cap) { ensureLinked(); est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->setHWireClkRC(chip, corner, res, cap); + estimate_parasitics->setHWireClkRC(tech, corner, res, cap); } void -set_v_wire_clk_rc_cmd(odb::dbChip *chip, +set_v_wire_clk_rc_cmd(odb::dbTech *tech, const Scene *corner, float res, float cap) { ensureLinked(); est::EstimateParasitics *estimate_parasitics = getEstimateParasitics(); - estimate_parasitics->setVWireClkRC(chip, corner, res, cap); + estimate_parasitics->setVWireClkRC(tech, corner, res, cap); } // ohms/meter diff --git a/src/est/src/EstimateParasitics.tcl b/src/est/src/EstimateParasitics.tcl index 177644b1b9..bc26a136f8 100644 --- a/src/est/src/EstimateParasitics.tcl +++ b/src/est/src/EstimateParasitics.tcl @@ -184,25 +184,24 @@ sta::define_cmd_args "set_wire_rc" {[-clock] [-signal] [-data]\ [-capacitance cap]\ [-corner corner]\ [-tech tech]\ - [-chip chip]\ [-redistribution_layer]} proc set_wire_rc { args } { sta::parse_key_args "set_wire_rc" args \ keys {-layer -layers -resistance -capacitance -corner \ -h_resistance -h_capacitance -v_resistance -v_capacitance \ - -tech -chip} \ + -tech} \ flags {-clock -signal -data -redistribution_layer} set corner [sta::parse_scene_or_null keys] - set target_chips [est::parse_wire_rc_chips keys flags has_selector] - if { $has_selector && [llength $target_chips] == 0 } { + set target_techs [est::parse_wire_rc_techs keys flags has_selector] + if { $has_selector && [llength $target_techs] == 0 } { return } - set chip_args $target_chips - if { [llength $chip_args] == 0 } { - set chip_args {NULL} + set tech_args $target_techs + if { [llength $tech_args] == 0 } { + set tech_args {NULL} } set h_wire_res 0.0 @@ -231,7 +230,7 @@ proc set_wire_rc { args } { set v_layers 0 set layers $keys(-layers) - set tech [est::wire_rc_tech $target_chips] + set tech [est::wire_rc_tech $target_techs] foreach layer_name $layers { set tec_layer [$tech findLayer $layer_name] @@ -262,7 +261,7 @@ proc set_wire_rc { args } { incr v_layers } - est::add_wire_rc_layers $chip_args [info exists flags(-clock)] \ + est::add_wire_rc_layers $tech_args [info exists flags(-clock)] \ [info exists flags(-signal)] $tec_layer } if { $h_layers == 0 } { @@ -278,7 +277,7 @@ proc set_wire_rc { args } { set v_wire_cap [expr $total_v_wire_cap / $v_layers] } elseif { [info exists keys(-layer)] } { set layer_name $keys(-layer) - set tec_layer [[est::wire_rc_tech $target_chips] findLayer $layer_name] + set tec_layer [[est::wire_rc_tech $target_techs] findLayer $layer_name] if { $tec_layer == "NULL" } { utl::error EST 15 "layer $tec_layer not found." } @@ -293,7 +292,7 @@ proc set_wire_rc { args } { set v_wire_cap [est::layer_capacitance $tec_layer $corner] } - est::add_wire_rc_layers $chip_args [info exists flags(-clock)] \ + est::add_wire_rc_layers $tech_args [info exists flags(-clock)] \ [info exists flags(-signal)] $tec_layer } else { ord::ensure_units_initialized @@ -371,14 +370,14 @@ proc set_wire_rc { args } { set corners [sta::scenes] } foreach corner $corners { - foreach chip $chip_args { + foreach tech $tech_args { if { $signal } { - est::set_h_wire_signal_rc_cmd $chip $corner $h_wire_res $h_wire_cap - est::set_v_wire_signal_rc_cmd $chip $corner $v_wire_res $v_wire_cap + est::set_h_wire_signal_rc_cmd $tech $corner $h_wire_res $h_wire_cap + est::set_v_wire_signal_rc_cmd $tech $corner $v_wire_res $v_wire_cap } if { $clk } { - est::set_h_wire_clk_rc_cmd $chip $corner $h_wire_res $h_wire_cap - est::set_v_wire_clk_rc_cmd $chip $corner $v_wire_res $v_wire_cap + est::set_h_wire_clk_rc_cmd $tech $corner $h_wire_res $h_wire_cap + est::set_v_wire_clk_rc_cmd $tech $corner $v_wire_res $v_wire_cap } } } @@ -447,79 +446,67 @@ proc set_dbvia_wire_r { layer res } { $layer setResistance $res } -# Return the chips selected by -chip/-tech/-redistribution_layer, setting -# has_selector in the caller. An empty result means "set the shared -# defaults" when no selector was given and "nothing to do" when one was. -proc parse_wire_rc_chips { keys_var flags_var selector_var } { +# Return the technologies selected by -tech/-redistribution_layer, setting +# has_selector in the caller. An empty result means "set the shared defaults" +# when no selector was given and "nothing to do" when one was. +proc parse_wire_rc_techs { keys_var flags_var selector_var } { upvar 1 $keys_var keys upvar 1 $flags_var flags upvar 1 $selector_var has_selector set selector_count [expr { - [info exists keys(-tech)] + [info exists keys(-chip)] - + [info exists flags(-redistribution_layer)] + [info exists keys(-tech)] + [info exists flags(-redistribution_layer)] }] if { $selector_count > 1 } { - utl::error EST 28 "Use only one of -tech, -chip or -redistribution_layer." + utl::error EST 28 "Use only one of -tech or -redistribution_layer." } set has_selector [expr { $selector_count > 0 }] set db [ord::get_db] - set target_chips {} - if { [info exists keys(-chip)] } { - set chip [$db findChip $keys(-chip)] - if { $chip == "NULL" } { - utl::error EST 29 "chip $keys(-chip) not found." - } - lappend target_chips $chip - } elseif { [info exists keys(-tech)] } { - foreach chip [$db getChips] { - set chip_tech [$chip getTech] - if { $chip_tech != "NULL" && [$chip_tech getName] == $keys(-tech) } { - lappend target_chips $chip - } - } - if { [llength $target_chips] == 0 } { - utl::warn EST 30 "no chip uses technology $keys(-tech); values ignored." + set target_techs {} + if { [info exists keys(-tech)] } { + set tech [$db findTech $keys(-tech)] + if { $tech == "NULL" } { + utl::error EST 30 "technology $keys(-tech) not found." } + lappend target_techs $tech } elseif { [info exists flags(-redistribution_layer)] } { foreach chip [$db getChips] { - if { [$chip getChipType] == "RDL" } { - lappend target_chips $chip + if { [$chip getChipType] != "RDL" } { + continue + } + set tech [$chip getTech] + if { $tech != "NULL" && [lsearch -exact $target_techs $tech] < 0 } { + lappend target_techs $tech } } - if { [llength $target_chips] == 0 } { + if { [llength $target_techs] == 0 } { utl::warn EST 31 "design has no RDL chip; values ignored." } } - return $target_chips + return $target_techs } -# Layer lookups use the targeted chips' technology when one is selected; -# layers cannot be resolved for chips with different technologies. -proc wire_rc_tech { chips } { - if { [llength $chips] > 0 } { - set tech [[lindex $chips 0] getTech] - foreach chip $chips { - if { [$chip getTech] != $tech } { - utl::error EST 32 "-layer and -layers require chips that share one\ - technology; set each chip separately with -chip." - } - } - if { $tech != "NULL" } { - return $tech - } +# Layer lookups use the targeted technology when one is selected; a layer +# cannot be resolved when the selection spans more than one technology. +proc wire_rc_tech { techs } { + if { [llength $techs] > 1 } { + utl::error EST 32 "-layer and -layers require a single technology; set\ + each technology separately with -tech." + } + if { [llength $techs] == 1 } { + return [lindex $techs 0] } return [est::get_db_tech_checked] } -proc add_wire_rc_layers { chips clk signal layer } { - foreach chip $chips { +proc add_wire_rc_layers { techs clk signal layer } { + foreach tech $techs { if { $clk || !$signal } { - est::add_clk_layer_cmd $chip $layer + est::add_clk_layer_cmd $tech $layer } if { $signal || !$clk } { - est::add_signal_layer_cmd $chip $layer + est::add_signal_layer_cmd $tech $layer } } } From e0b9e7f1c267d9f0f02ce3524184a33b0d380bbc Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Fri, 17 Jul 2026 19:53:38 -0300 Subject: [PATCH 16/17] est: retarget wire RC selector tests to technologies Signed-off-by: Eder Monteiro --- src/est/test/BUILD | 8 ++++---- src/est/test/CMakeLists.txt | 8 ++++---- src/est/test/cpp/TestEstimateParasitics.cc | 18 +++++++++--------- src/est/test/set_wire_rc_chip_errors.tcl | 11 ----------- ...p_ignored.ok => set_wire_rc_rdl_ignored.ok} | 1 - ...ignored.tcl => set_wire_rc_rdl_ignored.tcl} | 3 +-- src/est/test/set_wire_rc_rdl_mixed_tech.ok | 2 +- ...chip_select.ok => set_wire_rc_selectors.ok} | 0 ...ip_select.tcl => set_wire_rc_selectors.tcl} | 7 ++++--- ...set_wire_rc_chip.ok => set_wire_rc_tech.ok} | 0 ...t_wire_rc_chip.tcl => set_wire_rc_tech.tcl} | 0 ...ip_errors.ok => set_wire_rc_tech_errors.ok} | 6 +++--- src/est/test/set_wire_rc_tech_errors.tcl | 12 ++++++++++++ 13 files changed, 38 insertions(+), 38 deletions(-) delete mode 100644 src/est/test/set_wire_rc_chip_errors.tcl rename src/est/test/{set_wire_rc_chip_ignored.ok => set_wire_rc_rdl_ignored.ok} (84%) rename src/est/test/{set_wire_rc_chip_ignored.tcl => set_wire_rc_rdl_ignored.tcl} (52%) rename src/est/test/{set_wire_rc_chip_select.ok => set_wire_rc_selectors.ok} (100%) rename src/est/test/{set_wire_rc_chip_select.tcl => set_wire_rc_selectors.tcl} (58%) rename src/est/test/{set_wire_rc_chip.ok => set_wire_rc_tech.ok} (100%) rename src/est/test/{set_wire_rc_chip.tcl => set_wire_rc_tech.tcl} (100%) rename src/est/test/{set_wire_rc_chip_errors.ok => set_wire_rc_tech_errors.ok} (73%) create mode 100644 src/est/test/set_wire_rc_tech_errors.tcl diff --git a/src/est/test/BUILD b/src/est/test/BUILD index cb822fe22b..e73651a589 100644 --- a/src/est/test/BUILD +++ b/src/est/test/BUILD @@ -14,10 +14,10 @@ TESTS = [ "make_parasitics5", "make_parasitics6", "make_parasitics7", - "set_wire_rc_chip", - "set_wire_rc_chip_errors", - "set_wire_rc_chip_ignored", - "set_wire_rc_chip_select", + "set_wire_rc_tech", + "set_wire_rc_tech_errors", + "set_wire_rc_rdl_ignored", + "set_wire_rc_selectors", "set_wire_rc_rdl_mixed_tech", ] diff --git a/src/est/test/CMakeLists.txt b/src/est/test/CMakeLists.txt index 484b1edc13..5309e23356 100644 --- a/src/est/test/CMakeLists.txt +++ b/src/est/test/CMakeLists.txt @@ -10,10 +10,10 @@ or_integration_tests( make_parasitics5 make_parasitics6 make_parasitics7 - set_wire_rc_chip - set_wire_rc_chip_errors - set_wire_rc_chip_ignored - set_wire_rc_chip_select + set_wire_rc_tech + set_wire_rc_tech_errors + set_wire_rc_rdl_ignored + set_wire_rc_selectors set_wire_rc_rdl_mixed_tech ) diff --git a/src/est/test/cpp/TestEstimateParasitics.cc b/src/est/test/cpp/TestEstimateParasitics.cc index 374ba6a56f..74c768c15c 100644 --- a/src/est/test/cpp/TestEstimateParasitics.cc +++ b/src/est/test/cpp/TestEstimateParasitics.cc @@ -199,7 +199,7 @@ TEST_F(TestEstimateParasitics, ScanClockIdealOnlyInTestMode) // Verifies that wire RC values are stored per chip: chip-specific values take // precedence over the defaults, and chips without an entry use the defaults. -TEST_F(TestEstimateParasitics, WireRcPerChip) +TEST_F(TestEstimateParasitics, WireRcPerTech) { readVerilogAndSetup("TestEstimateParasitics.v"); @@ -207,7 +207,7 @@ TEST_F(TestEstimateParasitics, WireRcPerChip) odb::dbChip* chip1 = db_->getChip(); ASSERT_NE(chip1, nullptr); - // A null chip sets the default values used by chips without an entry. + // A null tech sets the default values used by techs without an entry. ep_.initChip(chip1); ep_.setHWireSignalRC(nullptr, scene, 1.0e3, 1.0e-10); ep_.setVWireSignalRC(nullptr, scene, 2.0e3, 2.0e-10); @@ -216,7 +216,7 @@ TEST_F(TestEstimateParasitics, WireRcPerChip) EXPECT_DOUBLE_EQ(ep_.wireSignalHResistance(scene), 1.0e3); EXPECT_DOUBLE_EQ(ep_.wireSignalVCapacitance(scene), 2.0e-10); - // A second chip on its own technology with chip-specific values. + // A second technology with tech-specific values, used by a second chip. loadTechAndLib( "tech2", "lib2", getFilePath("_main/test/Nangate45/Nangate45.lef")); odb::dbTech* tech2 = db_->findTech("tech2"); @@ -225,20 +225,20 @@ TEST_F(TestEstimateParasitics, WireRcPerChip) db_.get(), tech2, "chip2", odb::dbChip::ChipType::DIE); ASSERT_NE(chip2, nullptr); odb::dbBlock::create(chip2, "chip2_block"); - ep_.setHWireSignalRC(chip2, scene, 3.0e3, 3.0e-10); - ep_.setVWireSignalRC(chip2, scene, 4.0e3, 4.0e-10); + ep_.setHWireSignalRC(tech2, scene, 3.0e3, 3.0e-10); + ep_.setVWireSignalRC(tech2, scene, 4.0e3, 4.0e-10); - // The chip-specific values do not leak into the default-valued chip. + // The tech-specific values do not leak into the default-valued tech. EXPECT_DOUBLE_EQ(ep_.wireSignalHResistance(scene), 1.0e3); - // Rebinding to the second chip resolves its chip-specific signal values; - // its unset clock values fall back to the defaults independently. + // Rebinding to the second chip resolves tech2's signal values; its unset + // clock values fall back to the defaults independently. ep_.initChip(chip2); EXPECT_DOUBLE_EQ(ep_.wireSignalHResistance(scene), 3.0e3); EXPECT_DOUBLE_EQ(ep_.wireSignalVCapacitance(scene), 4.0e-10); EXPECT_DOUBLE_EQ(ep_.wireClkHResistance(scene), 5.0e3); - // Rebinding back to a chip without an entry falls back to the defaults. + // Rebinding back to a chip whose tech has no entry falls back to defaults. ep_.initChip(chip1); EXPECT_DOUBLE_EQ(ep_.wireSignalHResistance(scene), 1.0e3); EXPECT_DOUBLE_EQ(ep_.wireSignalVResistance(scene), 2.0e3); diff --git a/src/est/test/set_wire_rc_chip_errors.tcl b/src/est/test/set_wire_rc_chip_errors.tcl deleted file mode 100644 index 48621eaef1..0000000000 --- a/src/est/test/set_wire_rc_chip_errors.tcl +++ /dev/null @@ -1,11 +0,0 @@ -# set_wire_rc chip selector misuse errors -source "helpers.tcl" -read_lef Nangate45/Nangate45.lef -read_def reg3.def - -# unknown chip name is an error -catch { set_wire_rc -chip no_such_chip -resistance 1e-3 -capacitance 1e-1 } msg -puts $msg -# selectors are mutually exclusive -catch { set_wire_rc -tech Nangate45 -chip chip1 -resistance 1e-3 -capacitance 1e-1 } msg -puts $msg diff --git a/src/est/test/set_wire_rc_chip_ignored.ok b/src/est/test/set_wire_rc_rdl_ignored.ok similarity index 84% rename from src/est/test/set_wire_rc_chip_ignored.ok rename to src/est/test/set_wire_rc_rdl_ignored.ok index b53f94391c..f58b89b50c 100644 --- a/src/est/test/set_wire_rc_chip_ignored.ok +++ b/src/est/test/set_wire_rc_rdl_ignored.ok @@ -4,5 +4,4 @@ [INFO ODB-0131] Created 5 components and 27 component-terminals. [INFO ODB-0132] Created 2 special nets and 10 connections. [INFO ODB-0133] Created 8 nets and 14 connections. -[WARNING EST-0030] no chip uses technology no_such_tech; values ignored. [WARNING EST-0031] design has no RDL chip; values ignored. diff --git a/src/est/test/set_wire_rc_chip_ignored.tcl b/src/est/test/set_wire_rc_rdl_ignored.tcl similarity index 52% rename from src/est/test/set_wire_rc_chip_ignored.tcl rename to src/est/test/set_wire_rc_rdl_ignored.tcl index 1c14efb7c8..83a733936e 100644 --- a/src/est/test/set_wire_rc_chip_ignored.tcl +++ b/src/est/test/set_wire_rc_rdl_ignored.tcl @@ -1,7 +1,6 @@ -# set_wire_rc selectors matching no chip warn and are ignored +# set_wire_rc -redistribution_layer with no RDL chip warns and is ignored source "helpers.tcl" read_lef Nangate45/Nangate45.lef read_def reg3.def -set_wire_rc -tech no_such_tech -resistance 1e-3 -capacitance 1e-1 set_wire_rc -redistribution_layer -resistance 1e-3 -capacitance 1e-1 diff --git a/src/est/test/set_wire_rc_rdl_mixed_tech.ok b/src/est/test/set_wire_rc_rdl_mixed_tech.ok index a128f18d4f..a57d8babc8 100644 --- a/src/est/test/set_wire_rc_rdl_mixed_tech.ok +++ b/src/est/test/set_wire_rc_rdl_mixed_tech.ok @@ -5,5 +5,5 @@ [INFO ODB-0132] Created 2 special nets and 10 connections. [INFO ODB-0133] Created 8 nets and 14 connections. [INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias -[ERROR EST-0032] -layer and -layers require chips that share one technology; set each chip separately with -chip. +[ERROR EST-0032] -layer and -layers require a single technology; set each technology separately with -tech. EST-0032 diff --git a/src/est/test/set_wire_rc_chip_select.ok b/src/est/test/set_wire_rc_selectors.ok similarity index 100% rename from src/est/test/set_wire_rc_chip_select.ok rename to src/est/test/set_wire_rc_selectors.ok diff --git a/src/est/test/set_wire_rc_chip_select.tcl b/src/est/test/set_wire_rc_selectors.tcl similarity index 58% rename from src/est/test/set_wire_rc_chip_select.tcl rename to src/est/test/set_wire_rc_selectors.tcl index e98605fe87..a5ef263b38 100644 --- a/src/est/test/set_wire_rc_chip_select.tcl +++ b/src/est/test/set_wire_rc_selectors.tcl @@ -1,4 +1,4 @@ -# set_wire_rc -chip/-tech/-redistribution_layer select chips in a multi-chip db +# set_wire_rc -tech/-redistribution_layer target technologies in a multi-tech db source "helpers.tcl" read_lef Nangate45/Nangate45.lef read_liberty Nangate45/Nangate45_typ.lib @@ -6,9 +6,10 @@ read_def reg3.def read_lef -tech -tech_name tech2 Nangate45/Nangate45.lef set db [ord::get_db] -odb::dbChip_create $db [$db findTech tech2] "chip2" "RDL" +odb::dbChip_create $db [$db findTech tech2] "rdl" "RDL" -set_wire_rc -chip chip2 -resistance 1e-3 -capacitance 1e-1 +# a named technology, with layers resolved in that technology set_wire_rc -tech tech2 -layer metal3 +# every RDL chip's technology set_wire_rc -redistribution_layer -resistance 2e-3 -capacitance 2e-1 puts "selectors applied" diff --git a/src/est/test/set_wire_rc_chip.ok b/src/est/test/set_wire_rc_tech.ok similarity index 100% rename from src/est/test/set_wire_rc_chip.ok rename to src/est/test/set_wire_rc_tech.ok diff --git a/src/est/test/set_wire_rc_chip.tcl b/src/est/test/set_wire_rc_tech.tcl similarity index 100% rename from src/est/test/set_wire_rc_chip.tcl rename to src/est/test/set_wire_rc_tech.tcl diff --git a/src/est/test/set_wire_rc_chip_errors.ok b/src/est/test/set_wire_rc_tech_errors.ok similarity index 73% rename from src/est/test/set_wire_rc_chip_errors.ok rename to src/est/test/set_wire_rc_tech_errors.ok index 0af2b50288..f87f17a925 100644 --- a/src/est/test/set_wire_rc_chip_errors.ok +++ b/src/est/test/set_wire_rc_tech_errors.ok @@ -4,7 +4,7 @@ [INFO ODB-0131] Created 5 components and 27 component-terminals. [INFO ODB-0132] Created 2 special nets and 10 connections. [INFO ODB-0133] Created 8 nets and 14 connections. -[ERROR EST-0029] chip no_such_chip not found. -EST-0029 -[ERROR EST-0028] Use only one of -tech, -chip or -redistribution_layer. +[ERROR EST-0030] technology no_such_tech not found. +EST-0030 +[ERROR EST-0028] Use only one of -tech or -redistribution_layer. EST-0028 diff --git a/src/est/test/set_wire_rc_tech_errors.tcl b/src/est/test/set_wire_rc_tech_errors.tcl new file mode 100644 index 0000000000..03a19219c1 --- /dev/null +++ b/src/est/test/set_wire_rc_tech_errors.tcl @@ -0,0 +1,12 @@ +# set_wire_rc technology selector misuse errors +source "helpers.tcl" +read_lef Nangate45/Nangate45.lef +read_def reg3.def + +# unknown technology name is an error +catch { set_wire_rc -tech no_such_tech -resistance 1e-3 -capacitance 1e-1 } msg +puts $msg +# selectors are mutually exclusive +catch { set_wire_rc -tech Nangate45 -redistribution_layer \ + -resistance 1e-3 -capacitance 1e-1 } msg +puts $msg From 93c25f7cc77fb177c14b94f92338dc9fc0136d95 Mon Sep 17 00:00:00 2001 From: Eder Monteiro Date: Mon, 20 Jul 2026 21:21:24 -0300 Subject: [PATCH 17/17] est: format set_wire_rc_tech_errors catch block per tclfmt Signed-off-by: Eder Monteiro --- src/est/test/set_wire_rc_tech_errors.tcl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/est/test/set_wire_rc_tech_errors.tcl b/src/est/test/set_wire_rc_tech_errors.tcl index 03a19219c1..d03d6235d1 100644 --- a/src/est/test/set_wire_rc_tech_errors.tcl +++ b/src/est/test/set_wire_rc_tech_errors.tcl @@ -7,6 +7,8 @@ read_def reg3.def catch { set_wire_rc -tech no_such_tech -resistance 1e-3 -capacitance 1e-1 } msg puts $msg # selectors are mutually exclusive -catch { set_wire_rc -tech Nangate45 -redistribution_layer \ - -resistance 1e-3 -capacitance 1e-1 } msg +catch { + set_wire_rc -tech Nangate45 -redistribution_layer \ + -resistance 1e-3 -capacitance 1e-1 +} msg puts $msg