// OpenSTA, Static Timing Analyzer // Copyright (c) 2025, Parallax Software, Inc. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. // // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // This notice may not be removed or altered from any source distribution. #include "ConcreteParasitics.hh" #include // max #include "Report.hh" #include "Debug.hh" #include "Error.hh" #include "Mutex.hh" #include "MinMax.hh" #include "Network.hh" #include "Wireload.hh" #include "Liberty.hh" #include "Sdc.hh" #include "Parasitics.hh" #include "ConcreteParasiticsPvt.hh" #include "Scene.hh" // Multiple inheritance is used to share elmore and pi model base // classes, but care is taken to make sure there are no loops in the // inheritance graph (ConcreteParasitic only included once). namespace sta { using std::max; ConcreteParasitic::~ConcreteParasitic() { } bool ConcreteParasitic::isPiElmore() const { return false; } bool ConcreteParasitic::isPiModel() const { return false; } bool ConcreteParasitic::isPiPoleResidue() const { return false; } bool ConcreteParasitic::isPoleResidue() const { return false; } bool ConcreteParasitic::isParasiticNetwork() const { return false; } void ConcreteParasitic::piModel(float &, float &, float &) const { } void ConcreteParasitic::setPiModel(float, float, float) { } bool ConcreteParasitic::isReducedParasiticNetwork() const { return false; } void ConcreteParasitic::setIsReduced(bool) { } void ConcreteParasitic::findElmore(const Pin *, float &, bool &exists) const { exists = false; } void ConcreteParasitic::setElmore(const Pin *, float) { } Parasitic * ConcreteParasitic::findPoleResidue(const Pin *) const { return nullptr; } void ConcreteParasitic::setPoleResidue(const Pin *, ComplexFloatSeq *, ComplexFloatSeq *) { } //////////////////////////////////////////////////////////////// ConcretePi::ConcretePi(float c2, float rpi, float c1) : c2_(c2), rpi_(rpi), c1_(c1), is_reduced_(false) { } float ConcretePi::capacitance() const { return c1_ + c2_; } void ConcretePi::setPiModel(float c2, float rpi, float c1) { c2_ = c2; rpi_ = rpi; c1_ = c1; } void ConcretePi::piModel(float &c2, float &rpi, float &c1) const { c2 = c2_; rpi = rpi_; c1 = c1_; } void ConcretePi::setIsReduced(bool reduced) { is_reduced_ = reduced; } //////////////////////////////////////////////////////////////// ConcretePiElmore::ConcretePiElmore(float c2, float rpi, float c1) : ConcretePi(c2, rpi, c1) { } float ConcretePiElmore::capacitance() const { return ConcretePi::capacitance(); } void ConcretePiElmore::piModel(float &c2, float &rpi, float &c1) const { ConcretePi::piModel(c2, rpi, c1); } void ConcretePiElmore::setPiModel(float c2, float rpi, float c1) { ConcretePi::setPiModel(c2, rpi, c1); } bool ConcretePiElmore::isReducedParasiticNetwork() const { return ConcretePi::isReducedParasiticNetwork(); } void ConcretePiElmore::setIsReduced(bool reduced) { ConcretePi::setIsReduced(reduced); } void ConcretePiElmore::findElmore(const Pin *load_pin, float &elmore, bool &exists) const { auto itr = loads_.find(load_pin); if (itr == loads_.end()) exists = false; else { elmore = itr->second; exists = true; } } void ConcretePiElmore::setElmore(const Pin *load_pin, float elmore) { loads_[load_pin] = elmore; } void ConcretePiElmore::deleteLoad(const Pin *load_pin) { loads_.erase(load_pin); } PinSet ConcretePiElmore::unannotatedLoads(const Pin *drvr_pin, const Parasitics *parasitics) const { PinSet loads = parasitics->loads(drvr_pin); for (const auto [load, elmore] : loads_) loads.erase(load); return loads; } //////////////////////////////////////////////////////////////// ConcretePoleResidue::ConcretePoleResidue() : poles_(nullptr), residues_(nullptr) { } ConcretePoleResidue::~ConcretePoleResidue() { delete poles_; delete residues_; } size_t ConcretePoleResidue::poleResidueCount() const { return poles_->size(); } void ConcretePoleResidue::poleResidue(int index, ComplexFloat &pole, ComplexFloat &residue) const { pole = (*poles_)[index]; residue = (*residues_)[index]; } void ConcretePoleResidue::setPoleResidue(ComplexFloatSeq *poles, ComplexFloatSeq *residues) { poles_ = poles; residues_ = residues; } PinSet ConcretePoleResidue::unannotatedLoads(const Pin *, const Parasitics *) const { return PinSet(); } //////////////////////////////////////////////////////////////// ConcretePiPoleResidue::ConcretePiPoleResidue(float c2, float rpi, float c1) : ConcretePi(c2, rpi, c1) { } float ConcretePiPoleResidue::capacitance() const { return ConcretePi::capacitance(); } void ConcretePiPoleResidue::piModel(float &c2, float &rpi, float &c1) const { ConcretePi::piModel(c2, rpi, c1); } void ConcretePiPoleResidue::setPiModel(float c2, float rpi, float c1) { ConcretePi::setPiModel(c2, rpi, c1); } bool ConcretePiPoleResidue::isReducedParasiticNetwork() const { return ConcretePi::isReducedParasiticNetwork(); } void ConcretePiPoleResidue::setIsReduced(bool reduced) { ConcretePi::setIsReduced(reduced); } Parasitic * ConcretePiPoleResidue::findPoleResidue(const Pin *load_pin) const { auto itr = load_pole_residue_.find(load_pin); if (itr == load_pole_residue_.end()) return nullptr; else return &const_cast(itr->second); } void ConcretePiPoleResidue::setPoleResidue(const Pin *load_pin, ComplexFloatSeq *poles, ComplexFloatSeq *residues) { ConcretePoleResidue &pole_residue = load_pole_residue_[load_pin]; pole_residue.setPoleResidue(poles, residues); } void ConcretePiPoleResidue::deleteLoad(const Pin *load_pin) { load_pole_residue_.erase(load_pin); } PinSet ConcretePiPoleResidue::unannotatedLoads(const Pin *drvr_pin, const Parasitics *parasitics) const { PinSet loads = parasitics->loads(drvr_pin); for (const auto& [load, pole_residue] : load_pole_residue_) loads.erase(load); return loads; } //////////////////////////////////////////////////////////////// ConcreteParasiticNode::ConcreteParasiticNode(const Net *net, int id, bool is_external) : is_net_(true), is_external_(is_external), id_(id), cap_(0.0) { net_pin_.net_ = net; } ConcreteParasiticNode::ConcreteParasiticNode(const Pin *pin, bool is_external) : is_net_(false), is_external_(is_external), id_(0), cap_(0.0) { net_pin_.pin_ = pin; } void ConcreteParasiticNode::incrCapacitance(float cap) { cap_ += cap; } const char * ConcreteParasiticNode::name(const Network *network) const { if (is_net_) { const char *net_name = network->pathName(net_pin_.net_); return stringPrintTmp("%s:%d", net_name, id_); } else return network->pathName(net_pin_.pin_); } const Pin * ConcreteParasiticNode::pin() const { if (is_net_) return nullptr; else return net_pin_.pin_; } const Net * ConcreteParasiticNode::net(const Network *network) const { if (is_net_) return net_pin_.net_; else { Net *net = network->net(net_pin_.pin_); // Pins on the top level instance may not have nets. // Use the net connected to the pin's terminal. if (net == nullptr && network->isTopLevelPort(net_pin_.pin_)) { Term *term = network->term(net_pin_.pin_); if (term) return network->net(term); } return net; } } //////////////////////////////////////////////////////////////// ConcreteParasiticDevice::ConcreteParasiticDevice(size_t id, float value, ConcreteParasiticNode *node1, ConcreteParasiticNode *node2) : id_(id), value_(value), node1_(node1), node2_(node2) { } void ConcreteParasiticDevice::replaceNode(ConcreteParasiticNode *from_node, ConcreteParasiticNode *to_node) { if (from_node == node1_) node1_ = to_node; else if (from_node == node2_) node2_ = to_node; } ConcreteParasiticResistor::ConcreteParasiticResistor(size_t id, float value, ConcreteParasiticNode *node1, ConcreteParasiticNode *node2) : ConcreteParasiticDevice(id, value, node1, node2) { } ConcreteParasiticCapacitor::ConcreteParasiticCapacitor(size_t id, float value, ConcreteParasiticNode *node1, ConcreteParasiticNode *node2) : ConcreteParasiticDevice(id, value, node1, node2) { } //////////////////////////////////////////////////////////////// ConcreteParasiticNetwork::ConcreteParasiticNetwork(const Net *net, bool includes_pin_caps, const Network *network) : net_(net), sub_nodes_(network), pin_nodes_(network), max_node_id_(0), includes_pin_caps_(includes_pin_caps) { } ConcreteParasiticNetwork::ConcreteParasiticNetwork(ConcreteParasiticNetwork &¶sitic): net_(parasitic.net_), sub_nodes_(parasitic.sub_nodes_), pin_nodes_(parasitic.pin_nodes_), max_node_id_(parasitic.max_node_id_), includes_pin_caps_(parasitic.includes_pin_caps_) { } ConcreteParasiticNetwork::~ConcreteParasiticNetwork() { deleteDevices(); deleteNodes(); } void ConcreteParasiticNetwork::deleteNodes() { for (const auto& [id, node] : sub_nodes_) delete node; for (const auto& [pin, node] : pin_nodes_) delete node; } void ConcreteParasiticNetwork::deleteDevices() { for (ParasiticResistor *resistor : resistors_) { ConcreteParasiticResistor *cresistor = reinterpret_cast(resistor); delete cresistor; } for (ParasiticCapacitor *capacitor : capacitors_) { ConcreteParasiticCapacitor *ccapacitor = reinterpret_cast(capacitor); delete ccapacitor; } } void ConcreteParasiticNetwork::addResistor(ParasiticResistor *resistor) { resistors_.push_back(resistor); } void ConcreteParasiticNetwork::addCapacitor(ParasiticCapacitor *capacitor) { capacitors_.push_back(capacitor); } ParasiticNodeSeq ConcreteParasiticNetwork::nodes() const { ParasiticNodeSeq nodes; for (const auto [pin, node] : pin_nodes_) nodes.push_back(node); for (const auto& [id, node] : sub_nodes_) nodes.push_back(node); return nodes; } float ConcreteParasiticNetwork::capacitance() const { float cap = 0.0; for (const auto& [id, node] : sub_nodes_) { if (!node->isExternal()) cap += node->capacitance(); } for (const auto [pin, node] : pin_nodes_) { if (!node->isExternal()) cap += node->capacitance(); } for (ParasiticCapacitor *capacitor : capacitors_) { ConcreteParasiticCapacitor *ccap = static_cast(capacitor); cap += ccap->value(); } return cap; } ConcreteParasiticNode * ConcreteParasiticNetwork::findParasiticNode(const Net *net, int id, const Network *) const { NetIdPair net_id(net, id); auto id_node = sub_nodes_.find(net_id); if (id_node == sub_nodes_.end()) return nullptr; else return id_node->second; } ConcreteParasiticNode * ConcreteParasiticNetwork::findParasiticNode(const Pin *pin) const { auto pin_node = pin_nodes_.find(pin); if (pin_node == pin_nodes_.end()) return nullptr; else return pin_node->second; } ConcreteParasiticNode * ConcreteParasiticNetwork::ensureParasiticNode(const Net *net, int id, const Network *network) { ConcreteParasiticNode *node; NetIdPair net_id(net, id); auto id_node = sub_nodes_.find(net_id); if (id_node == sub_nodes_.end()) { Net *net1 = network->highestNetAbove(const_cast(net)); node = new ConcreteParasiticNode(net, id, network->highestNetAbove(net1) != net_); sub_nodes_[net_id] = node; if (net == net_) max_node_id_ = max((int) max_node_id_, id); } else node = id_node->second; return node; } ConcreteParasiticNode * ConcreteParasiticNetwork::ensureParasiticNode(const Pin *pin, const Network *network) { ConcreteParasiticNode *node; auto pin_node = pin_nodes_.find(pin); if (pin_node == pin_nodes_.end()) { Net *net = network->net(pin); // Pins on the top level instance may not have nets. // Use the net connected to the pin's terminal. if (net == nullptr && network->isTopLevelPort(pin)) { Term *term = network->term(pin); if (term) net = network->net(term); } else if (net) net = network->highestNetAbove(net); node = new ConcreteParasiticNode(pin, net != net_); pin_nodes_[pin] = node; } else node = pin_node->second; return node; } PinSet ConcreteParasiticNetwork::unannotatedLoads(const Pin *drvr_pin, const Parasitics *parasitics) const { PinSet loads = parasitics->loads(drvr_pin); ParasiticNode *drvr_node = findParasiticNode(drvr_pin); if (drvr_node) { ParasiticNodeResistorMap resistor_map = parasitics->parasiticNodeResistorMap(this); ParasiticNodeSet visited_nodes; ParasiticResistorSet loop_resistors; unannotatedLoads(drvr_node, nullptr, loads, visited_nodes, loop_resistors, resistor_map, parasitics); } return loads; } void ConcreteParasiticNetwork::unannotatedLoads(ParasiticNode *node, ParasiticResistor *from_res, PinSet &loads, ParasiticNodeSet &visited_nodes, ParasiticResistorSet &loop_resistors, ParasiticNodeResistorMap &resistor_map, const Parasitics *parasitics) const { const Pin *pin = parasitics->pin(node); if (pin) loads.erase(const_cast(pin)); visited_nodes.insert(node); ParasiticResistorSeq &resistors = resistor_map[node]; for (ParasiticResistor *resistor : resistors) { if (!loop_resistors.contains(resistor)) { ParasiticNode *onode = parasitics->otherNode(resistor, node); // One commercial extractor creates resistors with identical from/to nodes. if (onode != node && resistor != from_res) { if (!visited_nodes.contains(onode)) unannotatedLoads(onode, resistor, loads, visited_nodes, loop_resistors, resistor_map, parasitics); else // resistor loop loop_resistors.insert(resistor); } } } visited_nodes.erase(node); } //////////////////////////////////////////////////////////////// void ConcreteParasiticNetwork::disconnectPin(const Pin *pin, const Net *net, const Network *network) { auto pin_node = pin_nodes_.find(pin); if (pin_node != pin_nodes_.end()) { ConcreteParasiticNode *node = pin_node->second; // Make a subnode to replace the pin node. ConcreteParasiticNode *subnode = ensureParasiticNode(net,max_node_id_+1, network); // Hand over the devices. for (ParasiticResistor *resistor : resistors_) { ConcreteParasiticResistor *cresistor = reinterpret_cast(resistor); cresistor->replaceNode(node, subnode); } for (ParasiticCapacitor *capacitor : capacitors_) { ConcreteParasiticCapacitor *ccapacitor = reinterpret_cast(capacitor); ccapacitor->replaceNode(node, subnode); } pin_nodes_.erase(pin_node); delete node; } } //////////////////////////////////////////////////////////////// NetIdPairLess::NetIdPairLess(const Network *network) : net_less_(network) { } bool NetIdPairLess::operator()(const NetIdPair &net_id1, const NetIdPair &net_id2) const { const auto& [net1, id1] = net_id1; const auto& [net2, id2] = net_id2; return net_less_(net1, net2) || (net1 == net2 && id1 < id2); } //////////////////////////////////////////////////////////////// ConcreteParasitics::ConcreteParasitics(std::string name, std::string filename, StaState *sta) : Parasitics(sta), name_(name), filename_(filename) { } ConcreteParasitics::~ConcreteParasitics() { deleteParasitics(); } bool ConcreteParasitics::haveParasitics() { return !drvr_parasitic_map_.empty() || !parasitic_network_map_.empty(); } void ConcreteParasitics::clear() { deleteParasitics(); } void ConcreteParasitics::deleteParasitics() { for (auto &[drvr, parasitics] : drvr_parasitic_map_) { for (size_t i = 0; i < min_max_rise_fall_count; i++) delete parasitics[i]; } drvr_parasitic_map_.clear(); parasitic_network_map_.clear(); } void ConcreteParasitics::deleteParasitics(const Pin *drvr_pin) { auto itr = drvr_parasitic_map_.find(drvr_pin); if (itr != drvr_parasitic_map_.end()) { const MinMaxRiseFallParasitics ¶sitics = itr->second; for (size_t i = 0; i < min_max_rise_fall_count; i++) delete parasitics[i]; drvr_parasitic_map_.erase(itr); } } void ConcreteParasitics::deleteParasitics(const Net *net) { PinSet *drivers = network_->drivers(net); for (auto drvr_pin : *drivers) deleteParasitics(drvr_pin); parasitic_network_map_.erase(net); } float ConcreteParasitics::capacitance(const Parasitic *parasitic) const { const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic->capacitance(); } bool ConcreteParasitics::isReducedParasiticNetwork(const Parasitic *parasitic) const { const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic->isReducedParasiticNetwork(); } void ConcreteParasitics::setIsReducedParasiticNetwork(Parasitic *parasitic, bool is_reduced) { ConcreteParasitic *cparasitic = static_cast(parasitic); cparasitic->setIsReduced(is_reduced); } void ConcreteParasitics::disconnectPinBefore(const Pin *pin) { if (haveParasitics()) { deleteReducedParasitics(pin); const Net *net = findParasiticNet(pin); if (net) { ConcreteParasiticNetwork *parasitic = static_cast(findParasiticNetwork(pin)); if (parasitic) parasitic->disconnectPin(pin, net, network_); } } } void ConcreteParasitics::deletePinBefore(const Pin *pin) { // Actions are the same. disconnectPinBefore(pin); } void ConcreteParasitics::loadPinCapacitanceChanged(const Pin *pin) { // Delete reduced models that depend on load pin capacitances. deleteReducedParasitics(pin); } void ConcreteParasitics::deleteReducedParasitics(const Net *net) { if (!drvr_parasitic_map_.empty()) { PinSet *drivers = network_->drivers(net); if (drivers) { for (auto drvr_pin : *drivers) deleteDrvrReducedParasitics(drvr_pin); } } } // Delete reduced models on pin's net. void ConcreteParasitics::deleteReducedParasitics(const Pin *pin) { if (!drvr_parasitic_map_.empty()) { PinSet *drivers = network_->drivers(pin); if (drivers) { for (auto drvr_pin : *drivers) deleteDrvrReducedParasitics(drvr_pin); } } } void ConcreteParasitics::deleteDrvrReducedParasitics(const Pin *drvr_pin) { deleteParasitics(drvr_pin); } //////////////////////////////////////////////////////////////// bool ConcreteParasitics::isPiElmore(const Parasitic *parasitic) const { const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic && cparasitic->isPiElmore(); } size_t minMaxRiseFallIndex(const MinMax *min_max, const RiseFall *rf) { return min_max->index() * RiseFall::index_count + rf->index(); } Parasitic * ConcreteParasitics::findPiElmore(const Pin *drvr_pin, const RiseFall *rf, const MinMax *min_max) const { LockGuard lock(lock_); auto itr = drvr_parasitic_map_.find(drvr_pin); if (itr != drvr_parasitic_map_.end()) { const MinMaxRiseFallParasitics ¶sitics = itr->second; ConcreteParasitic *parasitic = parasitics[minMaxRiseFallIndex(min_max, rf)]; if (parasitic && parasitic->isPiElmore()) return parasitic; } return nullptr; } Parasitic * ConcreteParasitics::makePiElmore(const Pin *drvr_pin, const RiseFall *rf, const MinMax *min_max, float c2, float rpi, float c1) { LockGuard lock(lock_); auto itr = drvr_parasitic_map_.find(drvr_pin); ConcretePiElmore *pi_elmore = nullptr; size_t mm_rf_index = minMaxRiseFallIndex(min_max, rf); if (itr != drvr_parasitic_map_.end()) { MinMaxRiseFallParasitics ¶sitics = itr->second; ConcreteParasitic *parasitic = parasitics[mm_rf_index]; if (parasitic && parasitic->isPiElmore()) { pi_elmore = dynamic_cast(parasitic); pi_elmore->setPiModel(c2, rpi, c1); pi_elmore->loads().clear(); } else { delete parasitic; pi_elmore = new ConcretePiElmore(c2, rpi, c1); parasitics[mm_rf_index] = pi_elmore; } } else { MinMaxRiseFallParasitics ¶sitics = drvr_parasitic_map_[drvr_pin]; for (size_t i = 0; i < min_max_rise_fall_count; i++) parasitics[i] = nullptr; pi_elmore = new ConcretePiElmore(c2, rpi, c1); parasitics[mm_rf_index] = pi_elmore; } return pi_elmore; } //////////////////////////////////////////////////////////////// bool ConcreteParasitics::isPiModel(const Parasitic *parasitic) const { const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic && cparasitic->isPiModel(); } void ConcreteParasitics::piModel(const Parasitic *parasitic, float &c2, float &rpi, float &c1) const { const ConcreteParasitic *cparasitic = static_cast(parasitic); cparasitic->piModel(c2, rpi, c1); } void ConcreteParasitics::setPiModel(Parasitic *parasitic, float c2, float rpi, float c1) { ConcreteParasitic *cparasitic = static_cast(parasitic); cparasitic->setPiModel(c2, rpi, c1); } //////////////////////////////////////////////////////////////// void ConcreteParasitics::findElmore(const Parasitic *parasitic, const Pin *load_pin, float &elmore, bool &exists) const { const ConcreteParasitic *cparasitic = static_cast(parasitic); cparasitic->findElmore(load_pin, elmore, exists); } void ConcreteParasitics::setElmore(Parasitic *parasitic, const Pin *load_pin, float elmore) { ConcreteParasitic *cparasitic = static_cast(parasitic); cparasitic->setElmore(load_pin, elmore); } //////////////////////////////////////////////////////////////// bool ConcreteParasitics::isPiPoleResidue(const Parasitic* parasitic) const { const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic && cparasitic->isPiPoleResidue(); } Parasitic * ConcreteParasitics::findPiPoleResidue(const Pin *drvr_pin, const RiseFall *rf, const MinMax *min_max) const { LockGuard lock(lock_); auto itr = drvr_parasitic_map_.find(drvr_pin); if (itr != drvr_parasitic_map_.end()) { const MinMaxRiseFallParasitics ¶sitics = itr->second; size_t mm_rf_index = minMaxRiseFallIndex(min_max, rf); ConcreteParasitic *parasitic = parasitics[mm_rf_index]; if (parasitic && parasitic->isPiPoleResidue()) return parasitic; } return nullptr; } Parasitic * ConcreteParasitics::makePiPoleResidue(const Pin *drvr_pin, const RiseFall *rf, const MinMax *min_max, float c2, float rpi, float c1) { LockGuard lock(lock_); auto itr = drvr_parasitic_map_.find(drvr_pin); ConcretePiPoleResidue *pi_pole_residue = nullptr; size_t mm_rf_index = minMaxRiseFallIndex(min_max, rf); if (itr != drvr_parasitic_map_.end()) { MinMaxRiseFallParasitics ¶sitics = itr->second; ConcreteParasitic *parasitic = parasitics[mm_rf_index]; if (parasitic && parasitic->isPoleResidue()) { pi_pole_residue = dynamic_cast(parasitic); pi_pole_residue->setPiModel(c2, rpi, c1); pi_pole_residue->loadResidues().clear(); } else { delete parasitic; pi_pole_residue = new ConcretePiPoleResidue(c2, rpi, c1); parasitics[mm_rf_index] = pi_pole_residue; } } else { MinMaxRiseFallParasitics ¶sitics = drvr_parasitic_map_[drvr_pin]; for (size_t i = 0; i < min_max_rise_fall_count; i++) parasitics[i] = nullptr; pi_pole_residue = new ConcretePiPoleResidue(c2, rpi, c1); parasitics[mm_rf_index] = pi_pole_residue; } return pi_pole_residue; } Parasitic * ConcreteParasitics::findPoleResidue(const Parasitic *parasitic, const Pin *load_pin) const { const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic->findPoleResidue(load_pin); } void ConcreteParasitics::setPoleResidue(Parasitic *parasitic, const Pin *load_pin, ComplexFloatSeq *poles, ComplexFloatSeq *residues) { ConcreteParasitic *cparasitic = static_cast(parasitic); cparasitic->setPoleResidue(load_pin, poles, residues); } //////////////////////////////////////////////////////////////// bool ConcreteParasitics::isPoleResidue(const Parasitic *parasitic) const { const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic->isPoleResidue(); } size_t ConcreteParasitics::poleResidueCount(const Parasitic *parasitic) const { const ConcretePoleResidue *pr_parasitic = static_cast(parasitic); return pr_parasitic->poleResidueCount(); } void ConcreteParasitics::poleResidue(const Parasitic *parasitic, int pole_index, ComplexFloat &pole, ComplexFloat &residue) const { const ConcretePoleResidue *pr_parasitic = static_cast(parasitic); pr_parasitic->poleResidue(pole_index, pole, residue); } //////////////////////////////////////////////////////////////// bool ConcreteParasitics::isParasiticNetwork(const Parasitic *parasitic) const { const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic && cparasitic->isParasiticNetwork(); } Parasitic * ConcreteParasitics::findParasiticNetwork(const Net *net) { LockGuard lock(lock_); auto itr = parasitic_network_map_.find(net); if (itr != parasitic_network_map_.end()) return &itr->second; else return nullptr; } Parasitic * ConcreteParasitics::findParasiticNetwork(const Pin *pin) { if (!parasitic_network_map_.empty()) { LockGuard lock(lock_); if (!parasitic_network_map_.empty()) { // Only call findParasiticNet if parasitics exist. const Net *net = findParasiticNet(pin); if (!parasitic_network_map_.empty()) { auto itr = parasitic_network_map_.find(net); if (itr != parasitic_network_map_.end()) return &itr->second; } } } return nullptr; } Parasitic * ConcreteParasitics::makeParasiticNetwork(const Net *net, bool includes_pin_caps) { LockGuard lock(lock_); auto itr = parasitic_network_map_.find(net); if (itr != parasitic_network_map_.end()) { parasitic_network_map_.erase(itr); for (const Pin *drvr_pin : *network_->drivers(net)) deleteParasitics(drvr_pin); } parasitic_network_map_.emplace(net, ConcreteParasiticNetwork(net, includes_pin_caps, network_)); return ¶sitic_network_map_.find(net)->second; } void ConcreteParasitics::deleteParasiticNetwork(const Net *net) { LockGuard lock(lock_); parasitic_network_map_.erase(net); } const Net * ConcreteParasitics::net(const Parasitic *parasitic) const { const ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); if (cparasitic->isParasiticNetwork()) return cparasitic->net(); else return nullptr; } bool ConcreteParasitics::includesPinCaps(const Parasitic *parasitic) const { const ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->includesPinCaps(); } ParasiticNode * ConcreteParasitics::findParasiticNode(Parasitic *parasitic, const Net *net, int id, const Network *network) const { const ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->findParasiticNode(net, id, network); } ParasiticNode * ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic, const Net *net, int id, const Network *network) { ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->ensureParasiticNode(net, id, network); } ParasiticNode * ConcreteParasitics::findParasiticNode(const Parasitic *parasitic, const Pin *pin) const { const ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->findParasiticNode(pin); } ParasiticNode * ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic, const Pin *pin, const Network *network) { ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->ensureParasiticNode(pin, network); } void ConcreteParasitics::incrCap(ParasiticNode *node, float cap) { ConcreteParasiticNode *cnode = static_cast(node); cnode->incrCapacitance(cap); } void ConcreteParasitics::makeCapacitor(Parasitic *parasitic, size_t index, float cap, ParasiticNode *node1, ParasiticNode *node2) { ConcreteParasiticNode *cnode1 = static_cast(node1); ConcreteParasiticNode *cnode2 = static_cast(node2); ConcreteParasiticCapacitor *capacitor = new ConcreteParasiticCapacitor(index, cap, cnode1, cnode2); ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); cparasitic->addCapacitor(capacitor); } void ConcreteParasitics::makeResistor(Parasitic *parasitic, size_t index, float res, ParasiticNode *node1, ParasiticNode *node2) { ConcreteParasiticNode *cnode1 = static_cast(node1); ConcreteParasiticNode *cnode2 = static_cast(node2); ParasiticResistor *resistor = new ConcreteParasiticResistor(index, res, cnode1, cnode2); ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); cparasitic->addResistor(resistor); } ParasiticNodeSeq ConcreteParasitics::nodes(const Parasitic *parasitic) const { const ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->nodes(); } ParasiticResistorSeq ConcreteParasitics::resistors(const Parasitic *parasitic) const { const ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->resistors(); } ParasiticCapacitorSeq ConcreteParasitics::capacitors(const Parasitic *parasitic) const { const ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->capacitors(); } const char * ConcreteParasitics::name(const ParasiticNode *node) const { const ConcreteParasiticNode *cnode = static_cast(node); return cnode->name(network_); } float ConcreteParasitics::nodeGndCap(const ParasiticNode *node) const { const ConcreteParasiticNode *cnode = static_cast(node); return cnode->capacitance(); } const Pin * ConcreteParasitics::pin(const ParasiticNode *node) const { const ConcreteParasiticNode *cnode = static_cast(node); return cnode->pin(); } const Net * ConcreteParasitics::net(const ParasiticNode *node, const Network *network) const { const ConcreteParasiticNode *cnode = static_cast(node); return cnode->net(network); } unsigned ConcreteParasitics::netId(const ParasiticNode *node) const { const ConcreteParasiticNode *cnode = static_cast(node); return cnode->id(); } bool ConcreteParasitics::isExternal(const ParasiticNode *node) const { const ConcreteParasiticNode *cnode = static_cast(node); return cnode->isExternal(); } //////////////////////////////////////////////////////////////// size_t ConcreteParasitics::id(const ParasiticResistor *resistor) const { const ConcreteParasiticResistor *cresistor = static_cast(resistor); return cresistor->id(); } float ConcreteParasitics::value(const ParasiticResistor *resistor) const { const ConcreteParasiticResistor *cresistor = static_cast(resistor); return cresistor->value(); } ParasiticNode * ConcreteParasitics::node1(const ParasiticResistor *resistor) const { const ConcreteParasiticResistor *cresistor = static_cast(resistor); return cresistor->node1(); } ParasiticNode * ConcreteParasitics::node2(const ParasiticResistor *resistor) const { const ConcreteParasiticResistor *cresistor = static_cast(resistor); return cresistor->node2(); } //////////////////////////////////////////////////////////////// size_t ConcreteParasitics::id(const ParasiticCapacitor *capacitor) const { const ConcreteParasiticCapacitor *ccapacitor = static_cast(capacitor); return ccapacitor->id(); } float ConcreteParasitics::value(const ParasiticCapacitor *capacitor) const { const ConcreteParasiticCapacitor *ccapacitor = static_cast(capacitor); return ccapacitor->value(); } ParasiticNode * ConcreteParasitics::node1(const ParasiticCapacitor *capacitor) const { const ConcreteParasiticCapacitor *ccapacitor = static_cast(capacitor); return ccapacitor->node1(); } ParasiticNode * ConcreteParasitics::node2(const ParasiticCapacitor *capacitor) const { const ConcreteParasiticCapacitor *ccapacitor = static_cast(capacitor); return ccapacitor->node2(); } //////////////////////////////////////////////////////////////// PinSet ConcreteParasitics::unannotatedLoads(const Parasitic *parasitic, const Pin *drvr_pin) const { const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic->unannotatedLoads(drvr_pin, this); } } // namespace