liberty min_period timing group support resolves #275

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2025-07-27 18:12:26 -07:00
parent 253cca73ff
commit 3620d7a259
11 changed files with 105 additions and 39 deletions

View File

@ -1597,28 +1597,39 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge,
void void
GraphDelayCalc::minPeriod(const Pin *pin, GraphDelayCalc::minPeriod(const Pin *pin,
const Corner *corner,
// Return values. // Return values.
float &min_period, float &min_period,
bool &exists) bool &exists)
{ {
exists = false; exists = false;
const MinMax *min_max = MinMax::max(); const MinMax *min_max = MinMax::max();
for (const DcalcAnalysisPt *dcalc_ap : corners_->dcalcAnalysisPts()) { const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
// Sdf annotation. // Sdf annotation.
float min_period1 = 0.0; float min_period1 = 0.0;
bool exists1 = false; bool exists1 = false;
graph_->periodCheckAnnotation(pin, dcalc_ap->index(), graph_->periodCheckAnnotation(pin, dcalc_ap->index(),
min_period, exists); min_period, exists);
if (exists1 if (exists1
&& (!exists || min_period1 < min_period)) { && (!exists || min_period1 < min_period)) {
min_period = min_period1; min_period = min_period1;
exists = true;
}
if (!exists) {
// Liberty timing group timing_type minimum_period.
Vertex *vertex = graph_->pinLoadVertex(pin);
Edge *edge;
TimingArc *arc;
graph_->minPeriodArc(vertex, RiseFall::rise(), edge, arc);
if (edge) {
exists = true; exists = true;
min_period = delayAsFloat(graph_->arcDelay(edge, arc, dcalc_ap->index()));
} }
} }
if (!exists) { if (!exists) {
// Liberty port min_period attribute.
LibertyPort *port = network_->libertyPort(pin); LibertyPort *port = network_->libertyPort(pin);
if (port) { if (port) {
// Liberty library.
Instance *inst = network_->instance(pin); Instance *inst = network_->instance(pin);
OperatingConditions *op_cond = sdc_->operatingConditions(min_max); OperatingConditions *op_cond = sdc_->operatingConditions(min_max);
const Pvt *pvt = inst ? sdc_->pvt(inst, min_max) : nullptr; const Pvt *pvt = inst ? sdc_->pvt(inst, min_max) : nullptr;

View File

@ -871,6 +871,30 @@ Graph::minPulseWidthArc(Vertex *vertex,
arc = nullptr; arc = nullptr;
} }
void
Graph::minPeriodArc(Vertex *vertex,
const RiseFall *rf,
// Return values.
Edge *&edge,
TimingArc *&arc)
{
VertexOutEdgeIterator edge_iter(vertex, this);
while (edge_iter.hasNext()) {
edge = edge_iter.next();
TimingArcSet *arc_set = edge->timingArcSet();
if (arc_set->role() == TimingRole::period()) {
for (TimingArc *arc1 : arc_set->arcs()) {
if (arc1->fromEdge()->asRiseFall() == rf) {
arc = arc1;
return;
}
}
}
}
edge = nullptr;
arc = nullptr;
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
void void

View File

@ -171,6 +171,11 @@ public:
// Return values. // Return values.
Edge *&edge, Edge *&edge,
TimingArc *&arc); TimingArc *&arc);
void minPeriodArc(Vertex *vertex,
const RiseFall *rf,
// Return values.
Edge *&edge,
TimingArc *&arc);
// Sdf period check annotation. // Sdf period check annotation.
void periodCheckAnnotation(const Pin *pin, void periodCheckAnnotation(const Pin *pin,
DcalcAPIndex ap_index, DcalcAPIndex ap_index,

View File

@ -114,8 +114,10 @@ public:
ArcDelayCalc *arc_delay_calc); ArcDelayCalc *arc_delay_calc);
// Precedence: // Precedence:
// SDF annotation // SDF annotation
// Liberty library // Liberty port timing group timing_type minimum_period.
// Liberty port min_period attribute.
void minPeriod(const Pin *pin, void minPeriod(const Pin *pin,
const Corner *corner,
// Return values. // Return values.
float &min_period, float &min_period,
bool &exists); bool &exists);

View File

@ -289,6 +289,8 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
return makeMinPulseWidthArcs(cell, from_port, to_port, related_out, return makeMinPulseWidthArcs(cell, from_port, to_port, related_out,
TimingRole::width(), attrs); TimingRole::width(), attrs);
case TimingType::minimum_period: case TimingType::minimum_period:
return makeMinPulseWidthArcs(cell, from_port, to_port, related_out,
TimingRole::period(), attrs);
case TimingType::nochange_high_high: case TimingType::nochange_high_high:
case TimingType::nochange_high_low: case TimingType::nochange_high_low:
case TimingType::nochange_low_high: case TimingType::nochange_low_high:

View File

@ -4235,6 +4235,7 @@ LibertyReader::endTiming(LibertyGroup *group)
TimingType timing_type = timing_->attrs()->timingType(); TimingType timing_type = timing_->attrs()->timingType();
if (timing_->relatedPortNames() == nullptr if (timing_->relatedPortNames() == nullptr
&& !(timing_type == TimingType::min_pulse_width && !(timing_type == TimingType::min_pulse_width
|| timing_type == TimingType::minimum_period
|| timing_type == TimingType::min_clock_tree_path || timing_type == TimingType::min_clock_tree_path
|| timing_type == TimingType::max_clock_tree_path)) || timing_type == TimingType::max_clock_tree_path))
libWarn(1243, group, "timing group missing related_pin/related_bus_pin."); libWarn(1243, group, "timing group missing related_pin/related_bus_pin.");

View File

@ -546,7 +546,7 @@ SdfWriter::writeTimingChecks(const Instance *inst,
} }
float min_period; float min_period;
bool exists; bool exists;
graph_delay_calc_->minPeriod(pin, min_period, exists); graph_delay_calc_->minPeriod(pin, corner_, min_period, exists);
if (exists) { if (exists) {
ensureTimingCheckheaders(check_header, inst, inst_header); ensureTimingCheckheaders(check_header, inst, inst_header);
writePeriodCheck(pin, min_period); writePeriodCheck(pin, min_period);

View File

@ -39,12 +39,21 @@ namespace sta {
class MinPeriodCheckVisitor class MinPeriodCheckVisitor
{ {
public: public:
MinPeriodCheckVisitor() {} MinPeriodCheckVisitor(const Corner *corner);
virtual ~MinPeriodCheckVisitor() {} virtual ~MinPeriodCheckVisitor() {}
virtual void visit(MinPeriodCheck &check, virtual void visit(MinPeriodCheck &check,
StaState *sta) = 0; StaState *sta) = 0;
const Corner *corner() { return corner_; }
protected:
const Corner *corner_;
}; };
MinPeriodCheckVisitor::MinPeriodCheckVisitor(const Corner *corner) :
corner_(corner)
{
}
CheckMinPeriods::CheckMinPeriods(StaState *sta) : CheckMinPeriods::CheckMinPeriods(StaState *sta) :
sta_(sta) sta_(sta)
{ {
@ -64,7 +73,8 @@ CheckMinPeriods::clear()
class MinPeriodViolatorsVisitor : public MinPeriodCheckVisitor class MinPeriodViolatorsVisitor : public MinPeriodCheckVisitor
{ {
public: public:
MinPeriodViolatorsVisitor(MinPeriodCheckSeq &checks); MinPeriodViolatorsVisitor(const Corner *corner,
MinPeriodCheckSeq &checks);
virtual void visit(MinPeriodCheck &check, virtual void visit(MinPeriodCheck &check,
StaState *sta); StaState *sta);
@ -72,7 +82,9 @@ private:
MinPeriodCheckSeq &checks_; MinPeriodCheckSeq &checks_;
}; };
MinPeriodViolatorsVisitor::MinPeriodViolatorsVisitor(MinPeriodCheckSeq &checks): MinPeriodViolatorsVisitor::MinPeriodViolatorsVisitor(const Corner *corner,
MinPeriodCheckSeq &checks):
MinPeriodCheckVisitor(corner),
checks_(checks) checks_(checks)
{ {
} }
@ -86,10 +98,10 @@ MinPeriodViolatorsVisitor::visit(MinPeriodCheck &check,
} }
MinPeriodCheckSeq & MinPeriodCheckSeq &
CheckMinPeriods::violations() CheckMinPeriods::violations(const Corner *corner)
{ {
clear(); clear();
MinPeriodViolatorsVisitor visitor(checks_); MinPeriodViolatorsVisitor visitor(corner, checks_);
visitMinPeriodChecks(&visitor); visitMinPeriodChecks(&visitor);
sort(checks_, MinPeriodSlackLess(sta_)); sort(checks_, MinPeriodSlackLess(sta_));
return checks_; return checks_;
@ -113,16 +125,17 @@ CheckMinPeriods::visitMinPeriodChecks(Vertex *vertex,
{ {
Search *search = sta_->search(); Search *search = sta_->search();
GraphDelayCalc *graph_dcalc = sta_->graphDelayCalc(); GraphDelayCalc *graph_dcalc = sta_->graphDelayCalc();
const Corner *corner = visitor->corner();
Pin *pin = vertex->pin(); Pin *pin = vertex->pin();
float min_period; float min_period;
bool exists; bool exists;
graph_dcalc->minPeriod(pin, min_period, exists); graph_dcalc->minPeriod(pin, corner, min_period, exists);
if (exists) { if (exists) {
const ClockSet clks = search->clocks(vertex); const ClockSet clks = search->clocks(vertex);
ClockSet::ConstIterator clk_iter(clks); ClockSet::ConstIterator clk_iter(clks);
while (clk_iter.hasNext()) { while (clk_iter.hasNext()) {
Clock *clk = clk_iter.next(); Clock *clk = clk_iter.next();
MinPeriodCheck check(pin, clk); MinPeriodCheck check(pin, clk, corner);
visitor->visit(check, sta_); visitor->visit(check, sta_);
} }
} }
@ -133,16 +146,17 @@ CheckMinPeriods::visitMinPeriodChecks(Vertex *vertex,
class MinPeriodSlackVisitor : public MinPeriodCheckVisitor class MinPeriodSlackVisitor : public MinPeriodCheckVisitor
{ {
public: public:
MinPeriodSlackVisitor(); MinPeriodSlackVisitor(const Corner *corner);
virtual void visit(MinPeriodCheck &check, void visit(MinPeriodCheck &check,
StaState *sta); StaState *sta) override;
MinPeriodCheck *minSlackCheck(); MinPeriodCheck *minSlackCheck();
private: private:
MinPeriodCheck *min_slack_check_; MinPeriodCheck *min_slack_check_;
}; };
MinPeriodSlackVisitor::MinPeriodSlackVisitor() : MinPeriodSlackVisitor::MinPeriodSlackVisitor(const Corner *corner) :
MinPeriodCheckVisitor(corner),
min_slack_check_(nullptr) min_slack_check_(nullptr)
{ {
} }
@ -167,10 +181,10 @@ MinPeriodSlackVisitor::minSlackCheck()
} }
MinPeriodCheck * MinPeriodCheck *
CheckMinPeriods::minSlackCheck() CheckMinPeriods::minSlackCheck(const Corner *corner)
{ {
clear(); clear();
MinPeriodSlackVisitor visitor; MinPeriodSlackVisitor visitor(corner);
visitMinPeriodChecks(&visitor); visitMinPeriodChecks(&visitor);
MinPeriodCheck *check = visitor.minSlackCheck(); MinPeriodCheck *check = visitor.minSlackCheck();
// Save check for cleanup. // Save check for cleanup.
@ -181,16 +195,18 @@ CheckMinPeriods::minSlackCheck()
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
MinPeriodCheck::MinPeriodCheck(Pin *pin, MinPeriodCheck::MinPeriodCheck(Pin *pin,
Clock *clk) : Clock *clk,
const Corner *corner) :
pin_(pin), pin_(pin),
clk_(clk) clk_(clk),
corner_(corner)
{ {
} }
MinPeriodCheck * MinPeriodCheck *
MinPeriodCheck::copy() MinPeriodCheck::copy()
{ {
return new MinPeriodCheck(pin_, clk_); return new MinPeriodCheck(pin_, clk_, corner_);
} }
float float
@ -205,7 +221,7 @@ MinPeriodCheck::minPeriod(const StaState *sta) const
GraphDelayCalc *graph_dcalc = sta->graphDelayCalc(); GraphDelayCalc *graph_dcalc = sta->graphDelayCalc();
float min_period; float min_period;
bool exists; bool exists;
graph_dcalc->minPeriod(pin_, min_period, exists); graph_dcalc->minPeriod(pin_, corner_, min_period, exists);
return min_period; return min_period;
} }

View File

@ -38,12 +38,12 @@ class MinPeriodCheckVisitor;
class CheckMinPeriods class CheckMinPeriods
{ {
public: public:
explicit CheckMinPeriods(StaState *sta); CheckMinPeriods(StaState *sta);
~CheckMinPeriods(); ~CheckMinPeriods();
void clear(); void clear();
MinPeriodCheckSeq &violations(); MinPeriodCheckSeq &violations(const Corner *corner);
// Min period check with the least slack. // Min period check with the least slack.
MinPeriodCheck *minSlackCheck(); MinPeriodCheck *minSlackCheck(const Corner *corner);
protected: protected:
void visitMinPeriodChecks(MinPeriodCheckVisitor *visitor); void visitMinPeriodChecks(MinPeriodCheckVisitor *visitor);
@ -57,7 +57,9 @@ protected:
class MinPeriodCheck class MinPeriodCheck
{ {
public: public:
MinPeriodCheck(Pin *pin, Clock *clk); MinPeriodCheck(Pin *pin,
Clock *clk,
const Corner *corner);
MinPeriodCheck *copy(); MinPeriodCheck *copy();
Pin *pin() const { return pin_; } Pin *pin() const { return pin_; }
Clock *clk() const { return clk_; } Clock *clk() const { return clk_; }
@ -68,17 +70,18 @@ public:
private: private:
Pin *pin_; Pin *pin_;
Clock *clk_; Clock *clk_;
const Corner *corner_;
}; };
class MinPeriodSlackLess class MinPeriodSlackLess
{ {
public: public:
explicit MinPeriodSlackLess(StaState *sta); MinPeriodSlackLess(StaState *sta);
bool operator()(const MinPeriodCheck *check1, bool operator()(const MinPeriodCheck *check1,
const MinPeriodCheck *check2) const; const MinPeriodCheck *check2) const;
private: private:
const StaState *sta_; const StaState *sta_;
}; };
} // namespace } // namespace

View File

@ -38,7 +38,7 @@ class MinPulseWidthCheckVisitor;
class CheckMinPulseWidths class CheckMinPulseWidths
{ {
public: public:
explicit CheckMinPulseWidths(StaState *sta); CheckMinPulseWidths(StaState *sta);
~CheckMinPulseWidths(); ~CheckMinPulseWidths();
void clear(); void clear();
// Min pulse width checks for pins. // Min pulse width checks for pins.
@ -96,7 +96,7 @@ protected:
class MinPulseWidthSlackLess class MinPulseWidthSlackLess
{ {
public: public:
explicit MinPulseWidthSlackLess(const StaState *sta); MinPulseWidthSlackLess(const StaState *sta);
bool operator()(const MinPulseWidthCheck *check1, bool operator()(const MinPulseWidthCheck *check1,
const MinPulseWidthCheck *check2) const; const MinPulseWidthCheck *check2) const;

View File

@ -5554,14 +5554,16 @@ MinPeriodCheckSeq &
Sta::minPeriodViolations() Sta::minPeriodViolations()
{ {
minPeriodPreamble(); minPeriodPreamble();
return check_min_periods_->violations(); const Corner *corner = cmdCorner();
return check_min_periods_->violations(corner);
} }
MinPeriodCheck * MinPeriodCheck *
Sta::minPeriodSlack() Sta::minPeriodSlack()
{ {
minPeriodPreamble(); minPeriodPreamble();
return check_min_periods_->minSlackCheck(); const Corner *corner = cmdCorner();
return check_min_periods_->minSlackCheck(corner);
} }
void void