1714 lines
41 KiB
C++
1714 lines
41 KiB
C++
// 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 <https://www.gnu.org/licenses/>.
|
|
|
|
#include "ConcreteParasitics.hh"
|
|
|
|
#include <limits>
|
|
#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 "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<ConcreteParasitic*>(parasitic);
|
|
delete cparasitic;
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::save()
|
|
{
|
|
// No database to save to.
|
|
}
|
|
|
|
float
|
|
ConcreteParasitics::capacitance(Parasitic *parasitic) const
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<ConcreteParasitic*>(parasitic);
|
|
return cparasitic->capacitance();
|
|
}
|
|
|
|
bool
|
|
ConcreteParasitics::isReducedParasiticNetwork(Parasitic *parasitic) const
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<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)
|
|
{
|
|
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<ConcreteParasitic*>(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<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(Parasitic *parasitic) const
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<ConcreteParasitic*>(parasitic);
|
|
return cparasitic && cparasitic->isPiModel();
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::piModel(Parasitic *parasitic,
|
|
float &c2,
|
|
float &rpi,
|
|
float &c1) const
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<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(Parasitic *parasitic,
|
|
const Pin *load_pin,
|
|
float &elmore,
|
|
bool &exists) const
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<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(Parasitic* parasitic) const
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<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);
|
|
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<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(Parasitic *parasitic) const
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<ConcreteParasitic*>(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<ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->includesPinCaps();
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic,
|
|
const Net *net,
|
|
int id)
|
|
{
|
|
ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->ensureParasiticNode(net, id);
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic,
|
|
const Pin *pin)
|
|
{
|
|
ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->ensureParasiticNode(pin);
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::incrCap(ParasiticNode *node,
|
|
float cap,
|
|
const ParasiticAnalysisPt *)
|
|
{
|
|
ConcreteParasiticNode *cnode = static_cast<ConcreteParasiticNode*>(node);
|
|
cnode->incrCapacitance(cap);
|
|
}
|
|
|
|
void
|
|
ConcreteParasitics::makeCouplingCap(const char *name,
|
|
ParasiticNode *node,
|
|
ParasiticNode *other_node,
|
|
float cap,
|
|
const ParasiticAnalysisPt *)
|
|
{
|
|
ConcreteParasiticNode *cnode = static_cast<ConcreteParasiticNode*>(node);
|
|
ConcreteParasiticNode *other_cnode =
|
|
static_cast<ConcreteParasiticNode*>(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<ConcreteParasiticNode*>(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<ConcreteParasiticNode*>(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<ConcreteParasiticNode*>(node1);
|
|
ConcreteParasiticNode *cnode2 = static_cast<ConcreteParasiticNode*>(node2);
|
|
ConcreteParasiticDevice *resistor =
|
|
new ConcreteParasiticResistor(name, cnode1, cnode2, res);
|
|
cnode1->addDevice(resistor);
|
|
cnode2->addDevice(resistor);
|
|
}
|
|
|
|
ParasiticDeviceIterator *
|
|
ConcreteParasitics::deviceIterator(Parasitic *parasitic)
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<ConcreteParasitic*>(parasitic);
|
|
return cparasitic->deviceIterator();
|
|
}
|
|
|
|
ParasiticNodeIterator *
|
|
ConcreteParasitics::nodeIterator(Parasitic *parasitic)
|
|
{
|
|
ConcreteParasitic *cparasitic = static_cast<ConcreteParasitic*>(parasitic);
|
|
return cparasitic->nodeIterator();
|
|
}
|
|
|
|
float
|
|
ConcreteParasitics::nodeGndCap(const ParasiticNode *node,
|
|
const ParasiticAnalysisPt *) const
|
|
{
|
|
const ConcreteParasiticNode *cnode =
|
|
static_cast<const ConcreteParasiticNode*>(node);
|
|
return cnode->capacitance();
|
|
}
|
|
|
|
const char *
|
|
ConcreteParasitics::name(const ParasiticNode *node)
|
|
{
|
|
const ConcreteParasiticNode *cnode =
|
|
static_cast<const ConcreteParasiticNode*>(node);
|
|
return cnode->name(network_);
|
|
}
|
|
|
|
const Pin *
|
|
ConcreteParasitics::connectionPin(const ParasiticNode *node) const
|
|
{
|
|
const ConcreteParasiticNode *cnode =
|
|
static_cast<const ConcreteParasiticNode*>(node);
|
|
if (cnode->isPinNode()) {
|
|
const ConcreteParasiticPinNode *pin_node =
|
|
dynamic_cast<const ConcreteParasiticPinNode*>(cnode);
|
|
return pin_node->pin();
|
|
}
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::findNode(Parasitic *parasitic,
|
|
const Pin *pin) const
|
|
{
|
|
ConcreteParasiticNetwork *cparasitic =
|
|
static_cast<ConcreteParasiticNetwork*>(parasitic);
|
|
return cparasitic->findNode(pin);
|
|
}
|
|
|
|
ParasiticDeviceIterator *
|
|
ConcreteParasitics::deviceIterator(ParasiticNode *node) const
|
|
{
|
|
ConcreteParasiticNode *cnode = static_cast<ConcreteParasiticNode*>(node);
|
|
return new ConcreteParasiticDeviceSeqIterator(cnode->devices());
|
|
}
|
|
|
|
const char *
|
|
ConcreteParasitics::name(const ParasiticDevice *device) const
|
|
{
|
|
const ConcreteParasiticDevice *cdevice =
|
|
static_cast<const ConcreteParasiticDevice*>(device);
|
|
return cdevice->name();
|
|
}
|
|
|
|
bool
|
|
ConcreteParasitics::isResistor(const ParasiticDevice *device) const
|
|
{
|
|
const ConcreteParasiticDevice *cdevice =
|
|
static_cast<const ConcreteParasiticDevice*>(device);
|
|
return cdevice->isResistor();
|
|
}
|
|
|
|
bool
|
|
ConcreteParasitics::isCouplingCap(const ParasiticDevice *device) const
|
|
{
|
|
const ConcreteParasiticDevice *cdevice =
|
|
static_cast<const ConcreteParasiticDevice*>(device);
|
|
return cdevice->isCouplingCap();
|
|
}
|
|
|
|
float
|
|
ConcreteParasitics::value(const ParasiticDevice *device,
|
|
const ParasiticAnalysisPt *) const
|
|
{
|
|
const ConcreteParasiticDevice *cdevice =
|
|
static_cast<const ConcreteParasiticDevice*>(device);
|
|
return cdevice->value();
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::node1(const ParasiticDevice *device) const
|
|
{
|
|
const ConcreteParasiticDevice *cdevice =
|
|
static_cast<const ConcreteParasiticDevice*>(device);
|
|
return cdevice->node1();
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::node2(const ParasiticDevice *device) const
|
|
{
|
|
const ConcreteParasiticDevice *cdevice =
|
|
static_cast<const ConcreteParasiticDevice*>(device);
|
|
return cdevice->node2();
|
|
}
|
|
|
|
ParasiticNode *
|
|
ConcreteParasitics::otherNode(const ParasiticDevice *device,
|
|
ParasiticNode *node) const
|
|
{
|
|
const ConcreteParasiticDevice *cdevice =
|
|
static_cast<const ConcreteParasiticDevice*>(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
|