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,13 +1597,14 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge,
void
GraphDelayCalc::minPeriod(const Pin *pin,
const Corner *corner,
// Return values.
float &min_period,
bool &exists)
{
exists = false;
const MinMax *min_max = MinMax::max();
for (const DcalcAnalysisPt *dcalc_ap : corners_->dcalcAnalysisPts()) {
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
// Sdf annotation.
float min_period1 = 0.0;
bool exists1 = false;
@ -1614,11 +1615,21 @@ GraphDelayCalc::minPeriod(const Pin *pin,
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;
min_period = delayAsFloat(graph_->arcDelay(edge, arc, dcalc_ap->index()));
}
}
if (!exists) {
// Liberty port min_period attribute.
LibertyPort *port = network_->libertyPort(pin);
if (port) {
// Liberty library.
Instance *inst = network_->instance(pin);
OperatingConditions *op_cond = sdc_->operatingConditions(min_max);
const Pvt *pvt = inst ? sdc_->pvt(inst, min_max) : nullptr;

View File

@ -871,6 +871,30 @@ Graph::minPulseWidthArc(Vertex *vertex,
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

View File

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

View File

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

View File

@ -289,6 +289,8 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
return makeMinPulseWidthArcs(cell, from_port, to_port, related_out,
TimingRole::width(), attrs);
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_low:
case TimingType::nochange_low_high:

View File

@ -4235,6 +4235,7 @@ LibertyReader::endTiming(LibertyGroup *group)
TimingType timing_type = timing_->attrs()->timingType();
if (timing_->relatedPortNames() == nullptr
&& !(timing_type == TimingType::min_pulse_width
|| timing_type == TimingType::minimum_period
|| timing_type == TimingType::min_clock_tree_path
|| timing_type == TimingType::max_clock_tree_path))
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;
bool exists;
graph_delay_calc_->minPeriod(pin, min_period, exists);
graph_delay_calc_->minPeriod(pin, corner_, min_period, exists);
if (exists) {
ensureTimingCheckheaders(check_header, inst, inst_header);
writePeriodCheck(pin, min_period);

View File

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

View File

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

View File

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

View File

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