Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
7b4cea532b
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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/??
|
||||
-------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
-------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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() :
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)];
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
381
sdc/Sdc.cc
381
sdc/Sdc.cc
|
|
@ -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_);
|
||||
|
|
|
|||
13
sdc/Sdc.i
13
sdc/Sdc.i
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
23
sdc/Sdc.tcl
23
sdc/Sdc.tcl
|
|
@ -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."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue