Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Matt Liberty 2025-11-13 03:32:56 +00:00
commit 7b4cea532b
30 changed files with 522 additions and 888 deletions

View File

@ -202,7 +202,6 @@ set(STA_SOURCE
search/TagGroup.cc
search/VertexVisitor.cc
search/VisitPathEnds.cc
search/VisitPathGroupVertices.cc
search/WorstSlack.cc
spice/WritePathSpice.cc

View File

@ -50,6 +50,9 @@ The following classes now return const objects.
Transition
TimingRole
Liberty PgPorts are now LibertyPorts with additional member functions for
liberty pg_pins.
Release 2.6.1 2025/03/??
-------------------------

View File

@ -17,6 +17,8 @@ to remove paths through identical pins and rise/fall edges.
report_checks [-unique_edges_to_endpoint]
Instances now have pins for verilog netlist power/ground connections,
Release 2.6.1 2025/03/30
-------------------------

View File

@ -43,7 +43,6 @@ class WriteTimingModel;
class LibertyCellIterator;
class LibertyCellPortIterator;
class LibertyCellPortBitIterator;
class LibertyCellPgPortIterator;
class LibertyPortMemberIterator;
class ModeValueDef;
class TestCell;
@ -56,7 +55,6 @@ class LibertyReader;
class OcvDerate;
class TimingArcAttrs;
class InternalPowerAttrs;
class LibertyPgPort;
class StaState;
class Corner;
class Corners;
@ -90,7 +88,6 @@ typedef Vector<LatchEnable*> LatchEnableSeq;
typedef Map<const char *, OcvDerate*, CharPtrLess> OcvDerateMap;
typedef Vector<InternalPowerAttrs*> InternalPowerAttrsSeq;
typedef Map<std::string, float> SupplyVoltageMap;
typedef Map<std::string, LibertyPgPort*> LibertyPgPortMap;
typedef Map<std::string, DriverWaveform*> DriverWaveformMap;
typedef Vector<DcalcAnalysisPt*> DcalcAnalysisPtSeq;
@ -100,6 +97,12 @@ enum class DelayModelType { cmos_linear, cmos_pwl, cmos2, table, polynomial, dcm
enum class ScanSignalType { enable, enable_inverted, clock, clock_a, clock_b,
input, input_inverted, output, output_inverted, none };
enum class PwrGndType { none,
primary_power, primary_ground,
backup_power, backup_ground,
internal_power, internal_ground,
nwell, pwell,
deepnwell, deeppwell};
enum class ScaleFactorPvt { process, volt, temp, unknown };
constexpr int scale_factor_pvt_count = int(ScaleFactorPvt::unknown) + 1;
@ -423,8 +426,6 @@ public:
LibertyPort *findLibertyPort(const char *name) const;
LibertyPortSeq findLibertyPortsMatching(PatternMatch *pattern) const;
bool hasInternalPorts() const { return has_internal_ports_; }
LibertyPgPort *findPgPort(const char *name) const;
size_t pgPortCount() const { return pg_port_map_.size(); }
ScaleFactors *scaleFactors() const { return scale_factors_; }
void setScaleFactors(ScaleFactors *scale_factors);
ModeDef *makeModeDef(const char *name);
@ -533,7 +534,6 @@ public:
void setOcvArcDepth(float depth);
void setOcvDerate(OcvDerate *derate);
void addOcvDerate(OcvDerate *derate);
void addPgPort(LibertyPgPort *pg_port);
void setTestCell(TestCell *test);
void setHasInferedRegTimingArcs(bool infered);
void setIsDisabledConstraint(bool is_disabled);
@ -643,7 +643,6 @@ protected:
Vector<LibertyCell*> corner_cells_;
float leakage_power_;
bool leakage_power_exists_;
LibertyPgPortMap pg_port_map_;
bool has_internal_ports_;
std::atomic<bool> have_voltage_waveforms_;
std::mutex waveform_lock_;
@ -653,7 +652,6 @@ protected:
private:
friend class LibertyLibrary;
friend class LibertyCellPortIterator;
friend class LibertyCellPgPortIterator;
friend class LibertyPort;
friend class LibertyBuilder;
};
@ -681,17 +679,6 @@ private:
ConcreteCellPortBitIterator *iter_;
};
class LibertyCellPgPortIterator : public Iterator<LibertyPgPort*>
{
public:
LibertyCellPgPortIterator(const LibertyCell *cell);
bool hasNext();
LibertyPgPort *next();
private:
LibertyPgPortMap::Iterator iter_;
};
////////////////////////////////////////////////////////////////
class LibertyPort : public ConcretePort
@ -704,6 +691,16 @@ public:
LibertyPort *bundlePort() const;
BusDcl *busDcl() const { return bus_dcl_; }
void setDirection(PortDirection *dir);
////////////////////////////////////////////////////////////////
// pg_pin functions
bool isPwrGnd() const;
PwrGndType pwrGndType() const { return pwr_gnd_type_; }
void setPwrGndType(PwrGndType type);
const char *voltageName() const { return voltage_name_.c_str(); }
void setVoltageName(const char *voltage_name);
////////////////////////////////////////////////////////////////
ScanSignalType scanSignalType() const { return scan_signal_type_; }
void setScanSignalType(ScanSignalType type);
void fanoutLoad(// Return values.
@ -887,8 +884,10 @@ protected:
LibertyCell *liberty_cell_;
BusDcl *bus_dcl_;
FuncExpr *function_;
PwrGndType pwr_gnd_type_;
std::string voltage_name_;
ScanSignalType scan_signal_type_;
FuncExpr *function_;
FuncExpr *tristate_enable_;
ScaledPortMap *scaled_ports_;
RiseFallMinMax capacitance_;
@ -1136,37 +1135,13 @@ private:
TablePtr derate_[RiseFall::index_count][EarlyLate::index_count][path_type_count];
};
// Power/ground port.
class LibertyPgPort
{
public:
enum PgType { unknown,
primary_power, primary_ground,
backup_power, backup_ground,
internal_power, internal_ground,
nwell, pwell,
deepnwell, deeppwell};
LibertyPgPort(const char *name,
LibertyCell *cell);
const char *name() const { return name_.c_str(); }
LibertyCell *cell() const { return cell_; }
PgType pgType() const { return pg_type_; }
void setPgType(PgType type);
const char *voltageName() const { return voltage_name_.c_str(); }
void setVoltageName(const char *voltage_name);
static bool equiv(const LibertyPgPort *port1,
const LibertyPgPort *port2);
private:
std::string name_;
PgType pg_type_;
std::string voltage_name_;
LibertyCell *cell_;
};
std::string
portLibertyToSta(const char *port_name);
const char *
scanSignalTypeName(ScanSignalType scan_type);
const char *
pwrGndTypeName(PwrGndType pwr_gnd_type);
PwrGndType
findPwrGndType(const char *pg_name);
} // namespace

View File

@ -136,15 +136,15 @@ typedef Set<InputDelay*> InputDelaySet;
typedef Map<const Pin*, InputDelaySet*, PinIdLess> InputDelaysPinMap;
typedef Set<OutputDelay*> OutputDelaySet;
typedef Map<const Pin*,OutputDelaySet*, PinIdLess> OutputDelaysPinMap;
typedef UnorderedMap<const Pin*,ExceptionPathSet*> PinExceptionsMap;
typedef Map<const Clock*,ExceptionPathSet*> ClockExceptionsMap;
typedef Map<const Instance*,ExceptionPathSet*> InstanceExceptionsMap;
typedef Map<const Net*,ExceptionPathSet*> NetExceptionsMap;
typedef UnorderedMap<EdgePins, ExceptionPathSet*,
typedef UnorderedMap<const Pin*,ExceptionPathSet> PinExceptionsMap;
typedef UnorderedMap<const Clock*,ExceptionPathSet> ClockExceptionsMap;
typedef UnorderedMap<const Instance*,ExceptionPathSet> InstanceExceptionsMap;
typedef UnorderedMap<const Net*,ExceptionPathSet> NetExceptionsMap;
typedef UnorderedMap<EdgePins, ExceptionPathSet,
PinPairHash, PinPairEqual> EdgeExceptionsMap;
typedef Vector<ExceptionThru*> ExceptionThruSeq;
typedef Map<const Port*,InputDrive*> InputDriveMap;
typedef Map<size_t, ExceptionPathSet*, std::less<size_t> > ExceptionPathPtHash;
typedef Map<size_t, ExceptionPathSet, std::less<size_t>> ExceptionPathPtHash;
typedef Set<ClockLatency*, ClockLatencyLess> ClockLatencies;
typedef Map<const Pin*, ClockUncertainties*> PinClockUncertaintyMap;
typedef Set<InterClockUncertainty*, InterClockUncertaintyLess> InterClockUncertaintySet;
@ -1018,7 +1018,7 @@ public:
const PinSet &pathDelayInternalFrom() const;
bool isPathDelayInternalTo(const Pin *pin) const;
bool isPathDelayInternalToBreak(const Pin *pin) const;
ExceptionPathSet *exceptions() { return &exceptions_; }
ExceptionPathSet &exceptions() { return exceptions_; }
void deleteExceptions();
void deleteException(ExceptionPath *exception);
void recordException(ExceptionPath *exception);
@ -1043,7 +1043,6 @@ protected:
void removeLibertyAnnotations();
void deleteExceptionsReferencing(Clock *clk);
void deleteClkPinMappings(Clock *clk);
void deleteExceptionPtHashMapSets(ExceptionPathPtHash &map);
void makeClkPinMappings(Clock *clk);
void deletePinClocks(Clock *defining_clk,
PinSet *pins);

View File

@ -95,7 +95,7 @@ typedef Set<LibertyPortPair, LibertyPortPairLess> LibertyPortPairSet;
typedef Map<const Instance*, DisabledInstancePorts*> DisabledInstancePortsMap;
typedef Map<LibertyCell*, DisabledCellPorts*> DisabledCellPortsMap;
typedef MinMaxValues<float> ClockUncertainties;
typedef Set<ExceptionPath*> ExceptionPathSet;
typedef std::set<ExceptionPath*> ExceptionPathSet;
typedef PinPair EdgePins;
typedef PinPairSet EdgePinsSet;
typedef Map<const Pin*, LogicValue> LogicValueMap;

View File

@ -907,9 +907,6 @@ public:
PinSet endpointPins();
VertexSet *endpoints();
int endpointViolationCount(const MinMax *min_max);
// Find the fanin vertices for a group path.
// Vertices in the clock network are NOT included.
PinSet findGroupPathPins(const char *group_path_name);
// Find all required times after updateTiming().
void findRequireds();
std::string reportDelayCalc(Edge *edge,

View File

@ -67,17 +67,9 @@ static unsigned
hashFuncExpr(const FuncExpr *expr);
static unsigned
hashPort(const LibertyPort *port);
static unsigned
hashCellPgPorts(const LibertyCell *cell);
static unsigned
hashPgPort(const LibertyPgPort *port);
static bool
cellHasFuncs(const LibertyCell *cell);
static bool
equivCellPgPorts(const LibertyCell *cell1,
const LibertyCell *cell2);
static float
cellDriveResistance(const LibertyCell *cell)
{
@ -201,7 +193,6 @@ static unsigned
hashCell(const LibertyCell *cell)
{
return hashCellPorts(cell)
+ hashCellPgPorts(cell)
+ hashCellSequentials(cell);
}
@ -226,25 +217,6 @@ hashPort(const LibertyPort *port)
+ port->direction()->index() * 5;
}
static unsigned
hashCellPgPorts(const LibertyCell *cell)
{
unsigned hash = 0;
LibertyCellPgPortIterator port_iter(cell);
while (port_iter.hasNext()) {
LibertyPgPort *port = port_iter.next();
hash += hashPgPort(port);
}
return hash;
}
static unsigned
hashPgPort(const LibertyPgPort *port)
{
return hashString(port->name()) * 3
+ static_cast<int>(port->pgType()) * 5;
}
static unsigned
hashCellSequentials(const LibertyCell *cell)
{
@ -333,7 +305,6 @@ equivCells(const LibertyCell *cell1,
{
return equivCellPorts(cell1, cell2)
&& equivCellFuncs(cell1, cell2)
&& equivCellPgPorts(cell1, cell2)
&& equivCellSequentials(cell1, cell2)
&& equivCellStatetables(cell1, cell2)
// Reqwuire timing arc equivalence if there are no functions.
@ -347,7 +318,6 @@ equivCellsArcs(const LibertyCell *cell1,
{
return equivCellPorts(cell1, cell2)
&& equivCellFuncs(cell1, cell2)
&& equivCellPgPorts(cell1, cell2)
&& equivCellSequentials(cell1, cell2)
&& equivCellStatetables(cell1, cell2)
// Reqwuire timing arc equivalence if there are no functions.
@ -403,25 +373,6 @@ equivCellPorts(const LibertyCell *cell1,
}
}
static bool
equivCellPgPorts(const LibertyCell *cell1,
const LibertyCell *cell2)
{
if (cell1->pgPortCount() != cell2->pgPortCount())
return false;
else {
LibertyCellPgPortIterator port_iter1(cell1);
while (port_iter1.hasNext()) {
LibertyPgPort *port1 = port_iter1.next();
const char* name = port1->name();
LibertyPgPort *port2 = cell2->findPgPort(name);
if (!(port2 && LibertyPgPort::equiv(port1, port2)))
return false;
}
return true;
}
}
bool
equivCellSequentials(const LibertyCell *cell1,
const LibertyCell *cell2)

View File

@ -975,8 +975,6 @@ LibertyCell::~LibertyCell()
delete test_cell_;
ocv_derate_map_.deleteContents();
pg_port_map_.deleteContents();
}
LibertyPort *
@ -1021,18 +1019,6 @@ LibertyCell::setHasInternalPorts(bool has_internal)
has_internal_ports_ = has_internal;
}
void
LibertyCell::addPgPort(LibertyPgPort *pg_port)
{
pg_port_map_[pg_port->name()] = pg_port;
}
LibertyPgPort *
LibertyCell::findPgPort(const char *name) const
{
return pg_port_map_.findKey(name);
}
ModeDef *
LibertyCell::makeModeDef(const char *name)
{
@ -2093,8 +2079,9 @@ LibertyPort::LibertyPort(LibertyCell *cell,
ConcretePort(name, is_bus, from_index, to_index, is_bundle, members, cell),
liberty_cell_(cell),
bus_dcl_(bus_dcl),
function_(nullptr),
pwr_gnd_type_(PwrGndType::none),
scan_signal_type_(ScanSignalType::none),
function_(nullptr),
tristate_enable_(nullptr),
scaled_ports_(nullptr),
fanout_load_(0.0),
@ -2168,6 +2155,50 @@ static EnumNameMap<ScanSignalType> scan_signal_type_map =
{ScanSignalType::output_inverted, "output_inverted"},
{ScanSignalType::none, "none"}};
bool
LibertyPort::isPwrGnd() const
{
return pwr_gnd_type_ != PwrGndType::none;
}
void
LibertyPort::setPwrGndType(PwrGndType type)
{
pwr_gnd_type_ = type;
}
void
LibertyPort::setVoltageName(const char *voltage_name)
{
voltage_name_ = voltage_name;
}
static EnumNameMap<PwrGndType> pwr_gnd_type_map =
{{PwrGndType::none, "node"},
{PwrGndType::primary_power, "primary_power"},
{PwrGndType::primary_ground, "primary_ground"},
{PwrGndType::backup_power, "backup_power"},
{PwrGndType::backup_ground, "backup_ground"},
{PwrGndType::internal_power, "internal_power"},
{PwrGndType::internal_ground, "internal_ground"},
{PwrGndType::nwell, "nwell"},
{PwrGndType::pwell, "pwell"},
{PwrGndType::deepnwell, "deepnwell"},
{PwrGndType::deeppwell, "deeppwell"}};
const char *
pwrGndTypeName(PwrGndType pg_type)
{
return pwr_gnd_type_map.find(pg_type);
}
PwrGndType
findPwrGndType(const char *pg_name)
{
return pwr_gnd_type_map.find(pg_name, PwrGndType::none);
}
////////////////////////////////////////////////////////////////
const char *
scanSignalTypeName(ScanSignalType scan_type)
@ -2526,7 +2557,8 @@ LibertyPort::equiv(const LibertyPort *port1,
return (port1 == nullptr && port2 == nullptr)
|| (port1 != nullptr && port2 != nullptr
&& stringEq(port1->name(), port2->name())
&& port1->direction() == port2->direction());
&& port1->direction() == port2->direction()
&& port1->pwr_gnd_type_ == port2->pwr_gnd_type_);
}
bool
@ -3330,56 +3362,4 @@ OcvDerate::setDerateTable(const RiseFall *rf,
derate_[rf->index()][early_late->index()][int(path_type)] = derate;
}
////////////////////////////////////////////////////////////////
LibertyPgPort::LibertyPgPort(const char *name,
LibertyCell *cell) :
name_(name),
pg_type_(unknown),
cell_(cell)
{
}
void
LibertyPgPort::setPgType(PgType type)
{
pg_type_ = type;
}
void
LibertyPgPort::setVoltageName(const char *voltage_name)
{
voltage_name_ = voltage_name;
}
bool
LibertyPgPort::equiv(const LibertyPgPort *port1,
const LibertyPgPort *port2)
{
return port1->name_ == port2->name_
&& port1->pg_type_ == port2->pg_type_;
}
////////////////////////////////////////////////////////////////
LibertyCellPgPortIterator::LibertyCellPgPortIterator(const LibertyCell *cell) :
iter_(const_cast<LibertyCell*>(cell)->pg_port_map_)
{
}
bool
LibertyCellPgPortIterator::hasNext()
{
return iter_.hasNext();
}
LibertyPgPort *
LibertyCellPgPortIterator::next()
{
string name;
LibertyPgPort *port;
iter_.next(name, port);
return port;
}
} // namespace

View File

@ -317,6 +317,7 @@ bool has_members() { return self->hasMembers(); }
LibertyPortMemberIterator *
member_iterator() { return new LibertyPortMemberIterator(self); }
LibertyPort *bundle_port() { return self->bundlePort(); }
bool is_pwr_gnd() { return self->isPwrGnd(); }
string
function()

View File

@ -561,6 +561,8 @@ LibertyReader::defineVisitors()
&LibertyReader::endEcsmWaveform);
defineGroupVisitor("ecsm_waveform_set", &LibertyReader::beginEcsmWaveform,
&LibertyReader::endEcsmWaveform);
defineGroupVisitor("ecsm_capacitance", &LibertyReader::beginEcsmWaveform,
&LibertyReader::endEcsmWaveform);
}
void
@ -5686,8 +5688,7 @@ LibertyReader::beginPgPin(LibertyGroup *group)
{
if (cell_) {
const char *name = group->firstName();
pg_port_ = new LibertyPgPort(name, cell_);
cell_->addPgPort(pg_port_);
pg_port_ = builder_.makePort(cell_, name);
}
}
@ -5702,35 +5703,27 @@ LibertyReader::visitPgType(LibertyAttr *attr)
{
if (pg_port_) {
const char *type_name = getAttrString(attr);
LibertyPgPort::PgType type = LibertyPgPort::PgType::unknown;
if (stringEqual(type_name, "primary_ground"))
type = LibertyPgPort::PgType::primary_ground;
else if (stringEqual(type_name, "primary_power"))
type = LibertyPgPort::PgType::primary_power;
else if (stringEqual(type_name, "backup_ground"))
type = LibertyPgPort::PgType::backup_ground;
else if (stringEqual(type_name, "backup_power"))
type = LibertyPgPort::PgType::backup_power;
else if (stringEqual(type_name, "internal_ground"))
type = LibertyPgPort::PgType::internal_ground;
else if (stringEqual(type_name, "internal_power"))
type = LibertyPgPort::PgType::internal_power;
else if (stringEqual(type_name, "nwell"))
type = LibertyPgPort::PgType::nwell;
else if (stringEqual(type_name, "pwell"))
type = LibertyPgPort::PgType::pwell;
else if (stringEqual(type_name, "deepnwell"))
type = LibertyPgPort::PgType::deepnwell;
else if (stringEqual(type_name, "deeppwell"))
type = LibertyPgPort::PgType::deeppwell;
else
PwrGndType type = findPwrGndType(type_name);
PortDirection *dir = PortDirection::unknown();
switch (type) {
case PwrGndType::primary_ground:;
case PwrGndType::backup_ground:
case PwrGndType::internal_ground:
dir = PortDirection::ground();
break;
case PwrGndType::primary_power:
case PwrGndType::backup_power:
case PwrGndType::internal_power:
dir = PortDirection::power();
break;
case PwrGndType::none:
libError(1291, attr, "unknown pg_type.");
pg_port_->setPgType(type);
break;
default:
break;
}
pg_port_->setPwrGndType(type);
pg_port_->setDirection(dir);
}
}

View File

@ -653,7 +653,7 @@ protected:
const EarlyLateAll *derate_type_;
const EarlyLateAll *sigma_type_;
PathType path_type_;
LibertyPgPort *pg_port_;
LibertyPort *pg_port_;
ScaleFactorType scale_factor_type_;
TableAxisPtr axis_[3];
TablePtr table_;

View File

@ -59,6 +59,7 @@ protected:
void writeCells();
void writeCell(const LibertyCell *cell);
void writePort(const LibertyPort *port);
void writePwrGndPort(const LibertyPort *port);
void writeBusPort(const LibertyPort *port);
void writePortAttrs(const LibertyPort *port);
void writeTimingArcSet(const TimingArcSet *arc_set);
@ -310,7 +311,9 @@ LibertyWriter::writeCell(const LibertyCell *cell)
while (port_iter.hasNext()) {
const LibertyPort *port = port_iter.next();
if (!port->direction()->isInternal()) {
if (port->isBus())
if (port->isPwrGnd())
writePwrGndPort(port);
else if (port->isBus())
writeBusPort(port);
else if (port->isBundle())
report_->error(1340, "%s/%s bundled ports not supported.",
@ -394,6 +397,15 @@ LibertyWriter::writePortAttrs(const LibertyPort *port)
}
}
void
LibertyWriter::writePwrGndPort(const LibertyPort *port)
{
fprintf(stream_, " pg_pin(\"%s\") {\n", port->name());
fprintf(stream_, " pg_type : \"%s\";\n", pwrGndTypeName(port->pwrGndType()));
fprintf(stream_, " voltage_name : \"%s\";\n", port->voltageName());
fprintf(stream_, " }\n");
}
// Check if arc is added for port min_pulse_width_high/low attribute.
bool
LibertyWriter::isAutoWidthArc(const LibertyPort *port,

View File

@ -753,6 +753,15 @@ bool is_top_level_port() { return Sta::sta()->ensureLinked()->isTopLevelPort(sel
PinConnectedPinIterator *connected_pin_iterator()
{ return Sta::sta()->ensureLinked()->connectedPinIterator(self); }
bool
is_pwr_gnd()
{
sta::Sta *sta = Sta::sta();
Network *network = sta->network();
LibertyPort *lib_port = network->libertyPort(self);
return lib_port && lib_port->isPwrGnd();
}
Vertex **
vertices()
{

View File

@ -100,7 +100,8 @@ Power::Power(StaState *sta) :
input_activity_(), // default set in ensureActivities()
seq_activity_map_(100, SeqPinHash(network_), SeqPinEqual()),
activities_valid_(false),
bdd_(sta)
bdd_(sta),
corner_(nullptr)
{
}
@ -113,6 +114,8 @@ Power::clear()
seq_activity_map_.clear();
activity_map_.clear();
activities_valid_ = false;
instance_powers_.clear();
corner_ = nullptr;
}
void
@ -286,13 +289,10 @@ Power::power(const Corner *corner,
pad.clear();
ensureActivities();
Stats stats(debug_, report_);
LeafInstanceIterator *inst_iter = network_->leafInstanceIterator();
while (inst_iter->hasNext()) {
Instance *inst = inst_iter->next();
ensureInstPowers(corner);
for (auto [inst, inst_power] : instance_powers_) {
LibertyCell *cell = network_->libertyCell(inst);
if (cell) {
PowerResult inst_power = power(inst, cell, corner);
if (cell->isMacro()
|| cell->isMemory()
|| cell->interfaceTiming())
@ -308,8 +308,6 @@ Power::power(const Corner *corner,
total.incr(inst_power);
}
}
delete inst_iter;
stats.report("Find power");
}
bool
@ -332,17 +330,15 @@ PowerResult
Power::power(const Instance *inst,
const Corner *corner)
{
ensureActivities();
ensureInstPowers(corner);
if (network_->isHierarchical(inst)) {
PowerResult result;
powerInside(inst, corner, result);
return result;
}
LibertyCell *cell = network_->libertyCell(inst);
if (cell) {
ensureActivities();
return power(inst, cell, corner);
}
return PowerResult();
else
return instance_powers_[inst];
}
void
@ -355,13 +351,8 @@ Power::powerInside(const Instance *hinst,
Instance *child = child_iter->next();
if (network_->isHierarchical(child))
powerInside(child, corner, result);
else {
LibertyCell *cell = network_->libertyCell(child);
if (cell) {
PowerResult inst_power = power(child, cell, corner);
result.incr(inst_power);
}
}
else
result.incr(instance_powers_[child]);
}
delete child_iter;
}
@ -707,6 +698,7 @@ Power::evalBddActivity(DdNode *bdd,
void
Power::ensureActivities()
{
Stats stats(debug_, report_);
// No need to propagate activites if global activity is set.
if (!global_activity_.isSet()) {
if (!activities_valid_) {
@ -750,6 +742,7 @@ Power::ensureActivities()
activities_valid_ = true;
}
}
stats.report("Power activities");
}
void
@ -841,6 +834,32 @@ Power::seedRegOutputActivities(const Instance *reg,
////////////////////////////////////////////////////////////////
void
Power::ensureInstPowers(const Corner *corner)
{
if (instance_powers_.empty()
|| corner != corner_)
findInstPowers(corner);
}
void
Power::findInstPowers(const Corner *corner)
{
Stats stats(debug_, report_);
LeafInstanceIterator *inst_iter = network_->leafInstanceIterator();
while (inst_iter->hasNext()) {
Instance *inst = inst_iter->next();
LibertyCell *cell = network_->libertyCell(inst);
if (cell) {
PowerResult inst_power = power(inst, cell, corner);
instance_powers_[inst] = inst_power;
}
}
delete inst_iter;
corner_ = corner;
stats.report("Find power");
}
PowerResult
Power::power(const Instance *inst,
LibertyCell *cell,
@ -1368,7 +1387,7 @@ Power::pgNameVoltage(LibertyCell *cell,
const DcalcAnalysisPt *dcalc_ap)
{
if (pg_port_name) {
LibertyPgPort *pg_port = cell->findPgPort(pg_port_name);
LibertyPort *pg_port = cell->findLibertyPort(pg_port_name);
if (pg_port) {
const char *volt_name = pg_port->voltageName();
LibertyLibrary *library = cell->libertyLibrary();
@ -1484,14 +1503,17 @@ Power::findUnannotatedPins(const Instance *inst,
InstancePinIterator *pin_iter = network_->pinIterator(inst);
while (pin_iter->hasNext()) {
const Pin *pin = pin_iter->next();
LibertyPort *liberty_port = sdc_network_->libertyPort(pin);
if (!network_->direction(pin)->isInternal()
&& !network_->direction(pin)->isPowerGround()
&& !(liberty_port && liberty_port->isPwrGnd())
&& user_activity_map_.find(pin) == user_activity_map_.end())
unannotated_pins.push_back(pin);
}
delete pin_iter;
}
// leaf pins - internal pins + top instance pins
// leaf pins - internal pins - power/ground pins + top instance pins
size_t
Power::pinCount()
{
@ -1502,7 +1524,10 @@ Power::pinCount()
InstancePinIterator *pin_iter = network_->pinIterator(leaf);
while (pin_iter->hasNext()) {
const Pin *pin = pin_iter->next();
if (!network_->direction(pin)->isInternal())
LibertyPort *liberty_port = sdc_network_->libertyPort(pin);
if (!network_->direction(pin)->isInternal()
&& !network_->direction(pin)->isPowerGround()
&& !(liberty_port && liberty_port->isPwrGnd()))
count++;
}
delete pin_iter;
@ -1533,6 +1558,22 @@ Power::clockMinPeriod()
return 0.0;
}
void
Power::deleteInstanceBefore(const Instance *)
{
activities_valid_ = false;
instance_powers_.clear();
corner_ = nullptr;
}
void
Power::deletePinBefore(const Pin *)
{
activities_valid_ = false;
instance_powers_.clear();
corner_ = nullptr;
}
////////////////////////////////////////////////////////////////
PowerResult::PowerResult() :

View File

@ -107,6 +107,8 @@ public:
float clockMinPeriod();
InstanceSeq highestPowerInstances(size_t count,
const Corner *corner);
void deleteInstanceBefore(const Instance *inst);
void deletePinBefore(const Pin *pin);
protected:
PwrActivity &activity(const Pin *pin);
@ -129,6 +131,8 @@ protected:
PwrActivity &activity);
PwrActivity findActivity(const Pin *pin);
void ensureInstPowers(const Corner *corner);
void findInstPowers(const Corner *corner);
PowerResult power(const Instance *inst,
LibertyCell *cell,
const Corner *corner);
@ -229,6 +233,8 @@ private:
PwrSeqActivityMap seq_activity_map_;
bool activities_valid_;
Bdd bdd_;
std::map<const Instance*, PowerResult> instance_powers_;
const Corner *corner_;
static constexpr int max_activity_passes_ = 100;

View File

@ -33,6 +33,7 @@
#include "Report.hh"
#include "Network.hh"
#include "PortDirection.hh"
#include "Liberty.hh"
#include "Sdc.hh"
#include "Power.hh"
#include "power/SaifReaderPvt.hh"
@ -168,9 +169,11 @@ SaifReader::setNetDurations(const char *net_name,
if (parent) {
string unescaped_name = unescaped(net_name);
const Pin *pin = sdc_network_->findPin(parent, unescaped_name.c_str());
LibertyPort *liberty_port = pin ? sdc_network_->libertyPort(pin) : nullptr;
if (pin
&& !sdc_network_->isHierarchical(pin)
&& !sdc_network_->direction(pin)->isInternal()) {
&& !sdc_network_->direction(pin)->isInternal()
&& !(liberty_port && liberty_port->isPwrGnd())) {
double t1 = durations[static_cast<int>(SaifState::T1)];
float duty = t1 / duration_;
double tc = durations[static_cast<int>(SaifState::TC)];

View File

@ -30,6 +30,7 @@
#include "VcdParse.hh"
#include "Debug.hh"
#include "Network.hh"
#include "Liberty.hh"
#include "PortDirection.hh"
#include "VerilogNamespace.hh"
#include "ParseBus.hh"
@ -284,13 +285,16 @@ VcdCountReader::addVarPin(const string &pin_name,
size_t bit_idx)
{
const Pin *pin = sdc_network_->findPin(pin_name.c_str());
LibertyPort *liberty_port = pin ? sdc_network_->libertyPort(pin) : nullptr;
if (pin
&& !sdc_network_->isHierarchical(pin)
&& !sdc_network_->direction(pin)->isInternal()) {
&& !sdc_network_->direction(pin)->isInternal()
&& !sdc_network_->direction(pin)->isPowerGround()
&& !(liberty_port && liberty_port->isPwrGnd())) {
VcdCounts &vcd_counts = vcd_count_map_[id];
vcd_counts.resize(width);
vcd_counts[bit_idx].addPin(pin);
debugPrint(debug_, "read_vcd_activities", 2, "id %s pin %s",
debugPrint(debug_, "read_vcd", 2, "id %s pin %s",
id.c_str(),
pin_name.c_str());
}
@ -304,11 +308,11 @@ VcdCountReader::varAppendValue(const string &id,
const auto &itr = vcd_count_map_.find(id);
if (itr != vcd_count_map_.end()) {
VcdCounts &vcd_counts = itr->second;
if (debug_->check("read_vcd_activities", 3)) {
if (debug_->check("read_vcd", 3)) {
for (size_t bit_idx = 0; bit_idx < vcd_counts.size(); bit_idx++) {
VcdCount &vcd_count = vcd_counts[bit_idx];
for (const Pin *pin : vcd_count.pins()) {
debugPrint(debug_, "read_vcd_activities", 3, "%s time %" PRIu64 " value %c",
debugPrint(debug_, "read_vcd", 3, "%s time %" PRIu64 " value %c",
sdc_network_->pathName(pin),
time,
value);
@ -333,9 +337,9 @@ VcdCountReader::varAppendBusValue(const string &id,
for (size_t bit_idx = 0; bit_idx < vcd_counts.size(); bit_idx++) {
char bit_value = ((bus_value >> bit_idx) & 0x1) ? '1' : '0';
VcdCount &vcd_count = vcd_counts[bit_idx];
if (debug_->check("read_vcd_activities", 3)) {
if (debug_->check("read_vcd", 3)) {
for (const Pin *pin : vcd_count.pins()) {
debugPrint(debug_, "read_vcd_activities", 3, "%s time %" PRIu64 " value %c",
debugPrint(debug_, "read_vcd", 3, "%s time %" PRIu64 " value %c",
sdc_network_->pathName(pin),
time,
bit_value);
@ -420,9 +424,9 @@ ReadVcdActivities::setActivities()
VcdTime high_time = vcd_count.highTime(time_max);
float duty = static_cast<double>(high_time) / time_delta;
float density = transition_count / (time_delta * time_scale);
if (debug_->check("read_vcd_activities", 1)) {
if (debug_->check("read_vcd", 1)) {
for (const Pin *pin : vcd_count.pins()) {
debugPrint(debug_, "read_vcd_activities", 1,
debugPrint(debug_, "read_vcd", 1,
"%s transitions %.1f activity %.2f duty %.2f",
sdc_network_->pathName(pin),
transition_count,

View File

@ -3957,14 +3957,30 @@ Sdc::unrecordPathDelayInternalFrom(ExceptionPath *exception)
}
}
template<class OBJ>
const ExceptionPathSet *
findExceptions(const UnorderedMap<const OBJ*, ExceptionPathSet> &map,
const OBJ *obj)
{
const auto itr = map.find(obj);
if (itr != map.end())
return &itr->second;
else
return nullptr;
}
bool
Sdc::pathDelayFrom(const Pin *pin)
{
ExceptionPathSet *exceptions = first_from_pin_exceptions_.findKey(pin);
const ExceptionPathSet *exceptions =
findExceptions<Pin>(first_from_pin_exceptions_, pin);
if (exceptions) {
for (ExceptionPath *exception : *exceptions) {
if (exception->isPathDelay())
return true;
}
}
return false;
}
@ -4042,11 +4058,14 @@ Sdc::hasLibertyCheckTo(const Pin *pin)
bool
Sdc::pathDelayTo(const Pin *pin)
{
ExceptionPathSet *exceptions = first_to_pin_exceptions_.findKey(pin);
const ExceptionPathSet *exceptions =
findExceptions<Pin>(first_to_pin_exceptions_, pin);
if (exceptions) {
for (ExceptionPath *exception : *exceptions) {
if (exception->isPathDelay())
return true;
}
}
return false;
}
@ -4210,12 +4229,15 @@ void
Sdc::deleteLoopExceptions()
{
// erase prevents range iteration.
ExceptionPathSet::Iterator except_iter(exceptions_);
while (except_iter.hasNext()) {
ExceptionPath *except = except_iter.next();
if (except->isLoop())
for (auto itr = exceptions_.begin(); itr != exceptions_.end(); ) {
ExceptionPath *except = *itr;
if (except->isLoop()) {
itr = exceptions_.erase(itr);
deleteException(except);
}
else
itr++;
}
}
////////////////////////////////////////////////////////////////
@ -4420,8 +4442,8 @@ Sdc::findMatchingExceptionsFirstThru(ExceptionPath *exception,
for (const Net *net : *thru->nets()) {
// Potential matches includes exceptions that match net that are not
// the first exception point.
ExceptionPathSet *potential_matches =
first_thru_net_exceptions_.findKey(net);
const ExceptionPathSet *potential_matches =
findExceptions<Net>(first_thru_net_exceptions_, net);
if (potential_matches) {
for (ExceptionPath *match : *potential_matches) {
ExceptionThru *match_thru = (*match->thrus())[0];
@ -4457,8 +4479,11 @@ Sdc::findMatchingExceptionsClks(ExceptionPath *exception,
{
if (clks) {
ExceptionPathSet clks_matches;
for (Clock *clk : *clks)
clks_matches.insertSet(exception_map.findKey(clk));
for (Clock *clk : *clks) {
auto itr = exception_map.find(clk);
if (itr != exception_map.end())
clks_matches.insert(itr->second.begin(), itr->second.end());
}
findMatchingExceptions(exception, &clks_matches, matches);
}
}
@ -4471,8 +4496,11 @@ Sdc::findMatchingExceptionsPins(ExceptionPath *exception,
{
if (pins) {
ExceptionPathSet pins_matches;
for (const Pin *pin : *pins)
pins_matches.insertSet(exception_map.findKey(pin));
for (const Pin *pin : *pins) {
auto itr = exception_map.find(pin);
if (itr != exception_map.end())
pins_matches.insert(itr->second.begin(), itr->second.end());
}
findMatchingExceptions(exception, &pins_matches, matches);
}
}
@ -4484,10 +4512,13 @@ Sdc::findMatchingExceptionsInsts(ExceptionPath *exception,
ExceptionPathSet &matches)
{
if (insts) {
ExceptionPathSet insts_matches;
for (const Instance *inst : *insts)
insts_matches.insertSet(exception_map.findKey(inst));
findMatchingExceptions(exception, &insts_matches, matches);
ExceptionPathSet inst_matches;
for (const Instance *inst : *insts) {
auto itr = exception_map.find(inst);
if (itr != exception_map.end())
inst_matches.insert(itr->second.begin(), itr->second.end());
}
findMatchingExceptions(exception, &inst_matches, matches);
}
}
@ -4639,12 +4670,8 @@ Sdc::recordMergeHash(ExceptionPath *exception,
hash,
exception->asString(network_),
missing_pt->asString(network_));
ExceptionPathSet *set = exception_merge_hash_.findKey(hash);
if (set == nullptr) {
set = new ExceptionPathSet;
exception_merge_hash_[hash] = set;
}
set->insert(exception);
ExceptionPathSet &set = exception_merge_hash_[hash];
set.insert(exception);
}
// Record a mapping from first pin/clock/instance's to a set of exceptions.
@ -4716,12 +4743,8 @@ Sdc::recordExceptionClks(ExceptionPath *exception,
{
if (clks) {
for (Clock *clk : *clks) {
ExceptionPathSet *set = exception_map.findKey(clk);
if (set == nullptr) {
set = new ExceptionPathSet;
exception_map[clk] = set;
}
set->insert(exception);
ExceptionPathSet &set = exception_map[clk];
set.insert(exception);
}
}
}
@ -4733,12 +4756,8 @@ Sdc::recordExceptionEdges(ExceptionPath *exception,
{
if (edges) {
for (const EdgePins &edge : *edges) {
ExceptionPathSet *set = exception_map.findKey(edge);
if (set == nullptr) {
set = new ExceptionPathSet;
exception_map.insert(edge, set);
}
set->insert(exception);
ExceptionPathSet &set = exception_map[edge];
set.insert(exception);
}
}
}
@ -4750,12 +4769,8 @@ Sdc::recordExceptionPins(ExceptionPath *exception,
{
if (pins) {
for (const Pin *pin : *pins) {
ExceptionPathSet *set = exception_map.findKey(pin);
if (set == nullptr) {
set = new ExceptionPathSet;
exception_map.insert(pin, set);
}
set->insert(exception);
ExceptionPathSet &set = exception_map[pin];
set.insert(exception);
}
}
}
@ -4765,12 +4780,8 @@ Sdc::recordExceptionHpin(ExceptionPath *exception,
Pin *pin,
PinExceptionsMap &exception_map)
{
ExceptionPathSet *set = exception_map.findKey(pin);
if (set == nullptr) {
set = new ExceptionPathSet;
exception_map.insert(pin, set);
}
set->insert(exception);
ExceptionPathSet &set = exception_map[pin];
set.insert(exception);
}
void
@ -4780,12 +4791,8 @@ Sdc::recordExceptionInsts(ExceptionPath *exception,
{
if (insts) {
for (const Instance *inst : *insts) {
ExceptionPathSet *set = exception_map.findKey(inst);
if (set == nullptr) {
set = new ExceptionPathSet;
exception_map[inst] = set;
}
set->insert(exception);
ExceptionPathSet &set = exception_map[inst];
set.insert(exception);
}
}
}
@ -4797,12 +4804,8 @@ Sdc::recordExceptionNets(ExceptionPath *exception,
{
if (nets) {
for (const Net *net : *nets) {
ExceptionPathSet *set = exception_map.findKey(net);
if (set == nullptr) {
set = new ExceptionPathSet;
exception_map[net] = set;
}
set->insert(exception);
ExceptionPathSet &set = exception_map[net];
set.insert(exception);
}
}
}
@ -4836,9 +4839,10 @@ Sdc::findMergeMatch(ExceptionPath *exception)
while (missing_pt_iter.hasNext()) {
ExceptionPt *missing_pt = missing_pt_iter.next();
size_t hash = exception->hash(missing_pt);
ExceptionPathSet *matches = exception_merge_hash_.findKey(hash);
if (matches) {
for (ExceptionPath *match : *matches) {
auto itr = exception_merge_hash_.find(hash);
if (itr != exception_merge_hash_.end()) {
ExceptionPathSet &matches = itr->second;
for (ExceptionPath *match : matches) {
ExceptionPt *match_missing_pt;
if (match != exception
// Exceptions are not merged if their priorities are
@ -4876,59 +4880,52 @@ Sdc::findMergeMatch(ExceptionPath *exception)
void
Sdc::deleteExceptions()
{
exceptions_.deleteContentsClear();
exceptions_.clear();
exception_id_ = 0;
first_from_pin_exceptions_.deleteContentsClear();
first_from_clk_exceptions_.deleteContentsClear();
first_from_inst_exceptions_.deleteContentsClear();
first_to_pin_exceptions_.deleteContentsClear();
first_to_clk_exceptions_.deleteContentsClear();
first_to_inst_exceptions_.deleteContentsClear();
first_thru_pin_exceptions_.deleteContentsClear();
first_thru_inst_exceptions_.deleteContentsClear();
first_thru_net_exceptions_.deleteContentsClear();
first_thru_edge_exceptions_.deleteContentsClear();
first_from_pin_exceptions_.clear();
first_from_clk_exceptions_.clear();
first_from_inst_exceptions_.clear();
first_to_pin_exceptions_.clear();
first_to_clk_exceptions_.clear();
first_to_inst_exceptions_.clear();
first_thru_pin_exceptions_.clear();
first_thru_inst_exceptions_.clear();
first_thru_net_exceptions_.clear();
first_thru_edge_exceptions_.clear();
first_thru_edge_exceptions_.clear();
path_delay_internal_from_.clear();
path_delay_internal_from_break_.clear();
path_delay_internal_to_.clear();
path_delay_internal_to_break_.clear();
pin_exceptions_.deleteContentsClear();
pin_exceptions_.clear();
deleteExceptionPtHashMapSets(exception_merge_hash_);
exception_merge_hash_.clear();
exception_merge_hash_.clear();
have_thru_hpin_exceptions_ = false;
}
void
Sdc::deleteExceptionPtHashMapSets(ExceptionPathPtHash &map)
{
map.deleteContents();
}
////////////////////////////////////////////////////////////////
void
Sdc::deleteExceptionsReferencing(Clock *clk)
{
// erase prevents range iteration.
ExceptionPathSet::ConstIterator exception_iter(exceptions_);
while (exception_iter.hasNext()) {
ExceptionPath *exception = exception_iter.next();
for (auto itr = exceptions_.begin(); itr != exceptions_.end(); ) {
ExceptionPath *exception = *itr;
bool deleted = false;
ExceptionFrom *from = exception->from();
if (from) {
ClockSet *clks = from->clks();
if (clks && clks->hasKey(clk)) {
itr = exceptions_.erase(itr);
unrecordException(exception);
deleted = true;
from->deleteClock(clk);
if (from->hasObjects())
recordException(exception);
else {
else
deleteException(exception);
deleted = true;
}
}
}
@ -4937,6 +4934,8 @@ Sdc::deleteExceptionsReferencing(Clock *clk)
if (to) {
ClockSet *clks = to->clks();
if (clks && clks->hasKey(clk)) {
itr = exceptions_.erase(itr);
deleted = true;
unrecordException(exception);
to->deleteClock(clk);
if (to->hasObjects())
@ -4946,6 +4945,8 @@ Sdc::deleteExceptionsReferencing(Clock *clk)
}
}
}
if (!deleted)
itr++;
}
}
@ -4986,9 +4987,11 @@ Sdc::unrecordMergeHash(ExceptionPath *exception,
hash,
exception->asString(network_),
missing_pt->asString(network_));
ExceptionPathSet *matches = exception_merge_hash_.findKey(hash);
if (matches)
matches->erase(exception);
auto itr = exception_merge_hash_.find(hash);
if (itr != exception_merge_hash_.end()) {
ExceptionPathSet &matches = itr->second;
matches.erase(exception);
}
}
void
@ -5026,9 +5029,11 @@ Sdc::unrecordExceptionClks(ExceptionPath *exception,
{
if (clks) {
for (Clock *clk : *clks) {
ExceptionPathSet *set = exception_map.findKey(clk);
if (set)
set->erase(exception);
auto itr = exception_map.find(clk);
if (itr != exception_map.end()) {
ExceptionPathSet &set = itr->second;
set.erase(exception);
}
}
}
}
@ -5040,9 +5045,11 @@ Sdc::unrecordExceptionPins(ExceptionPath *exception,
{
if (pins) {
for (const Pin *pin : *pins) {
ExceptionPathSet *set = exception_map.findKey(pin);
if (set)
set->erase(exception);
auto itr = exception_map.find(pin);
if (itr != exception_map.end()) {
ExceptionPathSet &set = itr->second;
set.erase(exception);
}
}
}
}
@ -5054,9 +5061,11 @@ Sdc::unrecordExceptionInsts(ExceptionPath *exception,
{
if (insts) {
for (const Instance *inst : *insts) {
ExceptionPathSet *set = exception_map.findKey(inst);
if (set)
set->erase(exception);
auto itr = exception_map.find(inst);
if (itr != exception_map.end()) {
ExceptionPathSet &set = itr->second;
set.erase(exception);
}
}
}
}
@ -5068,9 +5077,11 @@ Sdc::unrecordExceptionEdges(ExceptionPath *exception,
{
if (edges) {
for (const EdgePins &edge : *edges) {
ExceptionPathSet *set = exception_map.findKey(edge);
if (set)
set->erase(exception);
auto itr = exception_map.find(edge);
if (itr != exception_map.end()) {
ExceptionPathSet &set = itr->second;
set.erase(exception);
}
}
}
}
@ -5082,9 +5093,11 @@ Sdc::unrecordExceptionNets(ExceptionPath *exception,
{
if (nets) {
for (const Net *net : *nets) {
ExceptionPathSet *set = exception_map.findKey(net);
if (set)
set->erase(exception);
auto itr = exception_map.find(net);
if (itr != exception_map.end()) {
ExceptionPathSet &set = itr->second;
set.erase(exception);
}
}
}
}
@ -5094,9 +5107,11 @@ Sdc::unrecordExceptionHpin(ExceptionPath *exception,
Pin *pin,
PinExceptionsMap &exception_map)
{
ExceptionPathSet *set = exception_map.findKey(pin);
if (set)
set->erase(exception);
auto itr = exception_map.find(pin);
if (itr != exception_map.end()) {
ExceptionPathSet &set = itr->second;
set.erase(exception);
}
}
////////////////////////////////////////////////////////////////
@ -5166,18 +5181,18 @@ Sdc::resetPath(ExceptionFrom *from,
const MinMaxAll *min_max)
{
checkFromThrusTo(from, thrus, to);
ExceptionPathSet::Iterator except_iter(exceptions_);
while (except_iter.hasNext()) {
ExceptionPath *match = except_iter.next();
// erase prevents range iteration.
for (auto itr = exceptions_.begin(); itr != exceptions_.end(); ) {
ExceptionPath *match = *itr;
if (match->resetMatch(from, thrus, to, min_max, network_)) {
debugPrint(debug_, "exception_match", 3, "reset match %s",
match->asString(network_));
ExceptionPathSet expansions;
expandException(match, expansions);
itr = exceptions_.erase(itr);
deleteException(match);
ExceptionPathSet::Iterator expand_iter(expansions);
while (expand_iter.hasNext()) {
ExceptionPath *expand = expand_iter.next();
for (ExceptionPath *expand : expansions) {
if (expand->resetMatch(from, thrus, to, min_max, network_)) {
unrecordPathDelayInternalFrom(expand);
unrecordPathDelayInternalTo(expand);
@ -5187,6 +5202,8 @@ Sdc::resetPath(ExceptionFrom *from,
addException(expand);
}
}
else
itr++;
}
}
@ -5214,33 +5231,38 @@ Sdc::exceptionFromStates(const Pin *pin,
{
bool srch_from = true;
if (pin) {
if (srch_from && !first_from_pin_exceptions_.empty())
srch_from &= exceptionFromStates(first_from_pin_exceptions_.findKey(pin),
pin, rf, min_max, include_filter,
states);
if (srch_from && !first_thru_pin_exceptions_.empty())
srch_from &= exceptionFromStates(first_thru_pin_exceptions_.findKey(pin),
pin, rf, min_max, include_filter,
states);
if (srch_from) {
const ExceptionPathSet *exceptions =
findExceptions<Pin>(first_from_pin_exceptions_, pin);
srch_from &= exceptionFromStates(exceptions, pin, rf, min_max,
include_filter, states);
}
if (srch_from) {
const ExceptionPathSet *exceptions =
findExceptions<Pin>(first_thru_pin_exceptions_, pin);
srch_from &= exceptionFromStates(exceptions, pin, rf, min_max,
include_filter, states);
}
if (srch_from
&& (!first_from_inst_exceptions_.empty()
|| !first_thru_inst_exceptions_.empty())) {
Instance *inst = network_->instance(pin);
if (srch_from && !first_from_inst_exceptions_.empty())
srch_from &= exceptionFromStates(first_from_inst_exceptions_.findKey(inst),
pin, rf, min_max, include_filter,
states);
if (srch_from && !first_thru_inst_exceptions_.empty())
srch_from &= exceptionFromStates(first_thru_inst_exceptions_.findKey(inst),
pin, rf, min_max, include_filter,
states);
const ExceptionPathSet *exceptions =
findExceptions<Instance>(first_from_inst_exceptions_, inst);
srch_from &= exceptionFromStates(exceptions, pin, rf, min_max,
include_filter, states);
const ExceptionPathSet *exceptions2 =
findExceptions<Instance>(first_thru_inst_exceptions_, inst);
srch_from &= exceptionFromStates(exceptions2, pin, rf, min_max,
include_filter, states);
}
}
if (srch_from && clk && !first_from_clk_exceptions_.empty())
srch_from &= exceptionFromStates(first_from_clk_exceptions_.findKey(clk),
pin, clk_rf, min_max, include_filter,
states);
if (srch_from && clk) {
const ExceptionPathSet *exceptions =
findExceptions<Clock>(first_from_clk_exceptions_, clk);
srch_from &= exceptionFromStates(exceptions, pin, clk_rf, min_max,
include_filter, states);
}
if (!srch_from) {
delete states;
states = nullptr;
@ -5299,20 +5321,22 @@ Sdc::exceptionFromClkStates(const Pin *pin,
ExceptionStateSet *&states) const
{
if (pin) {
if (!first_from_pin_exceptions_.empty())
exceptionFromStates(first_from_pin_exceptions_.findKey(pin),
nullptr, rf, min_max, true, states);
const ExceptionPathSet *exceptions =
findExceptions<Pin>(first_from_pin_exceptions_, pin);
exceptionFromStates(exceptions, nullptr, rf, min_max, true, states);
if (!first_from_inst_exceptions_.empty()) {
Instance *inst = network_->instance(pin);
exceptionFromStates(first_from_inst_exceptions_.findKey(inst),
pin, rf, min_max, true, states);
const ExceptionPathSet *exceptions =
findExceptions<Instance>(first_from_inst_exceptions_, inst);
exceptionFromStates(exceptions, pin, rf, min_max, true, states);
}
exceptionThruStates(first_thru_pin_exceptions_.findKey(pin),
rf, min_max, states);
const ExceptionPathSet *exceptions2 =
findExceptions<Pin>(first_thru_pin_exceptions_, pin);
exceptionThruStates(exceptions2, rf, min_max, states);
}
if (!first_from_clk_exceptions_.empty())
exceptionFromStates(first_from_clk_exceptions_.findKey(clk),
pin, clk_rf, min_max, true, states);
const ExceptionPathSet *exceptions =
findExceptions<Clock>(first_from_clk_exceptions_, clk);
exceptionFromStates(exceptions, pin, clk_rf, min_max, true, states);
}
void
@ -5322,10 +5346,10 @@ Sdc::filterRegQStates(const Pin *to_pin,
ExceptionStateSet *&states) const
{
if (!first_from_pin_exceptions_.empty()) {
const ExceptionPathSet *exceptions =
first_from_pin_exceptions_.findKey(to_pin);
if (exceptions) {
for (ExceptionPath *exception : *exceptions) {
auto itr = first_from_pin_exceptions_.find(to_pin);
if (itr != first_from_pin_exceptions_.end()) {
const ExceptionPathSet &exceptions = itr->second;
for (ExceptionPath *exception : exceptions) {
// Hack for filter -from reg/Q.
if (exception->isFilter()
&& exception->matchesFirstPt(to_rf, min_max)) {
@ -5346,19 +5370,25 @@ Sdc::exceptionThruStates(const Pin *from_pin,
const MinMax *min_max,
ExceptionStateSet *&states) const
{
exceptionThruStates(first_thru_pin_exceptions_.findKey(to_pin),
to_rf, min_max, states);
const ExceptionPathSet *exceptions =
findExceptions<Pin>(first_thru_pin_exceptions_, to_pin);
exceptionThruStates(exceptions, to_rf, min_max, states);
if (!first_thru_edge_exceptions_.empty()) {
EdgePins edge_pins(from_pin, to_pin);
exceptionThruStates(first_thru_edge_exceptions_.findKey(edge_pins),
to_rf, min_max, states);
auto itr = first_thru_edge_exceptions_.find(edge_pins);
if (itr != first_thru_edge_exceptions_.end()) {
const ExceptionPathSet *exceptions = &itr->second;
exceptionThruStates(exceptions, to_rf, min_max, states);
}
}
if (!first_thru_inst_exceptions_.empty()
&& (network_->direction(to_pin)->isAnyOutput()
|| network_->isLatchData(to_pin))) {
const Instance *to_inst = network_->instance(to_pin);
exceptionThruStates(first_thru_inst_exceptions_.findKey(to_inst),
to_rf, min_max, states);
const ExceptionPathSet *exceptions =
findExceptions<Instance>(first_thru_inst_exceptions_, to_inst);
exceptionThruStates(exceptions, to_rf, min_max, states);
}
}
@ -5396,18 +5426,26 @@ Sdc::exceptionTo(ExceptionPathType type,
{
if (!first_to_inst_exceptions_.empty()) {
Instance *inst = network_->instance(pin);
exceptionTo(first_to_inst_exceptions_.findKey(inst), type, pin, rf,
const ExceptionPathSet *exceptions =
findExceptions<Instance>(first_to_inst_exceptions_, inst);
exceptionTo(exceptions, type, pin, rf,
clk_edge, min_max, match_min_max_exactly,
hi_priority_exception, hi_priority);
}
if (!first_to_pin_exceptions_.empty())
exceptionTo(first_to_pin_exceptions_.findKey(pin), type, pin, rf,
if (!first_to_pin_exceptions_.empty()) {
const ExceptionPathSet *exceptions =
findExceptions<Pin>(first_to_pin_exceptions_, pin);
exceptionTo(exceptions, type, pin, rf,
clk_edge, min_max, match_min_max_exactly,
hi_priority_exception, hi_priority);
if (clk_edge && !first_to_clk_exceptions_.empty())
exceptionTo(first_to_clk_exceptions_.findKey(clk_edge->clock()),
type, pin, rf, clk_edge, min_max, match_min_max_exactly,
}
if (clk_edge && !first_to_clk_exceptions_.empty()) {
const ExceptionPathSet *exceptions =
findExceptions<Clock>(first_to_clk_exceptions_, clk_edge->clock());
exceptionTo(exceptions, type, pin, rf, clk_edge,
min_max, match_min_max_exactly,
hi_priority_exception, hi_priority);
}
}
void
@ -5515,15 +5553,20 @@ Sdc::groupPathsTo(const Pin *pin,
{
if (!first_to_inst_exceptions_.empty()) {
Instance *inst = network_->instance(pin);
groupPathsTo(first_to_inst_exceptions_.findKey(inst), pin, rf,
clk_edge, min_max, group_paths);
const ExceptionPathSet *exceptions =
findExceptions<Instance>(first_to_inst_exceptions_, inst);
groupPathsTo(exceptions, pin, rf, clk_edge, min_max, group_paths);
}
if (!first_to_pin_exceptions_.empty()) {
const ExceptionPathSet *exceptions =
findExceptions<Pin>(first_to_pin_exceptions_, pin);
groupPathsTo(exceptions, pin, rf, clk_edge, min_max, group_paths);
}
if (clk_edge && !first_to_clk_exceptions_.empty()) {
const ExceptionPathSet *exceptions =
findExceptions<Clock>(first_to_clk_exceptions_, clk_edge->clock());
groupPathsTo(exceptions, pin, rf, clk_edge, min_max, group_paths);
}
if (!first_to_pin_exceptions_.empty())
groupPathsTo(first_to_pin_exceptions_.findKey(pin), pin, rf,
clk_edge, min_max, group_paths);
if (clk_edge && !first_to_clk_exceptions_.empty())
groupPathsTo(first_to_clk_exceptions_.findKey(clk_edge->clock()),
pin, rf, clk_edge, min_max, group_paths);
}
void
@ -5627,7 +5670,7 @@ Sdc::disconnectPinBefore(const Pin *pin)
{
auto itr = pin_exceptions_.find(pin);
if (itr != pin_exceptions_.end()) {
for (ExceptionPath *exception : *itr->second) {
for (ExceptionPath *exception : itr->second) {
ExceptionFrom *from = exception->from();
if (from)
from->disconnectPinBefore(pin, network_);

View File

@ -1355,19 +1355,6 @@ set_voltage_net(const Net *net,
////////////////////////////////////////////////////////////////
PinSet
group_path_pins(const char *group_path_name)
{
Sta *sta = Sta::sta();
Sdc *sdc = sta->sdc();
if (sdc->isGroupPathName(group_path_name))
return sta->findGroupPathPins(group_path_name);
else
return PinSet(sta->network());
}
////////////////////////////////////////////////////////////////
char
pin_case_logic_value(const Pin *pin)
{

View File

@ -578,7 +578,12 @@ proc get_lib_pins { args } {
}
set libcells [get_libcells_error "objects" $keys(-of_objects)]
foreach libcell $libcells {
lappend ports {*}[$libcell find_liberty_ports_matching * 0 1]
foreach port [$libcell find_liberty_ports_matching * 0 1] {
# Filter pg ports.
if { ![$port is_pwr_gnd] } {
lappend ports $port
}
}
}
} else {
foreach pattern $patterns {
@ -610,11 +615,14 @@ proc get_lib_pins { args } {
set matches [$cell find_liberty_ports_matching $port_pattern \
$regexp $nocase]
foreach match $matches {
# Filter pg ports.
if { ![$match is_pwr_gnd] } {
lappend ports $match
set found_match 1
}
}
}
}
if { !$found_match } {
if { !$quiet } {
sta_warn 356 "port '$port_pattern' not found."
@ -814,16 +822,22 @@ proc get_pins { args } {
set pin_iter [$inst pin_iterator]
while { [$pin_iter has_next] } {
set pin [$pin_iter next]
# Filter pg ports.
if { ![$pin is_pwr_gnd] } {
lappend pins $pin
}
}
$pin_iter finish
}
foreach net $nets {
set pin_iter [$net pin_iterator]
while { [$pin_iter has_next] } {
set pin [$pin_iter next]
# Filter pg ports.
if { ![$pin is_pwr_gnd] } {
lappend pins $pin
}
}
$pin_iter finish
}
} else {
@ -852,7 +866,12 @@ proc get_pins { args } {
} else {
set matches [find_pins_matching $pattern $regexp $nocase]
}
set pins [concat $pins $matches]
foreach match $matches {
# Filter pg ports.
if { ![$match is_pwr_gnd] } {
lappend pins $match
}
}
if { $matches == {} && !$quiet } {
sta_warn 363 "pin '$pattern' not found."
}

View File

@ -1196,7 +1196,7 @@ void
WriteSdc::writeExceptions() const
{
ExceptionPathSeq exceptions;
for (ExceptionPath *exception : *sdc_->exceptions())
for (ExceptionPath *exception : sdc_->exceptions())
exceptions.push_back(exception);
sort(exceptions, ExceptionPathLess(network_));
for (ExceptionPath *exception : exceptions) {

View File

@ -514,6 +514,7 @@ SdfWriter::writeTimingChecks(const Instance *inst,
while (pin_iter->hasNext()) {
Pin *pin = pin_iter->next();
Vertex *vertex = graph_->pinLoadVertex(pin);
if (vertex) {
VertexOutEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
@ -552,6 +553,7 @@ SdfWriter::writeTimingChecks(const Instance *inst,
writePeriodCheck(pin, min_period);
}
}
}
delete pin_iter;
if (check_header)

View File

@ -273,10 +273,7 @@ CheckTiming::hasClkedDepature(Pin *pin)
bool
CheckTiming::hasMaxDelay(Pin *pin)
{
ExceptionPathSet *exceptions = sdc_->exceptions();
ExceptionPathSet::Iterator exception_iter(exceptions);
while (exception_iter.hasNext()) {
ExceptionPath *exception = exception_iter.next();
for (ExceptionPath *exception : sdc_->exceptions()) {
ExceptionTo *to = exception->to();
if (exception->isPathDelay()
&& exception->minMax() == MinMaxAll::max()

View File

@ -75,7 +75,6 @@
#include "ClkLatency.hh"
#include "FindRegister.hh"
#include "ReportPath.hh"
#include "VisitPathGroupVertices.hh"
#include "Genclks.hh"
#include "ClkNetwork.hh"
#include "power/Power.hh"
@ -2721,36 +2720,6 @@ Sta::endpointViolationCount(const MinMax *min_max)
return violations;
}
PinSet
Sta::findGroupPathPins(const char *group_path_name)
{
if (!(search_->havePathGroups()
&& search_->arrivalsValid())) {
PathEndSeq path_ends = findPathEnds(// from, thrus, to, unconstrained
nullptr, nullptr, nullptr, false,
// corner, min_max,
nullptr, MinMaxAll::max(),
// group_path_count, endpoint_path_count
1, 1,
// unique_pins, unique_edges
true, true,
-INF, INF, // slack_min, slack_max,
false, // sort_by_slack
nullptr, // group_names
// setup, hold, recovery, removal,
true, true, true, true,
// clk_gating_setup, clk_gating_hold
true, true);
}
PathGroup *path_group = search_->findPathGroup(group_path_name,
MinMax::max());
PinSet pins(network_);
VertexPinCollector visitor(pins);
visitPathGroupVertices(path_group, &visitor, this);
return pins;
}
////////////////////////////////////////////////////////////////
void
@ -4303,6 +4272,7 @@ Sta::replaceEquivCellBefore(const Instance *inst,
else {
// Force delay calculation on output pins.
Vertex *vertex = graph_->pinDrvrVertex(pin);
if (vertex)
graph_delay_calc_->delayInvalid(vertex);
}
}
@ -4618,6 +4588,7 @@ Sta::deleteLeafInstanceBefore(const Instance *inst)
{
sim_->deleteInstanceBefore(inst);
sdc_->deleteInstanceBefore(inst);
power_->deleteInstanceBefore(inst);
}
void
@ -4694,6 +4665,7 @@ Sta::deletePinBefore(const Pin *pin)
}
sim_->deletePinBefore(pin);
clk_network_->deletePinBefore(pin);
power_->deletePinBefore(pin);
}
void

View File

@ -1,313 +0,0 @@
// 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 "VisitPathGroupVertices.hh"
#include "Debug.hh"
#include "Graph.hh"
#include "Bfs.hh"
#include "Search.hh"
#include "Path.hh"
#include "PathEnd.hh"
#include "Tag.hh"
#include "VisitPathEnds.hh"
namespace sta {
typedef Set<Path*, PathLess> PathSet;
typedef Map<Vertex*, PathSet*> VertexPathSetMap;
static void
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
Vertex *vertex,
Tag *tag,
const StaState *sta);
// Visit each path end for a vertex and add the worst one in each
// path group to the group.
class VisitPathGroupEnds : public PathEndVisitor
{
public:
VisitPathGroupEnds(PathGroup *path_group,
VertexVisitor *vertex_visitor,
VertexPathSetMap *matching_path_map,
BfsBkwdIterator *bkwd_iter,
StaState *sta);
VisitPathGroupEnds(const VisitPathGroupEnds&) = default;
virtual PathEndVisitor *copy() const;
virtual void visit(PathEnd *path_end);
virtual void vertexBegin(Vertex *vertex);
virtual void vertexEnd(Vertex *vertex);
private:
PathGroup *path_group_;
VertexVisitor *vertex_visitor_;
BfsBkwdIterator *bkwd_iter_;
VertexPathSetMap *matching_path_map_;
bool vertex_matches_;
StaState *sta_;
};
class PathGroupPathVisitor : public PathVisitor
{
public:
PathGroupPathVisitor(VertexVisitor *visitor,
BfsBkwdIterator *bkwd_iter,
VertexPathSetMap *matching_path_map,
const StaState *sta);
virtual ~PathGroupPathVisitor();
virtual VertexVisitor *copy() const;
virtual void visit(Vertex *vertex);
protected:
// Return false to stop visiting.
virtual bool visitFromToPath(const Pin *from_pin,
Vertex *from_vertex,
const RiseFall *from_rf,
Tag *from_tag,
Path *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
ArcDelay arc_delay,
Vertex *to_vertex,
const RiseFall *to_rf,
Tag *to_tag,
Arrival &to_arrival,
const MinMax *min_max,
const PathAnalysisPt *path_ap);
void fromMatches(Vertex *from_vertex,
Tag *from_tag);
private:
VertexVisitor *visitor_;
BfsBkwdIterator *bkwd_iter_;
VertexPathSetMap *matching_path_map_;
bool vertex_matches_;
};
////////////////////////////////////////////////////////////////
// Visit the fanin vertices for the path group.
// Vertices in the clock network are NOT visited.
void
visitPathGroupVertices(PathGroup *path_group,
VertexVisitor *visitor,
StaState *sta)
{
Search *search = sta->search();
VertexPathSetMap matching_path_map;
// Do not visit clock network.
SearchPredNonReg2 srch_non_reg(sta);
BfsBkwdIterator bkwd_iter(BfsIndex::other, &srch_non_reg, sta);
// Visit the path ends and filter by path_group to seed the backward search.
VisitPathGroupEnds end_visitor(path_group, visitor, &matching_path_map,
&bkwd_iter, sta);
VisitPathEnds visit_path_ends(sta);
for(Vertex *vertex : *search->endpoints())
visit_path_ends.visitPathEnds(vertex, &end_visitor);
// Search backward from the path ends thru vertices that have arrival tags
// that match path_group end paths.
PathGroupPathVisitor path_visitor(visitor, &bkwd_iter, &matching_path_map,
sta);
bkwd_iter.visit(0, &path_visitor);
// Cleanup.
VertexPathSetMap::Iterator matching_iter(matching_path_map);
while (matching_iter.hasNext()) {
PathSet *paths = matching_iter.next();
PathSet::Iterator path_iter(paths);
while (path_iter.hasNext()) {
Path *path = path_iter.next();
delete path;
}
delete paths;
}
}
////////////////////////////////////////////////////////////////
VisitPathGroupEnds::VisitPathGroupEnds(PathGroup *path_group,
VertexVisitor *vertex_visitor,
VertexPathSetMap *matching_path_map,
BfsBkwdIterator *bkwd_iter,
StaState *sta) :
path_group_(path_group),
vertex_visitor_(vertex_visitor),
bkwd_iter_(bkwd_iter),
matching_path_map_(matching_path_map),
sta_(sta)
{
}
PathEndVisitor *
VisitPathGroupEnds::copy() const
{
return new VisitPathGroupEnds(*this);
}
void
VisitPathGroupEnds::vertexBegin(Vertex *)
{
vertex_matches_ = false;
}
void
VisitPathGroupEnds::visit(PathEnd *path_end)
{
PathGroupSeq groups = sta_->search()->pathGroups(path_end);
for (PathGroup *group : groups) {
if (group == path_group_) {
Path *path = path_end->path();
Vertex *vertex = path->vertex(sta_);
vertexPathSetMapInsertPath(matching_path_map_, vertex, path->tag(sta_), sta_);
vertex_matches_ = true;
}
}
}
static void
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
Vertex *vertex,
Tag *tag,
const StaState *sta)
{
PathSet *matching_paths = matching_path_map->findKey(vertex);
if (matching_paths == nullptr) {
PathLess path_less(sta);
matching_paths = new PathSet(path_less);
(*matching_path_map)[vertex] = matching_paths;
}
Path *vpath = new Path(vertex, tag, sta);
matching_paths->insert(vpath);
}
void
VisitPathGroupEnds::vertexEnd(Vertex *vertex)
{
if (vertex_matches_) {
vertex_visitor_->visit(vertex);
// Seed backward bfs fanin search.
bkwd_iter_->enqueueAdjacentVertices(vertex);
}
}
////////////////////////////////////////////////////////////////
PathGroupPathVisitor::PathGroupPathVisitor(VertexVisitor *visitor,
BfsBkwdIterator *bkwd_iter,
VertexPathSetMap *matching_path_map,
const StaState *sta) :
PathVisitor(sta),
visitor_(visitor),
bkwd_iter_(bkwd_iter),
matching_path_map_(matching_path_map)
{
}
PathGroupPathVisitor::~PathGroupPathVisitor()
{
}
VertexVisitor *
PathGroupPathVisitor::copy() const
{
return new PathGroupPathVisitor(visitor_, bkwd_iter_,
matching_path_map_, this);
}
void
PathGroupPathVisitor::visit(Vertex *vertex)
{
vertex_matches_ = false;
visitFanoutPaths(vertex);
if (vertex_matches_) {
debugPrint(debug_, "visit_path_group", 1, "visit %s",
vertex->to_string(this).c_str());
visitor_->visit(vertex);
bkwd_iter_->enqueueAdjacentVertices(vertex);
}
}
bool
PathGroupPathVisitor::visitFromToPath(const Pin *,
Vertex *from_vertex,
const RiseFall *,
Tag *from_tag,
Path *,
const Arrival &,
Edge *,
TimingArc *,
ArcDelay ,
Vertex *to_vertex,
const RiseFall *to_rf,
Tag *to_tag,
Arrival &,
const MinMax *,
const PathAnalysisPt *path_ap)
{
PathSet *matching_paths = matching_path_map_->findKey(to_vertex);
if (matching_paths) {
Path to_path(to_vertex, to_tag, this);
if (!to_path.isNull()) {
if (matching_paths->hasKey(&to_path)) {
debugPrint(debug_, "visit_path_group", 2, "match %s %s -> %s %s",
from_vertex->to_string(this).c_str(),
from_tag->to_string(this).c_str(),
to_vertex->to_string(this).c_str(),
to_tag->to_string(this).c_str());
fromMatches(from_vertex, from_tag);
}
}
else {
VertexPathIterator to_iter(to_vertex, to_rf, path_ap, this);
while (to_iter.hasNext()) {
Path *to_path = to_iter.next();
if (Tag::matchNoCrpr(to_path->tag(this), to_tag)
&& matching_paths->hasKey(to_path)) {
debugPrint(debug_, "visit_path_group", 2,
"match crpr %s %s -> %s %s",
from_vertex->to_string(this).c_str(),
from_tag->to_string(this).c_str(),
to_vertex->to_string(this).c_str(),
to_tag->to_string(this).c_str());
fromMatches(from_vertex, from_tag);
}
}
}
}
return true;
}
void
PathGroupPathVisitor::fromMatches(Vertex *from_vertex,
Tag *from_tag)
{
vertex_matches_ = true;
vertexPathSetMapInsertPath(matching_path_map_, from_vertex,
from_tag, this);
}
} // namespace

View File

@ -1,40 +0,0 @@
// 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.
#pragma once
namespace sta {
class PathGroup;
class VertexVisitor;
class StaState;
// Visit the fanin vertices for the path group.
// Vertices in the clock network are NOT visited.
void
visitPathGroupVertices(PathGroup *path_group,
VertexVisitor *visitor,
StaState *sta);
} // namespace

View File

@ -261,7 +261,7 @@ WriteSpice::recordSpicePortNames(const char *cell_name,
for (size_t i = 2; i < tokens.size(); i++) {
const char *port_name = tokens[i].c_str();
LibertyPort *port = cell->findLibertyPort(port_name);
LibertyPgPort *pg_port = cell->findPgPort(port_name);
LibertyPort *pg_port = cell->findLibertyPort(port_name);
if (port == nullptr
&& pg_port == nullptr
&& !stringEqual(port_name, power_name_)
@ -326,7 +326,7 @@ WriteSpice::writeSubcktInst(const Instance *inst)
for (string subckt_port_name : spice_port_names) {
const char *subckt_port_cname = subckt_port_name.c_str();
Pin *pin = network_->findPin(inst, subckt_port_cname);
LibertyPgPort *pg_port = cell->findPgPort(subckt_port_cname);
LibertyPort *pg_port = cell->findLibertyPort(subckt_port_cname);
const char *pin_name;
if (pin) {
pin_name = network_->pathName(pin);
@ -357,13 +357,13 @@ WriteSpice::writeSubcktInstVoltSrcs(const Instance *inst,
const char *subckt_port_name = subckt_port_sname.c_str();
LibertyPort *port = cell->findLibertyPort(subckt_port_name);
const Pin *pin = port ? network_->findPin(inst, port) : nullptr;
LibertyPgPort *pg_port = cell->findPgPort(subckt_port_name);
bool is_pg_port = port && port->isPwrGnd();
debugPrint(debug_, "write_spice", 2, " port %s%s",
subckt_port_name,
pg_port ? " pwr/gnd" : "");
if (pg_port)
is_pg_port ? " pwr/gnd" : "");
if (is_pg_port)
writeVoltageSource(inst_name, subckt_port_name,
pgPortVoltage(pg_port));
pgPortVoltage(port));
else if (stringEq(subckt_port_name, power_name_))
writeVoltageSource(inst_name, subckt_port_name, power_voltage_);
else if (stringEq(subckt_port_name, gnd_name_))
@ -420,7 +420,7 @@ WriteSpice::writeVoltageSource(LibertyCell *cell,
float voltage)
{
if (pg_port_name) {
LibertyPgPort *pg_port = cell->findPgPort(pg_port_name);
LibertyPort *pg_port = cell->findLibertyPort(pg_port_name);
if (pg_port)
voltage = pgPortVoltage(pg_port);
else
@ -433,9 +433,9 @@ WriteSpice::writeVoltageSource(LibertyCell *cell,
}
float
WriteSpice::pgPortVoltage(LibertyPgPort *pg_port)
WriteSpice::pgPortVoltage(LibertyPort *pg_port)
{
LibertyLibrary *liberty = pg_port->cell()->libertyLibrary();
LibertyLibrary *liberty = pg_port->libertyCell()->libertyLibrary();
float voltage = 0.0;
bool exists;
const char *voltage_name = pg_port->voltageName();
@ -448,14 +448,14 @@ WriteSpice::pgPortVoltage(LibertyPgPort *pg_port)
voltage = gnd_voltage_;
else
report_->error(1601 , "pg_pin %s/%s voltage %s not found,",
pg_port->cell()->name(),
pg_port->libertyCell()->name(),
pg_port->name(),
voltage_name);
}
}
else
report_->error(1602, "Liberty pg_port %s/%s missing voltage_name attribute,",
pg_port->cell()->name(),
pg_port->libertyCell()->name(),
pg_port->name());
return voltage;
}

View File

@ -73,7 +73,7 @@ protected:
void writeSubcktInstVoltSrcs(const Instance *inst,
LibertyPortLogicValues &port_values,
const PinSet &excluded_input_pins);
float pgPortVoltage(LibertyPgPort *pg_port);
float pgPortVoltage(LibertyPort *pg_port);
void writeVoltageSource(const char *inst_name,
const char *port_name,
float voltage);

View File

@ -1900,20 +1900,12 @@ VerilogReader::makeNamedInstPins(Cell *cell,
delete net_name_iter;
}
}
else {
LibertyPgPort *pg_port = nullptr;
LibertyCell *lib_cell = network_->libertyCell(cell);
if (lib_cell)
pg_port = lib_cell->findPgPort(port_name);
// Do not warn about connections to pg ports (which are ignored).
if (pg_port == nullptr) {
else
linkWarn(201, parent_module->filename(), mod_inst->line(),
"instance %s port %s not found.",
inst_vname.c_str(),
port_name);
}
}
}
}
void