// OpenSTA, Static Timing Analyzer // Copyright (c) 2020, 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 . #include "ConcreteParasitics.hh" #include #include // max #include "Report.hh" #include "Debug.hh" #include "Error.hh" #include "Mutex.hh" #include "Set.hh" #include "MinMax.hh" #include "Network.hh" #include "Wireload.hh" #include "Liberty.hh" #include "Sdc.hh" #include "Parasitics.hh" #include "ReduceParasitics.hh" #include "MakeConcreteParasitics.hh" #include "Parasitics.hh" #include "ConcreteParasiticsPvt.hh" #include "Corner.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 *) { } ParasiticDeviceIterator * ConcreteParasitic::deviceIterator() { return nullptr; } ParasiticNodeIterator * ConcreteParasitic::nodeIterator() { return nullptr; } //////////////////////////////////////////////////////////////// ConcreteElmore::ConcreteElmore() : loads_(nullptr) { } ConcreteElmore::~ConcreteElmore() { delete loads_; } void ConcreteElmore::findElmore(const Pin *load_pin, float &elmore, bool &exists) const { if (loads_) loads_->findKey(load_pin, elmore, exists); else exists = false; } void ConcreteElmore::deleteLoad(const Pin *load_pin) { loads_->erase(load_pin); } void ConcreteElmore::setElmore(const Pin *load_pin, float elmore) { if (loads_ == nullptr) loads_ = new ConcreteElmoreLoadMap; (*loads_)[load_pin] = elmore; } //////////////////////////////////////////////////////////////// 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), ConcreteElmore() { } 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 { ConcreteElmore::findElmore(load_pin, elmore, exists); } void ConcretePiElmore::setElmore(const Pin *load_pin, float elmore) { ConcreteElmore::setElmore(load_pin, elmore); } //////////////////////////////////////////////////////////////// ConcretePiElmoreEstimated::ConcretePiElmoreEstimated(float c2, float rpi, float c1, float elmore_res, float elmore_cap, bool elmore_use_load_cap, const RiseFall *rf, const OperatingConditions *op, const Corner *corner, const MinMax *min_max, Sdc *sdc): ConcretePi(c2, rpi, c1), elmore_res_(elmore_res), elmore_cap_(elmore_cap), elmore_use_load_cap_(elmore_use_load_cap), rf_(rf), op_cond_(op), corner_(corner), min_max_(min_max), sdc_(sdc) { } float ConcretePiElmoreEstimated::capacitance() const { return ConcretePi::capacitance(); } void ConcretePiElmoreEstimated::piModel(float &c2, float &rpi, float &c1) const { ConcretePi::piModel(c2, rpi, c1); } void ConcretePiElmoreEstimated::findElmore(const Pin *load_pin, float &elmore, bool &exists) const { float load_cap = 0.0; if (elmore_use_load_cap_) load_cap = sdc_->pinCapacitance(load_pin, rf_, op_cond_, corner_, min_max_); elmore = elmore_res_ * (elmore_cap_ + load_cap); exists = true; } void ConcretePiElmoreEstimated::setElmore(const Pin *, float) { // Cannot set elmore on estimated parasitic. } //////////////////////////////////////////////////////////////// ConcretePoleResidue:: ConcretePoleResidue(ComplexFloatSeq *poles, ComplexFloatSeq *residues) : poles_(poles), residues_(residues) { } 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; } //////////////////////////////////////////////////////////////// ConcretePiPoleResidue::ConcretePiPoleResidue(float c2, float rpi, float c1) : ConcretePi(c2, rpi, c1), load_pole_residue_(nullptr) { } ConcretePiPoleResidue::~ConcretePiPoleResidue() { if (load_pole_residue_) { load_pole_residue_->deleteContents(); delete load_pole_residue_; } } 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 { if (load_pole_residue_) return load_pole_residue_->findKey(load_pin); else return nullptr; } void ConcretePiPoleResidue::setPoleResidue(const Pin *load_pin, ComplexFloatSeq *poles, ComplexFloatSeq *residues) { if (load_pole_residue_ == nullptr) load_pole_residue_ = new ConcretePoleResidueMap; ConcretePoleResidue *pole_residue = load_pole_residue_->findKey(load_pin); if (pole_residue == nullptr) { pole_residue = new ConcretePoleResidue(poles, residues); (*load_pole_residue_)[load_pin] = pole_residue; } else pole_residue->setPoleResidue(poles, residues); } void ConcretePiPoleResidue::deleteLoad(const Pin *load_pin) { ConcretePoleResidue *pole_residue = load_pole_residue_->findKey(load_pin); if (pole_residue) { load_pole_residue_->erase(load_pin); delete pole_residue; } } //////////////////////////////////////////////////////////////// ConcreteParasiticNode::ConcreteParasiticNode() : cap_(0.0) { } void ConcreteParasiticNode::incrCapacitance(float cap) { cap_ += cap; } float ConcreteParasiticNode::capacitance() const { return cap_; } void ConcreteParasiticNode::addDevice(ConcreteParasiticDevice *device) { devices_.push_back(device); } //////////////////////////////////////////////////////////////// ConcreteParasiticSubNode::ConcreteParasiticSubNode(const Net *net, int id) : ConcreteParasiticNode(), net_(net), id_(id) { } const char * ConcreteParasiticSubNode::name(const Network *network) const { const char *net_name = network->pathName(net_); return stringPrintTmp("%s:%d", net_name, id_); } //////////////////////////////////////////////////////////////// ConcreteParasiticPinNode::ConcreteParasiticPinNode(const Pin *pin) : ConcreteParasiticNode(), pin_(pin) { } const char * ConcreteParasiticPinNode::name(const Network *network) const { return network->pathName(pin_); } //////////////////////////////////////////////////////////////// ConcreteParasiticDevice::ConcreteParasiticDevice(const char *name, ConcreteParasiticNode *node, float value) : name_(name), node_(node), value_(value) { } ConcreteParasiticDevice::~ConcreteParasiticDevice() { if (name_) stringDelete(name_); } ConcreteParasiticResistor:: ConcreteParasiticResistor(const char *name, ConcreteParasiticNode *node, ConcreteParasiticNode *other_node, float res) : ConcreteParasiticDevice(name, node, res), other_node_(other_node) { } ParasiticNode * ConcreteParasiticResistor::otherNode(ParasiticNode *node) const { if (node == node_) return other_node_; else if (node == other_node_) return node_; else return nullptr; } void ConcreteParasiticResistor::replaceNode(ConcreteParasiticNode *from_node, ConcreteParasiticNode *to_node) { if (from_node == node_) node_ = to_node; else other_node_ = to_node; } //////////////////////////////////////////////////////////////// ConcreteCouplingCap::ConcreteCouplingCap(const char *name, ConcreteParasiticNode *node, float cap) : ConcreteParasiticDevice(name, node, cap) { } void ConcreteCouplingCap::replaceNode(ConcreteParasiticNode *from_node, ConcreteParasiticNode *to_node) { if (from_node == node_) node_ = to_node; } //////////////////////////////////////////////////////////////// ConcreteCouplingCapInt:: ConcreteCouplingCapInt(const char *name, ConcreteParasiticNode *node, ConcreteParasiticNode *other_node, float cap) : ConcreteCouplingCap(name, node, cap), other_node_(other_node) { } ParasiticNode * ConcreteCouplingCapInt::otherNode(ParasiticNode *node) const { if (node == node_) return other_node_; else if (node == other_node_) return node_; else return nullptr; } void ConcreteCouplingCapInt::replaceNode(ConcreteParasiticNode *from_node, ConcreteParasiticNode *to_node) { if (from_node == node_) node_ = to_node; else other_node_ = to_node; } //////////////////////////////////////////////////////////////// ConcreteCouplingCapExtNode:: ConcreteCouplingCapExtNode(const char *name, ConcreteParasiticNode *node, Net *, int, float cap) : ConcreteCouplingCap(name, node, cap) { } ParasiticNode * ConcreteCouplingCapExtNode::otherNode(ParasiticNode *) const { return nullptr; } void ConcreteCouplingCapExtNode::replaceNode(ConcreteParasiticNode *from_node, ConcreteParasiticNode *to_node) { if (from_node == node_) node_ = to_node; } //////////////////////////////////////////////////////////////// ConcreteCouplingCapExtPin:: ConcreteCouplingCapExtPin(const char *name, ConcreteParasiticNode *node, Pin *, float cap) : ConcreteCouplingCap(name, node, cap) { } ParasiticNode * ConcreteCouplingCapExtPin::otherNode(ParasiticNode *) const { return nullptr; } void ConcreteCouplingCapExtPin::replaceNode(ConcreteParasiticNode *from_node, ConcreteParasiticNode *to_node) { if (from_node == node_) node_ = to_node; } //////////////////////////////////////////////////////////////// ConcreteParasiticNetwork::ConcreteParasiticNetwork(bool includes_pin_caps) : max_node_id_(0), includes_pin_caps_(includes_pin_caps) { } ConcreteParasiticNetwork::~ConcreteParasiticNetwork() { deleteDevices(); deleteNodes(); } void ConcreteParasiticNetwork::deleteNodes() { ConcreteParasiticSubNodeMap::Iterator node_iter1(sub_nodes_); while (node_iter1.hasNext()) { NetId *net_id; ConcreteParasiticSubNode *node; node_iter1.next(net_id, node); delete net_id; delete node; } pin_nodes_.deleteContents(); } void ConcreteParasiticNetwork::deleteDevices() { ConcreteParasiticDeviceSet devices1; devices(&devices1); devices1.deleteContents(); } ParasiticNodeIterator * ConcreteParasiticNetwork::nodeIterator() { ConcreteParasiticNodeSeq *nodes = new ConcreteParasiticNodeSeq(); ConcreteParasiticPinNodeMap::Iterator node_iter2(pin_nodes_); while (node_iter2.hasNext()) { ConcreteParasiticPinNode *node = node_iter2.next(); nodes->push_back(node); } ConcreteParasiticSubNodeMap::Iterator node_iter1(sub_nodes_); while (node_iter1.hasNext()) { ConcreteParasiticSubNode *node = node_iter1.next(); nodes->push_back(node); } return new ConcreteParasiticNodeSeqIterator(nodes); } ParasiticDeviceIterator * ConcreteParasiticNetwork::deviceIterator() { ConcreteParasiticDeviceSet *devices1 = new ConcreteParasiticDeviceSet(); devices(devices1); return new ConcreteParasiticDeviceSetIterator(devices1); } void ConcreteParasiticNetwork::devices(ConcreteParasiticDeviceSet *devices) { // Collect devices into a set so they are only deleted once // because multiple sub-nodes or pin nodes can refer to them. ConcreteParasiticSubNodeMap::Iterator node_iter1(sub_nodes_); while (node_iter1.hasNext()) { ConcreteParasiticSubNode *node = node_iter1.next(); ConcreteParasiticDeviceSeq::Iterator device_iter(node->devices()); while (device_iter.hasNext()) { ConcreteParasiticDevice *device = device_iter.next(); devices->insert(device); } } ConcreteParasiticPinNodeMap::Iterator node_iter2(pin_nodes_); while (node_iter2.hasNext()) { ConcreteParasiticPinNode *node = node_iter2.next(); ConcreteParasiticDeviceSeq::Iterator device_iter(node->devices()); while (device_iter.hasNext()) { ConcreteParasiticDevice *device = device_iter.next(); devices->insert(device); } } } float ConcreteParasiticNetwork::capacitance() const { float cap = 0.0; ConcreteParasiticSubNodeMap::ConstIterator sub_node_iter(sub_nodes_); while (sub_node_iter.hasNext()) { ConcreteParasiticSubNode *node = sub_node_iter.next(); cap += node->capacitance(); } ConcreteParasiticPinNodeMap::ConstIterator pin_node_iter(pin_nodes_); while (pin_node_iter.hasNext()) { ConcreteParasiticPinNode *node = pin_node_iter.next(); cap += node->capacitance(); } return cap; } ConcreteParasiticNode * ConcreteParasiticNetwork::ensureParasiticNode(const Net *net, int id) { NetId net_id(net, id); ConcreteParasiticSubNode *node = sub_nodes_.findKey(&net_id); if (node == nullptr) { node = new ConcreteParasiticSubNode(net, id); sub_nodes_[new NetId(net, id)] = node; max_node_id_ = max((int) max_node_id_, id); } return node; } ConcreteParasiticNode * ConcreteParasiticNetwork::findNode(const Pin *pin) { return pin_nodes_.findKey(pin); } void ConcreteParasiticNetwork::disconnectPin(const Pin *pin, Net *net) { ConcreteParasiticNode *node = pin_nodes_.findKey(pin); if (node) { // Make a subnode to replace the pin node. ConcreteParasiticNode *subnode = ensureParasiticNode(net,max_node_id_+1); // Hand over the devices. ConcreteParasiticDeviceSeq::Iterator device_iter(node->devices()); while (device_iter.hasNext()) { ConcreteParasiticDevice *device = device_iter.next(); subnode->addDevice(device); device->replaceNode(node, subnode); } pin_nodes_.erase(pin); delete node; } } ConcreteParasiticNode * ConcreteParasiticNetwork::ensureParasiticNode(const Pin *pin) { ConcreteParasiticPinNode *node = pin_nodes_.findKey(pin); if (node == nullptr) { node = new ConcreteParasiticPinNode(pin); pin_nodes_[pin] = node; } return node; } bool NetIdLess::operator()(const NetId *net_id1, const NetId *net_id2) const { const Net *net1 = net_id1->first; const Net *net2 = net_id2->first; int id1 = net_id1->second; int id2 = net_id2->second; return net1 < net2 || (net1 == net2 && id1 < id2); } //////////////////////////////////////////////////////////////// Parasitics * makeConcreteParasitics(StaState *sta) { return new ConcreteParasitics(sta); } ConcreteParasitics::ConcreteParasitics(StaState *sta) : Parasitics(sta) { } ConcreteParasitics::~ConcreteParasitics() { clear(); } bool ConcreteParasitics::haveParasitics() { return !drvr_parasitic_map_.empty() || !parasitic_network_map_.empty(); } void ConcreteParasitics::clear() { deleteParasitics(); } int ConcreteParasitics::parasiticAnalysisPtIndex(const ParasiticAnalysisPt *ap, const RiseFall *rf) const { return ap->index() * RiseFall::index_count + rf->index(); } void ConcreteParasitics::deleteParasitics() { int ap_count = corners_->parasiticAnalysisPtCount(); int ap_rf_count = ap_count * RiseFall::index_count; for (auto drvr_parasitics : drvr_parasitic_map_) { ConcreteParasitic **parasitics = drvr_parasitics.second; if (parasitics) { for (int i = 0; i < ap_rf_count; i++) delete parasitics[i]; delete [] parasitics; } } drvr_parasitic_map_.clear(); for (auto net_parasitics : parasitic_network_map_) { ConcreteParasiticNetwork **parasitics = net_parasitics.second; if (parasitics) { for (int i = 0; i < ap_count; i++) delete parasitics[i]; delete [] parasitics; } } parasitic_network_map_.clear(); } void ConcreteParasitics::deleteParasitics(const Pin *drvr_pin, const ParasiticAnalysisPt *ap) { ConcreteParasitic **parasitics = drvr_parasitic_map_[drvr_pin]; if (parasitics) { for (auto tr : RiseFall::range()) { int ap_rf_index = parasiticAnalysisPtIndex(ap, tr); delete parasitics[ap_rf_index]; parasitics[ap_rf_index] = nullptr; } } } void ConcreteParasitics::deleteParasitics(const Net *net, const ParasiticAnalysisPt *ap) { PinSet *drivers = network_->drivers(net); for (auto drvr_pin : *drivers) deleteParasitics(drvr_pin, ap); ConcreteParasiticNetwork **parasitics = parasitic_network_map_[net]; if (parasitics) { delete parasitics[ap->index()]; parasitics[ap->index()] = nullptr; } } void ConcreteParasitics::deleteUnsavedParasitic(Parasitic *parasitic) { ConcreteParasitic *cparasitic = static_cast(parasitic); delete cparasitic; } void ConcreteParasitics::save() { // No database to save to. } float ConcreteParasitics::capacitance(Parasitic *parasitic) const { ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic->capacitance(); } bool ConcreteParasitics::isReducedParasiticNetwork(Parasitic *parasitic) 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); Net *net = findParasiticNet(pin); if (net) { ConcreteParasiticNetwork **parasitics = parasitic_network_map_[net]; if (parasitics) { int ap_count = corners_->parasiticAnalysisPtCount(); for (int i = 0; i < ap_count; i++) { ConcreteParasiticNetwork *parasitic = parasitics[i]; if (parasitic) parasitic->disconnectPin(pin, net); } } } } } void ConcreteParasitics::loadPinCapacitanceChanged(const Pin *pin) { // Delete reduced models that depend on load pin capacitances. deleteReducedParasitics(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) { UniqueLock lock(lock_); ConcreteParasitic **parasitics = drvr_parasitic_map_[drvr_pin]; if (parasitics) { int ap_count = corners_->parasiticAnalysisPtCount(); int ap_rf_count = ap_count * RiseFall::index_count; for (int i = 0; i < ap_rf_count; i++) delete parasitics[i]; delete [] parasitics; } drvr_parasitic_map_[drvr_pin] = nullptr; } //////////////////////////////////////////////////////////////// bool ConcreteParasitics::isPiElmore(Parasitic *parasitic) const { ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic && cparasitic->isPiElmore(); } Parasitic * ConcreteParasitics::findPiElmore(const Pin *drvr_pin, const RiseFall *rf, const ParasiticAnalysisPt *ap) const { if (!drvr_parasitic_map_.empty()) { int ap_rf_index = parasiticAnalysisPtIndex(ap, rf); UniqueLock lock(lock_); ConcreteParasitic **parasitics = drvr_parasitic_map_.findKey(drvr_pin); if (parasitics) { ConcreteParasitic *parasitic = parasitics[ap_rf_index]; if (parasitic == nullptr && rf == RiseFall::fall()) { ap_rf_index = parasiticAnalysisPtIndex(ap, RiseFall::rise()); parasitic = parasitics[ap_rf_index]; } if (parasitic && parasitic->isPiElmore()) return parasitic; } } return nullptr; } Parasitic * ConcreteParasitics::makePiElmore(const Pin *drvr_pin, const RiseFall *rf, const ParasiticAnalysisPt *ap, float c2, float rpi, float c1) { UniqueLock lock(lock_); ConcreteParasitic **parasitics = drvr_parasitic_map_.findKey(drvr_pin); if (parasitics == nullptr) { int ap_count = corners_->parasiticAnalysisPtCount(); int ap_rf_count = ap_count * RiseFall::index_count; parasitics = new ConcreteParasitic*[ap_rf_count]; for (int i = 0; i < ap_rf_count; i++) parasitics[i] = nullptr; drvr_parasitic_map_[drvr_pin] = parasitics; } int ap_rf_index = parasiticAnalysisPtIndex(ap, rf); ConcreteParasitic *parasitic = parasitics[ap_rf_index]; ConcretePiElmore *pi_elmore = nullptr; if (parasitic) { if (parasitic->isPiElmore()) { pi_elmore = dynamic_cast(parasitic); pi_elmore->setPiModel(c2, rpi, c1); } else { delete parasitic; pi_elmore = new ConcretePiElmore(c2, rpi, c1); parasitics[ap_rf_index] = pi_elmore; } } else { pi_elmore = new ConcretePiElmore(c2, rpi, c1); parasitics[ap_rf_index] = pi_elmore; } return pi_elmore; } //////////////////////////////////////////////////////////////// bool ConcreteParasitics::isPiModel(Parasitic *parasitic) const { ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic && cparasitic->isPiModel(); } void ConcreteParasitics::piModel(Parasitic *parasitic, float &c2, float &rpi, float &c1) 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(Parasitic *parasitic, const Pin *load_pin, float &elmore, bool &exists) 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(Parasitic* parasitic) const { ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic && cparasitic->isPiPoleResidue(); } Parasitic * ConcreteParasitics::findPiPoleResidue(const Pin *drvr_pin, const RiseFall *rf, const ParasiticAnalysisPt *ap) const { if (!drvr_parasitic_map_.empty()) { int ap_rf_index = parasiticAnalysisPtIndex(ap, rf); UniqueLock lock(lock_); ConcreteParasitic **parasitics = drvr_parasitic_map_.findKey(drvr_pin); if (parasitics) { ConcreteParasitic *parasitic = parasitics[ap_rf_index]; if (parasitic == nullptr && rf == RiseFall::fall()) { ap_rf_index = parasiticAnalysisPtIndex(ap, RiseFall::rise()); parasitic = parasitics[ap_rf_index]; } if (parasitic->isPiPoleResidue()) return parasitic; } } return nullptr; } Parasitic * ConcreteParasitics::makePiPoleResidue(const Pin *drvr_pin, const RiseFall *rf, const ParasiticAnalysisPt *ap, float c2, float rpi, float c1) { UniqueLock lock(lock_); ConcreteParasitic **parasitics = drvr_parasitic_map_.findKey(drvr_pin); if (parasitics == nullptr) { int ap_count = corners_->parasiticAnalysisPtCount(); int ap_rf_count = ap_count * RiseFall::index_count; parasitics = new ConcreteParasitic*[ap_rf_count]; for (int i = 0; i < ap_rf_count; i++) parasitics[i] = nullptr; drvr_parasitic_map_[drvr_pin] = parasitics; } int ap_rf_index = parasiticAnalysisPtIndex(ap, rf); ConcreteParasitic *parasitic = parasitics[ap_rf_index]; ConcretePiPoleResidue *pi_pole_residue = nullptr; if (parasitic) { if (parasitic->isPiElmore()) { pi_pole_residue = dynamic_cast(parasitic); pi_pole_residue->setPiModel(c2, rpi, c1); } else { delete parasitic; pi_pole_residue = new ConcretePiPoleResidue(c2, rpi, c1); parasitics[ap_rf_index] = pi_pole_residue; } } else { pi_pole_residue = new ConcretePiPoleResidue(c2, rpi, c1); parasitics[ap_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(Parasitic *parasitic) const { ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic && cparasitic->isParasiticNetwork(); } Parasitic * ConcreteParasitics::findParasiticNetwork(const Net *net, const ParasiticAnalysisPt *ap) const { if (!parasitic_network_map_.empty()) { UniqueLock lock(lock_); if (!parasitic_network_map_.empty()) { ConcreteParasiticNetwork **parasitics=parasitic_network_map_.findKey(net); if (parasitics) return parasitics[ap->index()]; } } return nullptr; } Parasitic * ConcreteParasitics::findParasiticNetwork(const Pin *pin, const ParasiticAnalysisPt *ap) const { if (!parasitic_network_map_.empty()) { UniqueLock lock(lock_); if (!parasitic_network_map_.empty()) { // Only call findParasiticNet if parasitics exist. Net *net = findParasiticNet(pin); ConcreteParasiticNetwork **parasitics=parasitic_network_map_.findKey(net); if (parasitics) return parasitics[ap->index()]; } } return nullptr; } Parasitic * ConcreteParasitics::makeParasiticNetwork(const Net *net, bool includes_pin_caps, const ParasiticAnalysisPt *ap) { UniqueLock lock(lock_); ConcreteParasiticNetwork **parasitics = parasitic_network_map_.findKey(net); if (parasitics == nullptr) { int ap_count = corners_->parasiticAnalysisPtCount(); parasitics = new ConcreteParasiticNetwork*[ap_count]; for (int i = 0; i < ap_count; i++) parasitics[i] = nullptr; parasitic_network_map_[net] = parasitics; } int ap_index = ap->index(); ConcreteParasiticNetwork *parasitic = parasitics[ap_index]; if (parasitic) delete parasitic; parasitic = new ConcreteParasiticNetwork(includes_pin_caps); parasitics[ap_index] = parasitic; return parasitic; } void ConcreteParasitics::deleteParasiticNetwork(const Net *net, const ParasiticAnalysisPt *ap) { if (!parasitic_network_map_.empty()) { UniqueLock lock(lock_); ConcreteParasiticNetwork **parasitics = parasitic_network_map_.findKey(net); if (parasitics) { int ap_index = ap->index(); delete parasitics[ap_index]; parasitics[ap_index] = nullptr; } } } bool ConcreteParasitics::includesPinCaps(Parasitic *parasitic) const { ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->includesPinCaps(); } ParasiticNode * ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic, const Net *net, int id) { ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->ensureParasiticNode(net, id); } ParasiticNode * ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic, const Pin *pin) { ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->ensureParasiticNode(pin); } void ConcreteParasitics::incrCap(ParasiticNode *node, float cap, const ParasiticAnalysisPt *) { ConcreteParasiticNode *cnode = static_cast(node); cnode->incrCapacitance(cap); } void ConcreteParasitics::makeCouplingCap(const char *name, ParasiticNode *node, ParasiticNode *other_node, float cap, const ParasiticAnalysisPt *) { ConcreteParasiticNode *cnode = static_cast(node); ConcreteParasiticNode *other_cnode = static_cast(other_node); ConcreteCouplingCap *coupling_cap = new ConcreteCouplingCapInt(name, cnode, other_cnode, cap); cnode->addDevice(coupling_cap); other_cnode->addDevice(coupling_cap); } void ConcreteParasitics::makeCouplingCap(const char *name, ParasiticNode *node, Net *other_node_net, int other_node_id, float cap, const ParasiticAnalysisPt *) { ConcreteParasiticNode *cnode = static_cast(node); ConcreteCouplingCap *coupling_cap = new ConcreteCouplingCapExtNode(name, cnode, other_node_net, other_node_id, cap); cnode->addDevice(coupling_cap); } void ConcreteParasitics::makeCouplingCap(const char *name, ParasiticNode *node, Pin *other_node_pin, float cap, const ParasiticAnalysisPt *) { ConcreteParasiticNode *cnode = static_cast(node); ConcreteCouplingCap *coupling_cap = new ConcreteCouplingCapExtPin(name, cnode, other_node_pin, cap); cnode->addDevice(coupling_cap); } void ConcreteParasitics::makeResistor(const char *name, ParasiticNode *node1, ParasiticNode *node2, float res, const ParasiticAnalysisPt *) { ConcreteParasiticNode *cnode1 = static_cast(node1); ConcreteParasiticNode *cnode2 = static_cast(node2); ConcreteParasiticDevice *resistor = new ConcreteParasiticResistor(name, cnode1, cnode2, res); cnode1->addDevice(resistor); cnode2->addDevice(resistor); } ParasiticDeviceIterator * ConcreteParasitics::deviceIterator(Parasitic *parasitic) { ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic->deviceIterator(); } ParasiticNodeIterator * ConcreteParasitics::nodeIterator(Parasitic *parasitic) { ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic->nodeIterator(); } float ConcreteParasitics::nodeGndCap(const ParasiticNode *node, const ParasiticAnalysisPt *) const { const ConcreteParasiticNode *cnode = static_cast(node); return cnode->capacitance(); } const char * ConcreteParasitics::name(const ParasiticNode *node) { const ConcreteParasiticNode *cnode = static_cast(node); return cnode->name(network_); } const Pin * ConcreteParasitics::connectionPin(const ParasiticNode *node) const { const ConcreteParasiticNode *cnode = static_cast(node); if (cnode->isPinNode()) { const ConcreteParasiticPinNode *pin_node = dynamic_cast(cnode); return pin_node->pin(); } else return nullptr; } ParasiticNode * ConcreteParasitics::findNode(Parasitic *parasitic, const Pin *pin) const { ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); return cparasitic->findNode(pin); } ParasiticDeviceIterator * ConcreteParasitics::deviceIterator(ParasiticNode *node) const { ConcreteParasiticNode *cnode = static_cast(node); return new ConcreteParasiticDeviceSeqIterator(cnode->devices()); } const char * ConcreteParasitics::name(const ParasiticDevice *device) const { const ConcreteParasiticDevice *cdevice = static_cast(device); return cdevice->name(); } bool ConcreteParasitics::isResistor(const ParasiticDevice *device) const { const ConcreteParasiticDevice *cdevice = static_cast(device); return cdevice->isResistor(); } bool ConcreteParasitics::isCouplingCap(const ParasiticDevice *device) const { const ConcreteParasiticDevice *cdevice = static_cast(device); return cdevice->isCouplingCap(); } float ConcreteParasitics::value(const ParasiticDevice *device, const ParasiticAnalysisPt *) const { const ConcreteParasiticDevice *cdevice = static_cast(device); return cdevice->value(); } ParasiticNode * ConcreteParasitics::node1(const ParasiticDevice *device) const { const ConcreteParasiticDevice *cdevice = static_cast(device); return cdevice->node1(); } ParasiticNode * ConcreteParasitics::node2(const ParasiticDevice *device) const { const ConcreteParasiticDevice *cdevice = static_cast(device); return cdevice->node2(); } ParasiticNode * ConcreteParasitics::otherNode(const ParasiticDevice *device, ParasiticNode *node) const { const ConcreteParasiticDevice *cdevice = static_cast(device); return cdevice->otherNode(node); } //////////////////////////////////////////////////////////////// void ConcreteParasitics::reduceTo(Parasitic *parasitic, const Net *net, ReducedParasiticType reduce_to, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap) { switch (reduce_to) { case ReducedParasiticType::pi_elmore: reduceToPiElmore(parasitic, net, op_cond, corner, cnst_min_max, ap); break; case ReducedParasiticType::pi_pole_residue2: reduceToPiPoleResidue2(parasitic, net, op_cond, corner, cnst_min_max, ap); break; case ReducedParasiticType::arnoldi: case ReducedParasiticType::none: break; } } void ConcreteParasitics::reduceToPiElmore(Parasitic *parasitic, const Net *net, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap) { debugPrint(debug_, "parasitic_reduce", 1, "Reduce net %s", network_->pathName(net)); NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net); while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); if (network_->isDriver(pin)) { sta::reduceToPiElmore(parasitic, pin, ap->couplingCapFactor(), op_cond, corner, cnst_min_max, ap, this); } } delete pin_iter; } void ConcreteParasitics::reduceToPiElmore(Parasitic *parasitic, const Pin *drvr_pin, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap) { sta::reduceToPiElmore(parasitic, drvr_pin, ap->couplingCapFactor(), op_cond, corner, cnst_min_max, ap, this); } void ConcreteParasitics::reduceToPiPoleResidue2(Parasitic *parasitic, const Net *net, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap) { debugPrint(debug_, "parasitic_reduce", 1, "Reduce net %s", network_->pathName(net)); NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net); while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); if (network_->isDriver(pin)) sta::reduceToPiPoleResidue2(parasitic, pin, ap->couplingCapFactor(), op_cond, corner, cnst_min_max, ap, this); } delete pin_iter; } void ConcreteParasitics::reduceToPiPoleResidue2(Parasitic *parasitic, const Pin *drvr_pin, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap) { sta::reduceToPiPoleResidue2(parasitic, drvr_pin, ap->couplingCapFactor(), op_cond, corner, cnst_min_max, ap, this); } //////////////////////////////////////////////////////////////// Parasitic * ConcreteParasitics::estimatePiElmore(const Pin *drvr_pin, const RiseFall *rf, const Wireload *wireload, float fanout, float net_pin_cap, const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, const ParasiticAnalysisPt *) { float c2, rpi, c1, elmore_res, elmore_cap; bool elmore_use_load_cap; estimatePiElmore(drvr_pin, rf, wireload, fanout, net_pin_cap, op_cond, corner, min_max, this, c2, rpi, c1, elmore_res, elmore_cap, elmore_use_load_cap); if (c1 > 0.0 || c2 > 0.0) return new ConcretePiElmoreEstimated(c2, rpi, c1, elmore_res, elmore_cap, elmore_use_load_cap, rf, op_cond, corner, min_max, sdc_); else return nullptr; } //////////////////////////////////////////////////////////////// ConcreteParasiticDeviceSeqIterator:: ConcreteParasiticDeviceSeqIterator(ConcreteParasiticDeviceSeq *devices) : iter_(devices) { } ConcreteParasiticDeviceSetIterator:: ConcreteParasiticDeviceSetIterator(ConcreteParasiticDeviceSet *devices) : iter_(devices) { } ConcreteParasiticDeviceSetIterator::~ConcreteParasiticDeviceSetIterator() { delete iter_.container(); } ConcreteParasiticNodeSeqIterator:: ConcreteParasiticNodeSeqIterator(ConcreteParasiticNodeSeq *nodes) : iter_(nodes) { } ConcreteParasiticNodeSeqIterator::~ConcreteParasiticNodeSeqIterator() { delete iter_.container(); } } // namespace