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/TagGroup.cc
search/VertexVisitor.cc search/VertexVisitor.cc
search/VisitPathEnds.cc search/VisitPathEnds.cc
search/VisitPathGroupVertices.cc
search/WorstSlack.cc search/WorstSlack.cc
spice/WritePathSpice.cc spice/WritePathSpice.cc

View File

@ -50,6 +50,9 @@ The following classes now return const objects.
Transition Transition
TimingRole TimingRole
Liberty PgPorts are now LibertyPorts with additional member functions for
liberty pg_pins.
Release 2.6.1 2025/03/?? 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] report_checks [-unique_edges_to_endpoint]
Instances now have pins for verilog netlist power/ground connections,
Release 2.6.1 2025/03/30 Release 2.6.1 2025/03/30
------------------------- -------------------------

View File

@ -43,7 +43,6 @@ class WriteTimingModel;
class LibertyCellIterator; class LibertyCellIterator;
class LibertyCellPortIterator; class LibertyCellPortIterator;
class LibertyCellPortBitIterator; class LibertyCellPortBitIterator;
class LibertyCellPgPortIterator;
class LibertyPortMemberIterator; class LibertyPortMemberIterator;
class ModeValueDef; class ModeValueDef;
class TestCell; class TestCell;
@ -56,7 +55,6 @@ class LibertyReader;
class OcvDerate; class OcvDerate;
class TimingArcAttrs; class TimingArcAttrs;
class InternalPowerAttrs; class InternalPowerAttrs;
class LibertyPgPort;
class StaState; class StaState;
class Corner; class Corner;
class Corners; class Corners;
@ -90,7 +88,6 @@ typedef Vector<LatchEnable*> LatchEnableSeq;
typedef Map<const char *, OcvDerate*, CharPtrLess> OcvDerateMap; typedef Map<const char *, OcvDerate*, CharPtrLess> OcvDerateMap;
typedef Vector<InternalPowerAttrs*> InternalPowerAttrsSeq; typedef Vector<InternalPowerAttrs*> InternalPowerAttrsSeq;
typedef Map<std::string, float> SupplyVoltageMap; typedef Map<std::string, float> SupplyVoltageMap;
typedef Map<std::string, LibertyPgPort*> LibertyPgPortMap;
typedef Map<std::string, DriverWaveform*> DriverWaveformMap; typedef Map<std::string, DriverWaveform*> DriverWaveformMap;
typedef Vector<DcalcAnalysisPt*> DcalcAnalysisPtSeq; 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, enum class ScanSignalType { enable, enable_inverted, clock, clock_a, clock_b,
input, input_inverted, output, output_inverted, none }; 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 }; enum class ScaleFactorPvt { process, volt, temp, unknown };
constexpr int scale_factor_pvt_count = int(ScaleFactorPvt::unknown) + 1; constexpr int scale_factor_pvt_count = int(ScaleFactorPvt::unknown) + 1;
@ -423,8 +426,6 @@ public:
LibertyPort *findLibertyPort(const char *name) const; LibertyPort *findLibertyPort(const char *name) const;
LibertyPortSeq findLibertyPortsMatching(PatternMatch *pattern) const; LibertyPortSeq findLibertyPortsMatching(PatternMatch *pattern) const;
bool hasInternalPorts() const { return has_internal_ports_; } 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_; } ScaleFactors *scaleFactors() const { return scale_factors_; }
void setScaleFactors(ScaleFactors *scale_factors); void setScaleFactors(ScaleFactors *scale_factors);
ModeDef *makeModeDef(const char *name); ModeDef *makeModeDef(const char *name);
@ -533,7 +534,6 @@ public:
void setOcvArcDepth(float depth); void setOcvArcDepth(float depth);
void setOcvDerate(OcvDerate *derate); void setOcvDerate(OcvDerate *derate);
void addOcvDerate(OcvDerate *derate); void addOcvDerate(OcvDerate *derate);
void addPgPort(LibertyPgPort *pg_port);
void setTestCell(TestCell *test); void setTestCell(TestCell *test);
void setHasInferedRegTimingArcs(bool infered); void setHasInferedRegTimingArcs(bool infered);
void setIsDisabledConstraint(bool is_disabled); void setIsDisabledConstraint(bool is_disabled);
@ -643,7 +643,6 @@ protected:
Vector<LibertyCell*> corner_cells_; Vector<LibertyCell*> corner_cells_;
float leakage_power_; float leakage_power_;
bool leakage_power_exists_; bool leakage_power_exists_;
LibertyPgPortMap pg_port_map_;
bool has_internal_ports_; bool has_internal_ports_;
std::atomic<bool> have_voltage_waveforms_; std::atomic<bool> have_voltage_waveforms_;
std::mutex waveform_lock_; std::mutex waveform_lock_;
@ -653,7 +652,6 @@ protected:
private: private:
friend class LibertyLibrary; friend class LibertyLibrary;
friend class LibertyCellPortIterator; friend class LibertyCellPortIterator;
friend class LibertyCellPgPortIterator;
friend class LibertyPort; friend class LibertyPort;
friend class LibertyBuilder; friend class LibertyBuilder;
}; };
@ -681,17 +679,6 @@ private:
ConcreteCellPortBitIterator *iter_; ConcreteCellPortBitIterator *iter_;
}; };
class LibertyCellPgPortIterator : public Iterator<LibertyPgPort*>
{
public:
LibertyCellPgPortIterator(const LibertyCell *cell);
bool hasNext();
LibertyPgPort *next();
private:
LibertyPgPortMap::Iterator iter_;
};
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
class LibertyPort : public ConcretePort class LibertyPort : public ConcretePort
@ -704,6 +691,16 @@ public:
LibertyPort *bundlePort() const; LibertyPort *bundlePort() const;
BusDcl *busDcl() const { return bus_dcl_; } BusDcl *busDcl() const { return bus_dcl_; }
void setDirection(PortDirection *dir); 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_; } ScanSignalType scanSignalType() const { return scan_signal_type_; }
void setScanSignalType(ScanSignalType type); void setScanSignalType(ScanSignalType type);
void fanoutLoad(// Return values. void fanoutLoad(// Return values.
@ -887,8 +884,10 @@ protected:
LibertyCell *liberty_cell_; LibertyCell *liberty_cell_;
BusDcl *bus_dcl_; BusDcl *bus_dcl_;
FuncExpr *function_; PwrGndType pwr_gnd_type_;
std::string voltage_name_;
ScanSignalType scan_signal_type_; ScanSignalType scan_signal_type_;
FuncExpr *function_;
FuncExpr *tristate_enable_; FuncExpr *tristate_enable_;
ScaledPortMap *scaled_ports_; ScaledPortMap *scaled_ports_;
RiseFallMinMax capacitance_; RiseFallMinMax capacitance_;
@ -1136,37 +1135,13 @@ private:
TablePtr derate_[RiseFall::index_count][EarlyLate::index_count][path_type_count]; 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 std::string
portLibertyToSta(const char *port_name); portLibertyToSta(const char *port_name);
const char * const char *
scanSignalTypeName(ScanSignalType scan_type); scanSignalTypeName(ScanSignalType scan_type);
const char *
pwrGndTypeName(PwrGndType pwr_gnd_type);
PwrGndType
findPwrGndType(const char *pg_name);
} // namespace } // namespace

View File

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

View File

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

View File

@ -907,9 +907,6 @@ public:
PinSet endpointPins(); PinSet endpointPins();
VertexSet *endpoints(); VertexSet *endpoints();
int endpointViolationCount(const MinMax *min_max); 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(). // Find all required times after updateTiming().
void findRequireds(); void findRequireds();
std::string reportDelayCalc(Edge *edge, std::string reportDelayCalc(Edge *edge,

View File

@ -67,17 +67,9 @@ static unsigned
hashFuncExpr(const FuncExpr *expr); hashFuncExpr(const FuncExpr *expr);
static unsigned static unsigned
hashPort(const LibertyPort *port); hashPort(const LibertyPort *port);
static unsigned
hashCellPgPorts(const LibertyCell *cell);
static unsigned
hashPgPort(const LibertyPgPort *port);
static bool static bool
cellHasFuncs(const LibertyCell *cell); cellHasFuncs(const LibertyCell *cell);
static bool
equivCellPgPorts(const LibertyCell *cell1,
const LibertyCell *cell2);
static float static float
cellDriveResistance(const LibertyCell *cell) cellDriveResistance(const LibertyCell *cell)
{ {
@ -201,7 +193,6 @@ static unsigned
hashCell(const LibertyCell *cell) hashCell(const LibertyCell *cell)
{ {
return hashCellPorts(cell) return hashCellPorts(cell)
+ hashCellPgPorts(cell)
+ hashCellSequentials(cell); + hashCellSequentials(cell);
} }
@ -226,25 +217,6 @@ hashPort(const LibertyPort *port)
+ port->direction()->index() * 5; + 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 static unsigned
hashCellSequentials(const LibertyCell *cell) hashCellSequentials(const LibertyCell *cell)
{ {
@ -333,7 +305,6 @@ equivCells(const LibertyCell *cell1,
{ {
return equivCellPorts(cell1, cell2) return equivCellPorts(cell1, cell2)
&& equivCellFuncs(cell1, cell2) && equivCellFuncs(cell1, cell2)
&& equivCellPgPorts(cell1, cell2)
&& equivCellSequentials(cell1, cell2) && equivCellSequentials(cell1, cell2)
&& equivCellStatetables(cell1, cell2) && equivCellStatetables(cell1, cell2)
// Reqwuire timing arc equivalence if there are no functions. // Reqwuire timing arc equivalence if there are no functions.
@ -347,7 +318,6 @@ equivCellsArcs(const LibertyCell *cell1,
{ {
return equivCellPorts(cell1, cell2) return equivCellPorts(cell1, cell2)
&& equivCellFuncs(cell1, cell2) && equivCellFuncs(cell1, cell2)
&& equivCellPgPorts(cell1, cell2)
&& equivCellSequentials(cell1, cell2) && equivCellSequentials(cell1, cell2)
&& equivCellStatetables(cell1, cell2) && equivCellStatetables(cell1, cell2)
// Reqwuire timing arc equivalence if there are no functions. // 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 bool
equivCellSequentials(const LibertyCell *cell1, equivCellSequentials(const LibertyCell *cell1,
const LibertyCell *cell2) const LibertyCell *cell2)

View File

@ -975,8 +975,6 @@ LibertyCell::~LibertyCell()
delete test_cell_; delete test_cell_;
ocv_derate_map_.deleteContents(); ocv_derate_map_.deleteContents();
pg_port_map_.deleteContents();
} }
LibertyPort * LibertyPort *
@ -1021,18 +1019,6 @@ LibertyCell::setHasInternalPorts(bool has_internal)
has_internal_ports_ = 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 * ModeDef *
LibertyCell::makeModeDef(const char *name) 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), ConcretePort(name, is_bus, from_index, to_index, is_bundle, members, cell),
liberty_cell_(cell), liberty_cell_(cell),
bus_dcl_(bus_dcl), bus_dcl_(bus_dcl),
function_(nullptr), pwr_gnd_type_(PwrGndType::none),
scan_signal_type_(ScanSignalType::none), scan_signal_type_(ScanSignalType::none),
function_(nullptr),
tristate_enable_(nullptr), tristate_enable_(nullptr),
scaled_ports_(nullptr), scaled_ports_(nullptr),
fanout_load_(0.0), fanout_load_(0.0),
@ -2168,6 +2155,50 @@ static EnumNameMap<ScanSignalType> scan_signal_type_map =
{ScanSignalType::output_inverted, "output_inverted"}, {ScanSignalType::output_inverted, "output_inverted"},
{ScanSignalType::none, "none"}}; {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 * const char *
scanSignalTypeName(ScanSignalType scan_type) scanSignalTypeName(ScanSignalType scan_type)
@ -2526,7 +2557,8 @@ LibertyPort::equiv(const LibertyPort *port1,
return (port1 == nullptr && port2 == nullptr) return (port1 == nullptr && port2 == nullptr)
|| (port1 != nullptr && port2 != nullptr || (port1 != nullptr && port2 != nullptr
&& stringEq(port1->name(), port2->name()) && stringEq(port1->name(), port2->name())
&& port1->direction() == port2->direction()); && port1->direction() == port2->direction()
&& port1->pwr_gnd_type_ == port2->pwr_gnd_type_);
} }
bool bool
@ -3330,56 +3362,4 @@ OcvDerate::setDerateTable(const RiseFall *rf,
derate_[rf->index()][early_late->index()][int(path_type)] = derate; 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 } // namespace

View File

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

View File

@ -561,6 +561,8 @@ LibertyReader::defineVisitors()
&LibertyReader::endEcsmWaveform); &LibertyReader::endEcsmWaveform);
defineGroupVisitor("ecsm_waveform_set", &LibertyReader::beginEcsmWaveform, defineGroupVisitor("ecsm_waveform_set", &LibertyReader::beginEcsmWaveform,
&LibertyReader::endEcsmWaveform); &LibertyReader::endEcsmWaveform);
defineGroupVisitor("ecsm_capacitance", &LibertyReader::beginEcsmWaveform,
&LibertyReader::endEcsmWaveform);
} }
void void
@ -5686,8 +5688,7 @@ LibertyReader::beginPgPin(LibertyGroup *group)
{ {
if (cell_) { if (cell_) {
const char *name = group->firstName(); const char *name = group->firstName();
pg_port_ = new LibertyPgPort(name, cell_); pg_port_ = builder_.makePort(cell_, name);
cell_->addPgPort(pg_port_);
} }
} }
@ -5702,35 +5703,27 @@ LibertyReader::visitPgType(LibertyAttr *attr)
{ {
if (pg_port_) { if (pg_port_) {
const char *type_name = getAttrString(attr); const char *type_name = getAttrString(attr);
LibertyPgPort::PgType type = LibertyPgPort::PgType::unknown; PwrGndType type = findPwrGndType(type_name);
if (stringEqual(type_name, "primary_ground")) PortDirection *dir = PortDirection::unknown();
type = LibertyPgPort::PgType::primary_ground; switch (type) {
else if (stringEqual(type_name, "primary_power")) case PwrGndType::primary_ground:;
type = LibertyPgPort::PgType::primary_power; case PwrGndType::backup_ground:
case PwrGndType::internal_ground:
else if (stringEqual(type_name, "backup_ground")) dir = PortDirection::ground();
type = LibertyPgPort::PgType::backup_ground; break;
else if (stringEqual(type_name, "backup_power")) case PwrGndType::primary_power:
type = LibertyPgPort::PgType::backup_power; case PwrGndType::backup_power:
case PwrGndType::internal_power:
else if (stringEqual(type_name, "internal_ground")) dir = PortDirection::power();
type = LibertyPgPort::PgType::internal_ground; break;
else if (stringEqual(type_name, "internal_power")) case PwrGndType::none:
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
libError(1291, attr, "unknown pg_type."); 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 *derate_type_;
const EarlyLateAll *sigma_type_; const EarlyLateAll *sigma_type_;
PathType path_type_; PathType path_type_;
LibertyPgPort *pg_port_; LibertyPort *pg_port_;
ScaleFactorType scale_factor_type_; ScaleFactorType scale_factor_type_;
TableAxisPtr axis_[3]; TableAxisPtr axis_[3];
TablePtr table_; TablePtr table_;

View File

@ -59,6 +59,7 @@ protected:
void writeCells(); void writeCells();
void writeCell(const LibertyCell *cell); void writeCell(const LibertyCell *cell);
void writePort(const LibertyPort *port); void writePort(const LibertyPort *port);
void writePwrGndPort(const LibertyPort *port);
void writeBusPort(const LibertyPort *port); void writeBusPort(const LibertyPort *port);
void writePortAttrs(const LibertyPort *port); void writePortAttrs(const LibertyPort *port);
void writeTimingArcSet(const TimingArcSet *arc_set); void writeTimingArcSet(const TimingArcSet *arc_set);
@ -310,7 +311,9 @@ LibertyWriter::writeCell(const LibertyCell *cell)
while (port_iter.hasNext()) { while (port_iter.hasNext()) {
const LibertyPort *port = port_iter.next(); const LibertyPort *port = port_iter.next();
if (!port->direction()->isInternal()) { if (!port->direction()->isInternal()) {
if (port->isBus()) if (port->isPwrGnd())
writePwrGndPort(port);
else if (port->isBus())
writeBusPort(port); writeBusPort(port);
else if (port->isBundle()) else if (port->isBundle())
report_->error(1340, "%s/%s bundled ports not supported.", 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. // Check if arc is added for port min_pulse_width_high/low attribute.
bool bool
LibertyWriter::isAutoWidthArc(const LibertyPort *port, 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() PinConnectedPinIterator *connected_pin_iterator()
{ return Sta::sta()->ensureLinked()->connectedPinIterator(self); } { 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 ** Vertex **
vertices() vertices()
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -514,42 +514,44 @@ SdfWriter::writeTimingChecks(const Instance *inst,
while (pin_iter->hasNext()) { while (pin_iter->hasNext()) {
Pin *pin = pin_iter->next(); Pin *pin = pin_iter->next();
Vertex *vertex = graph_->pinLoadVertex(pin); Vertex *vertex = graph_->pinLoadVertex(pin);
VertexOutEdgeIterator edge_iter(vertex, graph_); if (vertex) {
while (edge_iter.hasNext()) { VertexOutEdgeIterator edge_iter(vertex, graph_);
Edge *edge = edge_iter.next(); while (edge_iter.hasNext()) {
const TimingRole *role = edge->role(); Edge *edge = edge_iter.next();
const char *sdf_check = nullptr; const TimingRole *role = edge->role();
if (role == TimingRole::setup()) const char *sdf_check = nullptr;
sdf_check = "SETUP"; if (role == TimingRole::setup())
else if (role == TimingRole::hold()) sdf_check = "SETUP";
sdf_check = "HOLD"; else if (role == TimingRole::hold())
else if (role == TimingRole::recovery()) sdf_check = "HOLD";
sdf_check = "RECOVERY"; else if (role == TimingRole::recovery())
else if (role == TimingRole::removal()) sdf_check = "RECOVERY";
sdf_check = "REMOVAL"; else if (role == TimingRole::removal())
if (sdf_check) { sdf_check = "REMOVAL";
ensureTimingCheckheaders(check_header, inst, inst_header); if (sdf_check) {
writeCheck(edge, sdf_check); ensureTimingCheckheaders(check_header, inst, inst_header);
writeCheck(edge, sdf_check);
}
} }
} for (auto hi_low : RiseFall::range()) {
for (auto hi_low : RiseFall::range()) { float min_width, max_width;
float min_width, max_width; Edge *edge;
Edge *edge; TimingArc *arc;
TimingArc *arc; graph_->minPulseWidthArc(vertex, hi_low, edge, arc);
graph_->minPulseWidthArc(vertex, hi_low, edge, arc); if (edge) {
if (edge) { min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_));
min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_)); max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_));
max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_)); ensureTimingCheckheaders(check_header, inst, inst_header);
ensureTimingCheckheaders(check_header, inst, inst_header); writeWidthCheck(pin, hi_low, min_width, max_width);
writeWidthCheck(pin, hi_low, min_width, max_width); }
}
float min_period;
bool exists;
graph_delay_calc_->minPeriod(pin, corner_, min_period, exists);
if (exists) {
ensureTimingCheckheaders(check_header, inst, inst_header);
writePeriodCheck(pin, min_period);
} }
}
float min_period;
bool exists;
graph_delay_calc_->minPeriod(pin, corner_, min_period, exists);
if (exists) {
ensureTimingCheckheaders(check_header, inst, inst_header);
writePeriodCheck(pin, min_period);
} }
} }
delete pin_iter; delete pin_iter;

View File

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

View File

@ -75,7 +75,6 @@
#include "ClkLatency.hh" #include "ClkLatency.hh"
#include "FindRegister.hh" #include "FindRegister.hh"
#include "ReportPath.hh" #include "ReportPath.hh"
#include "VisitPathGroupVertices.hh"
#include "Genclks.hh" #include "Genclks.hh"
#include "ClkNetwork.hh" #include "ClkNetwork.hh"
#include "power/Power.hh" #include "power/Power.hh"
@ -2721,36 +2720,6 @@ Sta::endpointViolationCount(const MinMax *min_max)
return violations; 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 void
@ -4303,7 +4272,8 @@ Sta::replaceEquivCellBefore(const Instance *inst,
else { else {
// Force delay calculation on output pins. // Force delay calculation on output pins.
Vertex *vertex = graph_->pinDrvrVertex(pin); Vertex *vertex = graph_->pinDrvrVertex(pin);
graph_delay_calc_->delayInvalid(vertex); if (vertex)
graph_delay_calc_->delayInvalid(vertex);
} }
} }
} }
@ -4618,6 +4588,7 @@ Sta::deleteLeafInstanceBefore(const Instance *inst)
{ {
sim_->deleteInstanceBefore(inst); sim_->deleteInstanceBefore(inst);
sdc_->deleteInstanceBefore(inst); sdc_->deleteInstanceBefore(inst);
power_->deleteInstanceBefore(inst);
} }
void void
@ -4694,6 +4665,7 @@ Sta::deletePinBefore(const Pin *pin)
} }
sim_->deletePinBefore(pin); sim_->deletePinBefore(pin);
clk_network_->deletePinBefore(pin); clk_network_->deletePinBefore(pin);
power_->deletePinBefore(pin);
} }
void 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++) { for (size_t i = 2; i < tokens.size(); i++) {
const char *port_name = tokens[i].c_str(); const char *port_name = tokens[i].c_str();
LibertyPort *port = cell->findLibertyPort(port_name); LibertyPort *port = cell->findLibertyPort(port_name);
LibertyPgPort *pg_port = cell->findPgPort(port_name); LibertyPort *pg_port = cell->findLibertyPort(port_name);
if (port == nullptr if (port == nullptr
&& pg_port == nullptr && pg_port == nullptr
&& !stringEqual(port_name, power_name_) && !stringEqual(port_name, power_name_)
@ -326,7 +326,7 @@ WriteSpice::writeSubcktInst(const Instance *inst)
for (string subckt_port_name : spice_port_names) { for (string subckt_port_name : spice_port_names) {
const char *subckt_port_cname = subckt_port_name.c_str(); const char *subckt_port_cname = subckt_port_name.c_str();
Pin *pin = network_->findPin(inst, subckt_port_cname); 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; const char *pin_name;
if (pin) { if (pin) {
pin_name = network_->pathName(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(); const char *subckt_port_name = subckt_port_sname.c_str();
LibertyPort *port = cell->findLibertyPort(subckt_port_name); LibertyPort *port = cell->findLibertyPort(subckt_port_name);
const Pin *pin = port ? network_->findPin(inst, port) : nullptr; 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", debugPrint(debug_, "write_spice", 2, " port %s%s",
subckt_port_name, subckt_port_name,
pg_port ? " pwr/gnd" : ""); is_pg_port ? " pwr/gnd" : "");
if (pg_port) if (is_pg_port)
writeVoltageSource(inst_name, subckt_port_name, writeVoltageSource(inst_name, subckt_port_name,
pgPortVoltage(pg_port)); pgPortVoltage(port));
else if (stringEq(subckt_port_name, power_name_)) else if (stringEq(subckt_port_name, power_name_))
writeVoltageSource(inst_name, subckt_port_name, power_voltage_); writeVoltageSource(inst_name, subckt_port_name, power_voltage_);
else if (stringEq(subckt_port_name, gnd_name_)) else if (stringEq(subckt_port_name, gnd_name_))
@ -420,7 +420,7 @@ WriteSpice::writeVoltageSource(LibertyCell *cell,
float voltage) float voltage)
{ {
if (pg_port_name) { if (pg_port_name) {
LibertyPgPort *pg_port = cell->findPgPort(pg_port_name); LibertyPort *pg_port = cell->findLibertyPort(pg_port_name);
if (pg_port) if (pg_port)
voltage = pgPortVoltage(pg_port); voltage = pgPortVoltage(pg_port);
else else
@ -433,9 +433,9 @@ WriteSpice::writeVoltageSource(LibertyCell *cell,
} }
float 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; float voltage = 0.0;
bool exists; bool exists;
const char *voltage_name = pg_port->voltageName(); const char *voltage_name = pg_port->voltageName();
@ -448,14 +448,14 @@ WriteSpice::pgPortVoltage(LibertyPgPort *pg_port)
voltage = gnd_voltage_; voltage = gnd_voltage_;
else else
report_->error(1601 , "pg_pin %s/%s voltage %s not found,", report_->error(1601 , "pg_pin %s/%s voltage %s not found,",
pg_port->cell()->name(), pg_port->libertyCell()->name(),
pg_port->name(), pg_port->name(),
voltage_name); voltage_name);
} }
} }
else else
report_->error(1602, "Liberty pg_port %s/%s missing voltage_name attribute,", report_->error(1602, "Liberty pg_port %s/%s missing voltage_name attribute,",
pg_port->cell()->name(), pg_port->libertyCell()->name(),
pg_port->name()); pg_port->name());
return voltage; return voltage;
} }

View File

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

View File

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