1566 lines
40 KiB
C++
1566 lines
40 KiB
C++
// 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 <https://www.gnu.org/licenses/>.
|
|
//
|
|
// 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 <algorithm> // 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 "MakeConcreteParasitics.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 *)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
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<ConcretePoleResidue&>(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()
|
|
{
|
|
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<ConcreteParasiticResistor*>(resistor);
|
|
delete cresistor;
|
|
}
|
|
for (ParasiticCapacitor *capacitor : capacitors_) {
|
|
ConcreteParasiticCapacitor *ccapacitor =
|
|
reinterpret_cast<ConcreteParasiticCapacitor*>(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<ConcreteParasiticCapacitor*>(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*>(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*>(pin));
|
|
|
|
visited_nodes.insert(node);
|
|
ParasiticResistorSeq &resistors = resistor_map[node];
|
|
for (ParasiticResistor *resistor : resistors) {
|
|
if (loop_resistors.find(resistor) == loop_resistors.end()) {
|
|
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.find(onode) == visited_nodes.end())
|
|
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<ConcreteParasiticResistor*>(resistor);
|
|
cresistor->replaceNode(node, subnode);
|
|
}
|
|
for (ParasiticCapacitor *capacitor : capacitors_) {
|
|
ConcreteParasiticCapacitor *ccapacitor =
|
|
reinterpret_cast<ConcreteParasiticCapacitor*>(capacitor);
|
|
ccapacitor->replaceNode(node, subnode);
|
|
}
|
|
|
|
pin_nodes_.erase(pin);
|
|
delete node;
|
|
}
|
|
}
|
|
|
|
NetIdPairLess::NetIdPairLess(const Network *network) :
|
|
net_less_(network)
|
|
{
|
|
}
|
|
|
|
bool
|
|
NetIdPairLess::operator()(const NetIdPair &net_id1,
|
|
const NetIdPair &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 net_less_(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 (const auto [drvr, parasitics] : drvr_parasitic_map_) {
|
|
if (parasitics) {
|
|
for (int i = 0; i < ap_rf_count; i++)
|
|
delete parasitics[i];
|
|
delete [] parasitics;
|
|
}
|
|
}
|
|
drvr_parasitic_map_.clear();
|
|
|
|
for (const auto [net, parasitics] : parasitic_network_map_) {
|
|
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 rf : RiseFall::range()) {
|
|
int ap_rf_index = parasiticAnalysisPtIndex(ap, rf);
|
|
delete parasitics[ap_rf_index];
|
|
parasitics[ap_rf_index] = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::deleteParasitics(const Pin *drvr_pin)
|
|
{
|
|
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];
|
|
parasitics[i] = 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;
|
|
}
|
|
}
|
|
|
|
float
|
|
ConcreteParasitics::capacitance(const Parasitic *parasitic) const
|
|
{
|
|
const ConcreteParasitic *cparasitic = static_cast<const ConcreteParasitic*>(parasitic);
|
|
return cparasitic->capacitance();
|
|
}
|
|
|
|
bool
|
|
ConcreteParasitics::isReducedParasiticNetwork(const Parasitic *parasitic) const
|
|
{
|
|
const ConcreteParasitic *cparasitic = static_cast<const ConcreteParasitic*>(parasitic);
|
|
return cparasitic->isReducedParasiticNetwork();
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::setIsReducedParasiticNetwork(Parasitic *parasitic,
|
|
bool is_reduced)
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<ConcreteParasitic*>(parasitic);
|
|
cparasitic->setIsReduced(is_reduced);
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::disconnectPinBefore(const Pin *pin,
|
|
const Network *network)
|
|
{
|
|
if (haveParasitics()) {
|
|
deleteReducedParasitics(pin);
|
|
|
|
const 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, network);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::loadPinCapacitanceChanged(const Pin *pin)
|
|
{
|
|
// Delete reduced models that depend on load pin capacitances.
|
|
deleteReducedParasitics(pin);
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::deleteReducedParasitics(const Net *net,
|
|
const ParasiticAnalysisPt *ap)
|
|
{
|
|
if (!drvr_parasitic_map_.empty()) {
|
|
PinSet *drivers = network_->drivers(net);
|
|
if (drivers) {
|
|
for (auto drvr_pin : *drivers)
|
|
deleteDrvrReducedParasitics(drvr_pin, ap);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
LockGuard 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;
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::deleteDrvrReducedParasitics(const Pin *drvr_pin,
|
|
const ParasiticAnalysisPt *ap)
|
|
{
|
|
LockGuard lock(lock_);
|
|
ConcreteParasitic **parasitics = drvr_parasitic_map_[drvr_pin];
|
|
if (parasitics) {
|
|
int ap_index = ap->index();
|
|
delete parasitics[ap_index];
|
|
parasitics[ap_index] = nullptr;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
bool
|
|
ConcreteParasitics::isPiElmore(const Parasitic *parasitic) const
|
|
{
|
|
const ConcreteParasitic *cparasitic = static_cast<const ConcreteParasitic*>(parasitic);
|
|
return cparasitic && cparasitic->isPiElmore();
|
|
}
|
|
|
|
Parasitic *
|
|
ConcreteParasitics::findPiElmore(const Pin *drvr_pin,
|
|
const RiseFall *rf,
|
|
const ParasiticAnalysisPt *ap) const
|
|
{
|
|
LockGuard lock(lock_);
|
|
if (!drvr_parasitic_map_.empty()) {
|
|
int ap_rf_index = parasiticAnalysisPtIndex(ap, rf);
|
|
ConcreteParasitic **parasitics = drvr_parasitic_map_.findKey(drvr_pin);
|
|
if (parasitics) {
|
|
ConcreteParasitic *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)
|
|
{
|
|
LockGuard 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<ConcretePiElmore*>(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(const Parasitic *parasitic) const
|
|
{
|
|
const ConcreteParasitic *cparasitic = static_cast<const ConcreteParasitic*>(parasitic);
|
|
return cparasitic && cparasitic->isPiModel();
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::piModel(const Parasitic *parasitic,
|
|
float &c2,
|
|
float &rpi,
|
|
float &c1) const
|
|
{
|
|
const ConcreteParasitic *cparasitic = static_cast<const ConcreteParasitic*>(parasitic);
|
|
cparasitic->piModel(c2, rpi, c1);
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::setPiModel(Parasitic *parasitic,
|
|
float c2,
|
|
float rpi,
|
|
float c1)
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<ConcreteParasitic*>(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<const ConcreteParasitic*>(parasitic);
|
|
cparasitic->findElmore(load_pin, elmore, exists);
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::setElmore(Parasitic *parasitic,
|
|
const Pin *load_pin,
|
|
float elmore)
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<ConcreteParasitic*>(parasitic);
|
|
cparasitic->setElmore(load_pin, elmore);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
bool
|
|
ConcreteParasitics::isPiPoleResidue(const Parasitic* parasitic) const
|
|
{
|
|
const ConcreteParasitic *cparasitic = static_cast<const ConcreteParasitic*>(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);
|
|
LockGuard 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->isPiPoleResidue())
|
|
return parasitic;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Parasitic *
|
|
ConcreteParasitics::makePiPoleResidue(const Pin *drvr_pin,
|
|
const RiseFall *rf,
|
|
const ParasiticAnalysisPt *ap,
|
|
float c2,
|
|
float rpi,
|
|
float c1)
|
|
{
|
|
LockGuard 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<ConcretePiPoleResidue*>(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<const ConcreteParasitic*>(parasitic);
|
|
return cparasitic->findPoleResidue(load_pin);
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::setPoleResidue(Parasitic *parasitic,
|
|
const Pin *load_pin,
|
|
ComplexFloatSeq *poles,
|
|
ComplexFloatSeq *residues)
|
|
{
|
|
ConcreteParasitic *cparasitic =
|
|
static_cast<ConcreteParasitic*>(parasitic);
|
|
cparasitic->setPoleResidue(load_pin, poles, residues);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
bool
|
|
ConcreteParasitics::isPoleResidue(const Parasitic *parasitic) const
|
|
{
|
|
const ConcreteParasitic *cparasitic =
|
|
static_cast<const ConcreteParasitic*>(parasitic);
|
|
return cparasitic->isPoleResidue();
|
|
}
|
|
|
|
size_t
|
|
ConcreteParasitics::poleResidueCount(const Parasitic *parasitic) const
|
|
{
|
|
const ConcretePoleResidue *pr_parasitic =
|
|
static_cast<const ConcretePoleResidue*>(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<const ConcretePoleResidue*>(parasitic);
|
|
pr_parasitic->poleResidue(pole_index, pole, residue);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
bool
|
|
ConcreteParasitics::isParasiticNetwork(const Parasitic *parasitic) const
|
|
{
|
|
const ConcreteParasitic *cparasitic = static_cast<const ConcreteParasitic*>(parasitic);
|
|
return cparasitic && cparasitic->isParasiticNetwork();
|
|
}
|
|
|
|
Parasitic *
|
|
ConcreteParasitics::findParasiticNetwork(const Net *net,
|
|
const ParasiticAnalysisPt *ap) const
|
|
{
|
|
if (!parasitic_network_map_.empty()) {
|
|
LockGuard lock(lock_);
|
|
if (!parasitic_network_map_.empty()) {
|
|
ConcreteParasiticNetwork **parasitics=parasitic_network_map_.findKey(net);
|
|
if (parasitics) {
|
|
ConcreteParasiticNetwork *parasitic = parasitics[ap->index()];
|
|
if (parasitic == nullptr)
|
|
parasitic = parasitics[ap->indexMax()];
|
|
return parasitic;
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Parasitic *
|
|
ConcreteParasitics::findParasiticNetwork(const Pin *pin,
|
|
const ParasiticAnalysisPt *ap) const
|
|
{
|
|
if (!parasitic_network_map_.empty()) {
|
|
LockGuard lock(lock_);
|
|
if (!parasitic_network_map_.empty()) {
|
|
// Only call findParasiticNet if parasitics exist.
|
|
const Net *net = findParasiticNet(pin);
|
|
ConcreteParasiticNetwork **parasitics=parasitic_network_map_.findKey(net);
|
|
if (parasitics) {
|
|
ConcreteParasiticNetwork *parasitic = parasitics[ap->index()];
|
|
if (parasitic == nullptr)
|
|
parasitic = parasitics[ap->indexMax()];
|
|
return parasitic;
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Parasitic *
|
|
ConcreteParasitics::makeParasiticNetwork(const Net *net,
|
|
bool includes_pin_caps,
|
|
const ParasiticAnalysisPt *ap)
|
|
{
|
|
LockGuard 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;
|
|
if (net) {
|
|
for (const Pin *drvr_pin : *network_->drivers(net))
|
|
deleteParasitics(drvr_pin);
|
|
}
|
|
}
|
|
parasitic = new ConcreteParasiticNetwork(net, includes_pin_caps, network_);
|
|
parasitics[ap_index] = parasitic;
|
|
return parasitic;
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::deleteParasiticNetwork(const Net *net,
|
|
const ParasiticAnalysisPt *ap)
|
|
{
|
|
if (!parasitic_network_map_.empty()) {
|
|
LockGuard lock(lock_);
|
|
ConcreteParasiticNetwork **parasitics = parasitic_network_map_.findKey(net);
|
|
if (parasitics) {
|
|
int ap_index = ap->index();
|
|
delete parasitics[ap_index];
|
|
parasitics[ap_index] = nullptr;
|
|
|
|
int ap_count = corners_->parasiticAnalysisPtCount();
|
|
bool have_parasitics = false;
|
|
for (int i = 0; i < ap_count; i++) {
|
|
if (parasitics[i]) {
|
|
have_parasitics = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!have_parasitics) {
|
|
delete [] parasitics;
|
|
parasitic_network_map_.erase(net);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::deleteParasiticNetworks(const Net *net)
|
|
{
|
|
if (!parasitic_network_map_.empty()) {
|
|
LockGuard lock(lock_);
|
|
ConcreteParasiticNetwork **parasitics = parasitic_network_map_.findKey(net);
|
|
if (parasitics) {
|
|
int ap_count = corners_->parasiticAnalysisPtCount();
|
|
for (int i = 0; i < ap_count; i++)
|
|
delete parasitics[i];
|
|
delete [] parasitics;
|
|
parasitic_network_map_.erase(net);
|
|
}
|
|
}
|
|
}
|
|
|
|
const Net *
|
|
ConcreteParasitics::net(const Parasitic *parasitic) const
|
|
{
|
|
const ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<const ConcreteParasiticNetwork*>(parasitic);
|
|
if (cparasitic->isParasiticNetwork())
|
|
return cparasitic->net();
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
bool
|
|
ConcreteParasitics::includesPinCaps(const Parasitic *parasitic) const
|
|
{
|
|
const ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<const ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->includesPinCaps();
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::findParasiticNode(Parasitic *parasitic,
|
|
const Net *net,
|
|
int id,
|
|
const Network *network) const
|
|
{
|
|
const ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<const ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->findParasiticNode(net, id, network);
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic,
|
|
const Net *net,
|
|
int id,
|
|
const Network *network)
|
|
{
|
|
ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->ensureParasiticNode(net, id, network);
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::findParasiticNode(const Parasitic *parasitic,
|
|
const Pin *pin) const
|
|
{
|
|
const ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<const ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->findParasiticNode(pin);
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic,
|
|
const Pin *pin,
|
|
const Network *network)
|
|
{
|
|
ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->ensureParasiticNode(pin, network);
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::incrCap(ParasiticNode *node,
|
|
float cap)
|
|
{
|
|
ConcreteParasiticNode *cnode = static_cast<ConcreteParasiticNode*>(node);
|
|
cnode->incrCapacitance(cap);
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::makeCapacitor(Parasitic *parasitic,
|
|
size_t index,
|
|
float cap,
|
|
ParasiticNode *node1,
|
|
ParasiticNode *node2)
|
|
{
|
|
ConcreteParasiticNode *cnode1 = static_cast<ConcreteParasiticNode*>(node1);
|
|
ConcreteParasiticNode *cnode2 = static_cast<ConcreteParasiticNode*>(node2);
|
|
ConcreteParasiticCapacitor *capacitor =
|
|
new ConcreteParasiticCapacitor(index, cap, cnode1, cnode2);
|
|
ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<ConcreteParasiticNetwork*>(parasitic);
|
|
cparasitic->addCapacitor(capacitor);
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::makeResistor(Parasitic *parasitic,
|
|
size_t index,
|
|
float res,
|
|
ParasiticNode *node1,
|
|
ParasiticNode *node2)
|
|
{
|
|
ConcreteParasiticNode *cnode1 = static_cast<ConcreteParasiticNode*>(node1);
|
|
ConcreteParasiticNode *cnode2 = static_cast<ConcreteParasiticNode*>(node2);
|
|
ParasiticResistor *resistor = new ConcreteParasiticResistor(index, res,
|
|
cnode1, cnode2);
|
|
ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<ConcreteParasiticNetwork*>(parasitic);
|
|
cparasitic->addResistor(resistor);
|
|
}
|
|
|
|
ParasiticNodeSeq
|
|
ConcreteParasitics::nodes(const Parasitic *parasitic) const
|
|
{
|
|
const ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<const ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->nodes();
|
|
}
|
|
|
|
ParasiticResistorSeq
|
|
ConcreteParasitics::resistors(const Parasitic *parasitic) const
|
|
{
|
|
const ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<const ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->resistors();
|
|
}
|
|
|
|
ParasiticCapacitorSeq
|
|
ConcreteParasitics::capacitors(const Parasitic *parasitic) const
|
|
{
|
|
const ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<const ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->capacitors();
|
|
}
|
|
|
|
|
|
const char *
|
|
ConcreteParasitics::name(const ParasiticNode *node) const
|
|
{
|
|
const ConcreteParasiticNode *cnode =
|
|
static_cast<const ConcreteParasiticNode*>(node);
|
|
return cnode->name(network_);
|
|
}
|
|
|
|
float
|
|
ConcreteParasitics::nodeGndCap(const ParasiticNode *node) const
|
|
{
|
|
const ConcreteParasiticNode *cnode =
|
|
static_cast<const ConcreteParasiticNode*>(node);
|
|
return cnode->capacitance();
|
|
}
|
|
|
|
const Pin *
|
|
ConcreteParasitics::pin(const ParasiticNode *node) const
|
|
{
|
|
const ConcreteParasiticNode *cnode =
|
|
static_cast<const ConcreteParasiticNode*>(node);
|
|
return cnode->pin();
|
|
}
|
|
|
|
const Net *
|
|
ConcreteParasitics::net(const ParasiticNode *node,
|
|
const Network *network) const
|
|
{
|
|
const ConcreteParasiticNode *cnode =
|
|
static_cast<const ConcreteParasiticNode*>(node);
|
|
return cnode->net(network);
|
|
}
|
|
|
|
unsigned
|
|
ConcreteParasitics::netId(const ParasiticNode *node) const
|
|
{
|
|
const ConcreteParasiticNode *cnode =
|
|
static_cast<const ConcreteParasiticNode*>(node);
|
|
return cnode->id();
|
|
}
|
|
|
|
bool
|
|
ConcreteParasitics::isExternal(const ParasiticNode *node) const
|
|
{
|
|
const ConcreteParasiticNode *cnode =
|
|
static_cast<const ConcreteParasiticNode*>(node);
|
|
return cnode->isExternal();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
size_t
|
|
ConcreteParasitics::id(const ParasiticResistor *resistor) const
|
|
{
|
|
const ConcreteParasiticResistor *cresistor =
|
|
static_cast<const ConcreteParasiticResistor*>(resistor);
|
|
return cresistor->id();
|
|
}
|
|
|
|
float
|
|
ConcreteParasitics::value(const ParasiticResistor *resistor) const
|
|
{
|
|
const ConcreteParasiticResistor *cresistor =
|
|
static_cast<const ConcreteParasiticResistor*>(resistor);
|
|
return cresistor->value();
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::node1(const ParasiticResistor *resistor) const
|
|
{
|
|
const ConcreteParasiticResistor *cresistor =
|
|
static_cast<const ConcreteParasiticResistor*>(resistor);
|
|
return cresistor->node1();
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::node2(const ParasiticResistor *resistor) const
|
|
{
|
|
const ConcreteParasiticResistor *cresistor =
|
|
static_cast<const ConcreteParasiticResistor*>(resistor);
|
|
return cresistor->node2();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
size_t
|
|
ConcreteParasitics::id(const ParasiticCapacitor *capacitor) const
|
|
{
|
|
const ConcreteParasiticCapacitor *ccapacitor =
|
|
static_cast<const ConcreteParasiticCapacitor*>(capacitor);
|
|
return ccapacitor->id();
|
|
}
|
|
|
|
float
|
|
ConcreteParasitics::value(const ParasiticCapacitor *capacitor) const
|
|
{
|
|
const ConcreteParasiticCapacitor *ccapacitor =
|
|
static_cast<const ConcreteParasiticCapacitor*>(capacitor);
|
|
return ccapacitor->value();
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::node1(const ParasiticCapacitor *capacitor) const
|
|
{
|
|
const ConcreteParasiticCapacitor *ccapacitor =
|
|
static_cast<const ConcreteParasiticCapacitor*>(capacitor);
|
|
return ccapacitor->node1();
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::node2(const ParasiticCapacitor *capacitor) const
|
|
{
|
|
const ConcreteParasiticCapacitor *ccapacitor =
|
|
static_cast<const ConcreteParasiticCapacitor*>(capacitor);
|
|
return ccapacitor->node2();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
PinSet
|
|
ConcreteParasitics::unannotatedLoads(const Parasitic *parasitic,
|
|
const Pin *drvr_pin) const
|
|
{
|
|
const ConcreteParasitic *cparasitic = static_cast<const ConcreteParasitic*>(parasitic);
|
|
return cparasitic->unannotatedLoads(drvr_pin, this);
|
|
}
|
|
|
|
} // namespace
|