diff --git a/include/sta/Clock.hh b/include/sta/Clock.hh index b5568e3d..841dfed8 100644 --- a/include/sta/Clock.hh +++ b/include/sta/Clock.hh @@ -52,6 +52,7 @@ public: int index() const { return index_; } bool isPropagated() const { return is_propagated_; } void setIsPropagated(bool propagated); + bool isIdeal() const { return !is_propagated_; } // Ideal clock slew. void slew(const RiseFall *rf, const MinMax *min_max, diff --git a/include/sta/PathEnd.hh b/include/sta/PathEnd.hh index 6bca1f97..b004b36c 100644 --- a/include/sta/PathEnd.hh +++ b/include/sta/PathEnd.hh @@ -101,6 +101,7 @@ public: // Required time with source clock offset. virtual Required requiredTimeOffset(const StaState *sta) const; virtual ArcDelay margin(const StaState *sta) const = 0; + virtual float macroClkTreeDelay(const StaState *) const { return 0.0; } virtual Slack slack(const StaState *sta) const = 0; virtual Slack slackNoCrpr(const StaState *sta) const = 0; virtual Arrival borrow(const StaState *sta) const; @@ -324,6 +325,7 @@ public: virtual void reportFull(ReportPath *report) const; virtual bool isCheck() const { return true; } virtual ArcDelay margin(const StaState *sta) const; + virtual float macroClkTreeDelay(const StaState *sta) const; virtual TimingRole *checkRole(const StaState *sta) const; virtual TimingArc *checkArc() const { return check_arc_; } virtual int exceptPathCmp(const PathEnd *path_end, @@ -339,6 +341,7 @@ protected: Crpr crpr, bool crpr_valid); Delay sourceClkDelay(const StaState *sta) const; + virtual Required requiredTimeNoCrpr(const StaState *sta) const; TimingArc *check_arc_; Edge *check_edge_; diff --git a/liberty/LibertyWriter.cc b/liberty/LibertyWriter.cc index 63889584..5360ef0f 100644 --- a/liberty/LibertyWriter.cc +++ b/liberty/LibertyWriter.cc @@ -185,6 +185,7 @@ LibertyWriter::writeHeader() if (exists) fprintf(stream_, " default_fanout_load : %.2f;\n", fanout_load); fprintf(stream_, "\n"); + fprintf(stream_, " nom_process : %.1f;\n", library_->nominalProcess()); fprintf(stream_, " nom_temperature : %.1f;\n", diff --git a/search/CheckSlewLimits.cc b/search/CheckSlewLimits.cc index 656b9a72..9ad90c05 100644 --- a/search/CheckSlewLimits.cc +++ b/search/CheckSlewLimits.cc @@ -87,6 +87,34 @@ CheckSlewLimits::CheckSlewLimits(const StaState *sta) : { } +void +CheckSlewLimits::checkSlewLimits(const Pin *pin, + bool violators, + const Corner *corner, + const MinMax *min_max, + PinSeq &slew_pins, + float &min_slack) +{ + const Corner *corner1; + const RiseFall *rf; + Slew slew; + float limit, slack; + checkSlew(pin, corner, min_max, true, corner1, rf, slew, limit, slack); + if (!fuzzyInf(slack)) { + if (violators) { + if (slack < 0.0) + slew_pins.push_back(pin); + } + else { + if (slew_pins.empty() + || slack < min_slack) { + slew_pins.push_back(pin); + min_slack = slack; + } + } + } +} + void CheckSlewLimits::checkSlew(const Pin *pin, const Corner *corner, @@ -94,86 +122,121 @@ CheckSlewLimits::checkSlew(const Pin *pin, bool check_clks, // Return values. const Corner *&corner1, - const RiseFall *&rf, - Slew &slew, - float &limit, - float &slack) const + const RiseFall *&rf1, + Slew &slew1, + float &limit1, + float &slack1) const { corner1 = nullptr; - rf = nullptr; - slew = 0.0; - limit = 0.0; - slack = MinMax::min()->initValue(); - if (corner) - checkSlews1(pin, corner, min_max, check_clks, - corner1, rf, slew, limit, slack); - else { - for (auto corner : *sta_->corners()) { - checkSlews1(pin, corner, min_max, check_clks, - corner1, rf, slew, limit, slack); - } - } -} + rf1 = nullptr; + slew1 = 0.0; + limit1 = 0.0; + slack1 = MinMax::min()->initValue(); -void -CheckSlewLimits::checkSlews1(const Pin *pin, - const Corner *corner, - const MinMax *min_max, - bool check_clks, - // Return values. - const Corner *&corner1, - const RiseFall *&rf1, - Slew &slew1, - float &limit1, - float &slack1) const -{ Vertex *vertex, *bidirect_drvr_vertex; sta_->graph()->pinVertices(pin, vertex, bidirect_drvr_vertex); if (vertex) - checkSlews1(vertex, corner, min_max, check_clks, - corner1, rf1, slew1, limit1, slack1); + checkSlew1(pin, vertex, corner, min_max, check_clks, + corner1, rf1, slew1, limit1, slack1); if (bidirect_drvr_vertex) - checkSlews1(bidirect_drvr_vertex, corner, min_max, check_clks, - corner1, rf1, slew1, limit1, slack1); + checkSlew1(pin, bidirect_drvr_vertex, corner, min_max, check_clks, + corner1, rf1, slew1, limit1, slack1); } - + void -CheckSlewLimits::checkSlews1(Vertex *vertex, - const Corner *corner, - const MinMax *min_max, - bool check_clks, - // Return values. - const Corner *&corner1, - const RiseFall *&rf1, - Slew &slew1, - float &limit1, - float &slack1) const +CheckSlewLimits::checkSlew1(const Pin *pin, + const Vertex *vertex, + const Corner *corner, + const MinMax *min_max, + bool check_clks, + // Return values. + const Corner *&corner1, + const RiseFall *&rf1, + Slew &slew1, + float &limit1, + float &slack1) const { - const Pin *pin = vertex->pin(); if (!vertex->isDisabledConstraint() && !vertex->isConstant() && !sta_->clkNetwork()->isIdealClock(pin)) { - for (auto rf : RiseFall::range()) { - float limit; - bool exists; - findLimit(pin, vertex, corner, rf, min_max, check_clks, - limit, exists); - if (exists) { - checkSlew(vertex, corner, rf, min_max, limit, - corner1, rf1, slew1, slack1, limit1); + ClockSet clks; + if (check_clks) + clks = clockDomains(vertex); + if (corner) + checkSlew2(pin, vertex, corner, min_max, clks, + corner1, rf1, slew1, limit1, slack1); + else { + for (auto corner : *sta_->corners()) { + checkSlew2(pin, vertex, corner, min_max, clks, + corner1, rf1, slew1, limit1, slack1); } } } } +void +CheckSlewLimits::checkSlew2(const Pin *pin, + const Vertex *vertex, + const Corner *corner, + const MinMax *min_max, + const ClockSet &clks, + // Return values. + const Corner *&corner1, + const RiseFall *&rf1, + Slew &slew1, + float &limit1, + float &slack1) const +{ + for (const RiseFall *rf : RiseFall::range()) { + float limit; + bool exists; + findLimit(pin, corner, rf, min_max, clks, + limit, exists); + if (exists) { + checkSlew3(vertex, corner, rf, min_max, limit, + corner1, rf1, slew1, slack1, limit1); + } + } +} + +void +CheckSlewLimits::checkSlew3(const Vertex *vertex, + const Corner *corner, + const RiseFall *rf, + const MinMax *min_max, + float limit, + // Return values. + const Corner *&corner1, + const RiseFall *&rf1, + Slew &slew1, + float &slack1, + float &limit1) const +{ + const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); + Slew slew = sta_->graph()->slew(vertex, rf, dcalc_ap->index()); + float slew2 = delayAsFloat(slew); + float slack = (min_max == MinMax::max()) + ? limit - slew2 : slew2 - limit; + if (corner1 == nullptr + || (slack < slack1 + // Break ties for the sake of regression stability. + || (fuzzyEqual(slack, slack1) + && rf->index() < rf1->index()))) { + corner1 = corner; + rf1 = rf; + slew1 = slew; + slack1 = slack; + limit1 = limit; + } +} + // Return the tightest limit. void CheckSlewLimits::findLimit(const Pin *pin, - const Vertex *vertex, const Corner *corner, const RiseFall *rf, const MinMax *min_max, - bool check_clks, + const ClockSet &clks, // Return values. float &limit, bool &exists) const @@ -186,14 +249,10 @@ CheckSlewLimits::findLimit(const Pin *pin, float limit1; bool exists1; - if (check_clks) { + if (!clks.empty()) { // Look for clock slew limits. bool is_clk = sta_->clkNetwork()->isIdealClock(pin); - ClockSet clks; - clockDomains(vertex, clks); - ClockSet::Iterator clk_iter(clks); - while (clk_iter.hasNext()) { - Clock *clk = clk_iter.next(); + for (Clock *clk : clks) { PathClkOrData clk_data = is_clk ? PathClkOrData::clk : PathClkOrData::data; sdc->slewLimit(clk, rf, clk_data, min_max, limit1, exists1); @@ -284,11 +343,10 @@ CheckSlewLimits::findLimit(const LibertyPort *port, } } -void -CheckSlewLimits::clockDomains(const Vertex *vertex, - // Return value. - ClockSet &clks) const +ClockSet +CheckSlewLimits::clockDomains(const Vertex *vertex) const { + ClockSet clks; VertexPathIterator path_iter(const_cast(vertex), sta_); while (path_iter.hasNext()) { Path *path = path_iter.next(); @@ -296,37 +354,7 @@ CheckSlewLimits::clockDomains(const Vertex *vertex, if (clk) clks.insert(const_cast(clk)); } -} - -void -CheckSlewLimits::checkSlew(Vertex *vertex, - const Corner *corner, - const RiseFall *rf, - const MinMax *min_max, - float limit, - // Return values. - const Corner *&corner1, - const RiseFall *&rf1, - Slew &slew1, - float &slack1, - float &limit1) const -{ - const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); - Slew slew = sta_->graph()->slew(vertex, rf, dcalc_ap->index()); - float slew2 = delayAsFloat(slew); - float slack = (min_max == MinMax::max()) - ? limit - slew2 : slew2 - limit; - if (corner1 == nullptr - || (slack < slack1 - // Break ties for the sake of regression stability. - || (fuzzyEqual(slack, slack1) - && rf->index() < rf1->index()))) { - corner1 = corner; - rf1 = rf; - slew1 = slew; - slack1 = slack; - limit1 = limit; - } + return clks; } //////////////////////////////////////////////////////////////// @@ -383,32 +411,4 @@ CheckSlewLimits::checkSlewLimits(const Instance *inst, delete pin_iter; } -void -CheckSlewLimits::checkSlewLimits(const Pin *pin, - bool violators, - const Corner *corner, - const MinMax *min_max, - PinSeq &slew_pins, - float &min_slack) -{ - const Corner *corner1; - const RiseFall *rf; - Slew slew; - float limit, slack; - checkSlew(pin, corner, min_max, true, corner1, rf, slew, limit, slack); - if (!fuzzyInf(slack)) { - if (violators) { - if (slack < 0.0) - slew_pins.push_back(pin); - } - else { - if (slew_pins.empty() - || slack < min_slack) { - slew_pins.push_back(pin); - min_slack = slack; - } - } - } -} - } // namespace diff --git a/search/CheckSlewLimits.hh b/search/CheckSlewLimits.hh index 9e70d69b..d0a8c3c2 100644 --- a/search/CheckSlewLimits.hh +++ b/search/CheckSlewLimits.hh @@ -33,6 +33,13 @@ class CheckSlewLimits { public: CheckSlewLimits(const StaState *sta); + // Return pins with the min/max slew limit slack. + // net=null check all nets + // corner=nullptr checks all corners. + PinSeq checkSlewLimits(const Net *net, + bool violators, + const Corner *corner, + const MinMax *min_max); // corner=nullptr checks all corners. void checkSlew(const Pin *pin, const Corner *corner, @@ -45,13 +52,6 @@ public: Slew &slew, float &limit, float &slack) const; - // Return pins with the min/max slew limit slack. - // net=null check all nets - // corner=nullptr checks all corners. - PinSeq checkSlewLimits(const Net *net, - bool violators, - const Corner *corner, - const MinMax *min_max); void findLimit(const LibertyPort *port, const Corner *corner, const MinMax *min_max, @@ -60,43 +60,44 @@ public: bool &exists) const; protected: - void checkSlews1(const Pin *pin, - const Corner *corner, - const MinMax *min_max, - bool check_clks, - // Return values. - const Corner *&corner1, - const RiseFall *&rf1, - Slew &slew1, - float &limit1, - float &slack1) const; - void checkSlews1(Vertex *vertex, - const Corner *corner, - const MinMax *min_max, - bool check_clks, - // Return values. - const Corner *&corner1, - const RiseFall *&rf1, - Slew &slew1, - float &limit1, - float &slack1) const; - void checkSlew(Vertex *vertex, - const Corner *corner1, - const RiseFall *rf1, - const MinMax *min_max, - float limit1, - // Return values. - const Corner *&corner, - const RiseFall *&rf, - Slew &slew, - float &slack, - float &limit) const; + void checkSlew1(const Pin *pin, + const Vertex *vertex, + const Corner *corner, + const MinMax *min_max, + bool check_clks, + // Return values. + const Corner *&corner1, + const RiseFall *&rf1, + Slew &slew1, + float &limit1, + float &slack1) const; + void checkSlew2(const Pin *pin, + const Vertex *vertex, + const Corner *corner, + const MinMax *min_max, + const ClockSet &clks, + // Return values. + const Corner *&corner1, + const RiseFall *&rf1, + Slew &slew1, + float &limit1, + float &slack1) const; + void checkSlew3(const Vertex *vertex, + const Corner *corner1, + const RiseFall *rf1, + const MinMax *min_max, + float limit1, + // Return values. + const Corner *&corner, + const RiseFall *&rf, + Slew &slew, + float &slack, + float &limit) const; void findLimit(const Pin *pin, - const Vertex *vertex, const Corner *corner, const RiseFall *rf, const MinMax *min_max, - bool check_clks, + const ClockSet &clks, // Return values. float &limit, bool &limit_exists) const; @@ -112,9 +113,7 @@ protected: const MinMax *min_max, PinSeq &slew_pins, float &min_slack); - void clockDomains(const Vertex *vertex, - // Return value. - ClockSet &clks) const; + ClockSet clockDomains(const Vertex *vertex) const; const StaState *sta_; }; diff --git a/search/MakeTimingModel.cc b/search/MakeTimingModel.cc index da3fdbac..e994461f 100644 --- a/search/MakeTimingModel.cc +++ b/search/MakeTimingModel.cc @@ -102,7 +102,7 @@ MakeTimingModel::makeTimingModel() findTimingFromInputs(); findClkedOutputPaths(); - findClkInsertionDelays(); + findClkTreeDelays(); cell_->finish(false, report_, debug_); @@ -542,7 +542,7 @@ MakeTimingModel::findClkedOutputPaths() //////////////////////////////////////////////////////////////// void -MakeTimingModel::findClkInsertionDelays() +MakeTimingModel::findClkTreeDelays() { Instance *top_inst = network_->topInstance(); Cell *top_cell = network_->cell(top_inst); @@ -556,8 +556,7 @@ MakeTimingModel::findClkInsertionDelays() if (pin && sdc_->isClock(pin)) { lib_port->setIsClock(true); ClockSet *clks = sdc_->findClocks(pin); - size_t clk_count = clks->size(); - if (clk_count == 1) { + if (clks->size() == 1) { for (const Clock *clk : *clks) { ClkDelays delays = sta_->findClkDelays(clk, true); for (const MinMax *min_max : MinMax::range()) { diff --git a/search/MakeTimingModelPvt.hh b/search/MakeTimingModelPvt.hh index 832aa822..a2e733db 100644 --- a/search/MakeTimingModelPvt.hh +++ b/search/MakeTimingModelPvt.hh @@ -64,7 +64,7 @@ private: void findTimingFromInputs(); void findTimingFromInput(Port *input_port); void findClkedOutputPaths(); - void findClkInsertionDelays(); + void findClkTreeDelays(); void makeClkTreePaths(LibertyPort *lib_port, const MinMax *min_max, TimingSense sense, diff --git a/search/PathEnd.cc b/search/PathEnd.cc index 6527bf12..02fb39a2 100644 --- a/search/PathEnd.cc +++ b/search/PathEnd.cc @@ -1048,6 +1048,40 @@ PathEndCheck::sourceClkDelay(const StaState *sta) const return 0.0; } +Required +PathEndCheck::requiredTimeNoCrpr(const StaState *sta) const +{ + Arrival tgt_clk_arrival = targetClkArrivalNoCrpr(sta); + ArcDelay check_margin = margin(sta); + float macro_clk_tree_delay = macroClkTreeDelay(sta); + if (checkGenericRole(sta) == TimingRole::setup()) + return tgt_clk_arrival - (check_margin + macro_clk_tree_delay); + else + return tgt_clk_arrival + (check_margin - macro_clk_tree_delay); +} + +float +PathEndCheck::macroClkTreeDelay(const StaState *sta) const +{ + const ClockEdge *tgt_clk_edge = targetClkEdge(sta); + const Clock *tgt_clk = tgt_clk_edge->clock(); + const Network *network = sta->network(); + const Pin *clk_pin = clk_path_.pin(sta); + const Instance *inst = network->instance(clk_pin); + const LibertyCell *inst_cell = network->libertyCell(inst); + if (tgt_clk->isIdeal() + && inst_cell && inst_cell->isMacro()) { + LibertyPort *clk_port = network->libertyPort(clk_pin); + if (clk_port) { + const MinMax *min_max = clk_path_.minMax(sta); + const RiseFall *rf = clk_path_.transition(sta); + float slew = delayAsFloat(clk_path_.slew(sta)); + return clk_port->clkTreeDelay(slew, rf, min_max); + } + } + return 0.0; +} + //////////////////////////////////////////////////////////////// PathEndLatchCheck::PathEndLatchCheck(Path *path, diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 5d42de79..38b39353 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -2455,10 +2455,16 @@ ReportPath::reportRequired(const PathEnd *end, { Required req_time = end->requiredTimeOffset(this); const EarlyLate *early_late = end->clkEarlyLate(this); + float macro_clk_tree_delay = end->macroClkTreeDelay(this); ArcDelay margin = end->margin(this); - if (end->minMax(this) == MinMax::max()) + if (end->minMax(this) == MinMax::min()) { margin = -margin; - reportLine(margin_msg.c_str(), margin, req_time, early_late); + macro_clk_tree_delay = -macro_clk_tree_delay; + } + if (macro_clk_tree_delay != 0.0) + reportLine("macro clock tree delay", -macro_clk_tree_delay, + req_time + margin, early_late); + reportLine(margin_msg.c_str(), -margin, req_time, early_late); reportLine("data required time", req_time, early_late); reportDashLine(); } diff --git a/search/Search.cc b/search/Search.cc index b03d15b6..daa68fd1 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -2139,6 +2139,18 @@ PathVisitor::visitFromPath(const Pin *from_pin, if (clk == nullptr || !sdc_->clkStopPropagation(from_pin, clk)) { arc_delay = search_->deratedDelay(from_vertex, arc, edge, false, path_ap); + + // Remove clock network delay for macros created with propagated + // clocks when used in a context with ideal clocks. + if (clk && clk->isIdeal()) { + const LibertyPort *clk_port = network_->libertyPort(from_pin); + const LibertyCell *inst_cell = clk_port->libertyCell(); + if (inst_cell->isMacro()) { + float slew = delayAsFloat(from_path->slew(this)); + arc_delay -= clk_port->clkTreeDelay(slew, from_rf, min_max); + } + } + // Propagate from unclocked reg/latch clk pins, which have no // clk but are distinguished with a segment_start flag. if ((clk_edge == nullptr diff --git a/search/Search.i b/search/Search.i index d0727538..e7017058 100644 --- a/search/Search.i +++ b/search/Search.i @@ -155,6 +155,7 @@ init_sta() initSta(); } +// Clear all state except network. void clear_sta() {