diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index f7b233da..cdf67203 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -1365,6 +1365,7 @@ protected: virtual void makeCheckMaxSkews(); virtual void makeReportPath(); virtual void makePower(); + virtual void makeClkSkews(); virtual void makeObservers(); NetworkEdit *networkCmdEdit(); diff --git a/search/ClkSkew.cc b/search/ClkSkew.cc index eb32989c..33df2af6 100644 --- a/search/ClkSkew.cc +++ b/search/ClkSkew.cc @@ -50,40 +50,6 @@ namespace sta { using std::abs; -// Source/target clock skew. -class ClkSkew -{ -public: - ClkSkew(); - ClkSkew(Path *src_path, - Path *tgt_path, - bool include_internal_latency, - StaState *sta); - ClkSkew(const ClkSkew &clk_skew); - void operator=(const ClkSkew &clk_skew); - Path *srcPath() { return src_path_; } - Path *tgtPath() { return tgt_path_; } - float srcLatency(const StaState *sta); - float tgtLatency(const StaState *sta); - float srcInternalClkLatency(const StaState *sta); - float tgtInternalClkLatency(const StaState *sta); - Crpr crpr(const StaState *sta); - float uncertainty(const StaState *sta); - float skew() const { return skew_; } - static bool srcTgtPathNameLess(ClkSkew &clk_skew1, - ClkSkew &clk_skew2, - const StaState *sta); - -private: - float clkTreeDelay(Path *clk_path, - const StaState *sta); - - Path *src_path_; - Path *tgt_path_; - bool include_internal_latency_; - float skew_; -}; - ClkSkew::ClkSkew() : src_path_(nullptr), tgt_path_(nullptr), @@ -206,10 +172,18 @@ ClkSkew::srcTgtPathNameLess(ClkSkew &clk_skew1, ClkSkews::ClkSkews(StaState *sta) : StaState(sta), + corner_(nullptr), + include_internal_latency_(true), fanout_pred_(sta) { } +void +ClkSkews::clear() +{ + skews_.clear(); +} + void ClkSkews::reportClkSkew(ConstClockSeq &clks, const Corner *corner, @@ -217,8 +191,7 @@ ClkSkews::reportClkSkew(ConstClockSeq &clks, bool include_internal_latency, int digits) { - ClkSkewMap skews = findClkSkew(clks, corner, setup_hold, - include_internal_latency); + findClkSkew(clks, corner, include_internal_latency); // Sort the clocks to report in a stable order. ConstClockSeq sorted_clks; @@ -228,9 +201,9 @@ ClkSkews::reportClkSkew(ConstClockSeq &clks, for (const Clock *clk : sorted_clks) { report_->reportLine("Clock %s", clk->name()); - auto skew_itr = skews.find(clk); - if (skew_itr != skews.end()) - reportClkSkew(skew_itr->second, digits); + auto skew_itr = skews_.find(clk); + if (skew_itr != skews_.end()) + reportClkSkew(skew_itr->second[setup_hold->index()], digits); else report_->reportLine("No launch/capture paths found."); report_->reportBlankLine(); @@ -289,25 +262,30 @@ ClkSkews::findWorstClkSkew(const Corner *corner, ConstClockSeq clks; for (const Clock *clk : *sdc_->clocks()) clks.push_back(clk); - ClkSkewMap skews = findClkSkew(clks, corner, setup_hold, include_internal_latency); + findClkSkew(clks, corner, include_internal_latency); float worst_skew = 0.0; - for (const auto& [clk, clk_skew] : skews) { - float skew = clk_skew.skew(); + for (const auto& [clk, clk_skews] : skews_) { + float skew = clk_skews[setup_hold->index()].skew(); if (abs(skew) > abs(worst_skew)) worst_skew = skew; } return worst_skew; } -ClkSkewMap +void ClkSkews::findClkSkew(ConstClockSeq &clks, const Corner *corner, - const SetupHold *setup_hold, bool include_internal_latency) { - ClkSkewMap skews; + if (corner == corner_ + && include_internal_latency == include_internal_latency_ + && clks == clks_ + && !skews_.empty()) + return; + + skews_.clear(); + clks_ = clks; corner_ = corner; - setup_hold_ = setup_hold; include_internal_latency_ = include_internal_latency; clk_set_.clear(); @@ -315,7 +293,7 @@ ClkSkews::findClkSkew(ConstClockSeq &clks, clk_set_.insert(clk); if (thread_count_ > 1) { - std::vector partial_skews(thread_count_, skews); + std::vector partial_skews(thread_count_); for (Vertex *src_vertex : *graph_->regClkVertices()) { if (hasClkPaths(src_vertex)) { dispatch_queue_->dispatch([this, src_vertex, &partial_skews](int i) { @@ -328,14 +306,30 @@ ClkSkews::findClkSkew(ConstClockSeq &clks, // Reduce skews from each register source. for (size_t i = 0; i < partial_skews.size(); i++) { for (auto& [clk, partial_skew] : partial_skews[i]) { - auto ins = skews.insert(std::make_pair(clk, partial_skew)); - if (!ins.second) { - ClkSkew &final_skew = ins.first->second; - if (abs(partial_skew.skew()) > abs(final_skew.skew()) - || (fuzzyEqual(abs(partial_skew.skew()), abs(final_skew.skew())) - // Break ties based on source/target path names. - && ClkSkew::srcTgtPathNameLess(partial_skew, final_skew, this))) - final_skew = partial_skew; + auto itr = skews_.find(clk); + if (itr == skews_.end()) { + // Insert new entry using emplace with piecewise_construct + // This will default-construct the array, then we copy the elements + auto result = skews_.emplace(std::piecewise_construct, + std::forward_as_tuple(clk), + std::make_tuple()); + itr = result.first; + // Copy array elements + for (int setup_hold_idx : SetupHold::rangeIndex()) + itr->second[setup_hold_idx] = partial_skew[setup_hold_idx]; + } else { + // Update existing entry + for (int setup_hold_idx : SetupHold::rangeIndex()) { + ClkSkew &final_skew = itr->second[setup_hold_idx]; + ClkSkew &partial_skew_val = partial_skew[setup_hold_idx]; + float partial_skew1 = partial_skew_val.skew(); + float final_skew1 = final_skew.skew(); + if (abs(partial_skew1) > abs(final_skew1) + || (fuzzyEqual(abs(partial_skew1), abs(final_skew1)) + // Break ties based on source/target path names. + && ClkSkew::srcTgtPathNameLess(partial_skew_val, final_skew, this))) + final_skew = partial_skew_val; + } } } } @@ -343,10 +337,9 @@ ClkSkews::findClkSkew(ConstClockSeq &clks, else { for (Vertex *src_vertex : *graph_->regClkVertices()) { if (hasClkPaths(src_vertex)) - findClkSkewFrom(src_vertex, skews); + findClkSkewFrom(src_vertex, skews_); } } - return skews; } bool @@ -392,11 +385,8 @@ ClkSkews::findClkSkewFrom(Vertex *src_vertex, while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); const TimingRole *role = edge->role(); - if (role->isTimingCheck() - && ((setup_hold_ == SetupHold::max() - && role->genericRole() == TimingRole::setup()) - || ((setup_hold_ == SetupHold::min() - && role->genericRole() == TimingRole::hold())))) { + if (role->genericRole() == TimingRole::setup() + || role->genericRole() == TimingRole::hold()) { Vertex *tgt_vertex = edge->from(graph_); const RiseFall *tgt_rf1 = edge->timingArcSet()->isRisingFallingEdge(); const RiseFallBoth *tgt_rf = tgt_rf1 @@ -416,16 +406,15 @@ ClkSkews::findClkSkew(Vertex *src_vertex, ClkSkewMap &skews) { Unit *time_unit = units_->timeUnit(); - const SetupHold *tgt_min_max = setup_hold_->opposite(); VertexPathIterator src_iter(src_vertex, this); while (src_iter.hasNext()) { Path *src_path = src_iter.next(); const Clock *src_clk = src_path->clock(this); if (src_path->isClock(this) && src_rf->matches(src_path->transition(this)) - && src_path->minMax(this) == setup_hold_ && clk_set_.find(src_clk) != clk_set_.end()) { Corner *src_corner = src_path->pathAnalysisPt(this)->corner(); + const MinMax *tgt_min_max = src_path->minMax(this)->opposite(); if (corner_ == nullptr || src_corner == corner_) { VertexPathIterator tgt_iter(tgt_vertex, this); @@ -438,7 +427,8 @@ ClkSkews::findClkSkew(Vertex *src_vertex, && tgt_path->minMax(this) == tgt_min_max && tgt_path->pathAnalysisPt(this)->corner() == src_corner) { ClkSkew probe(src_path, tgt_path, include_internal_latency_, this); - ClkSkew &clk_skew = skews[src_clk]; + const SetupHold *setup_hold = src_path->minMax(this); + ClkSkew &clk_skew = skews[src_clk][setup_hold->index()]; debugPrint(debug_, "clk_skew", 2, "%s %s %s -> %s %s %s crpr = %s skew = %s", network_->pathName(src_path->pin(this)), diff --git a/search/ClkSkew.hh b/search/ClkSkew.hh index 712e7b8b..f59d03dc 100644 --- a/search/ClkSkew.hh +++ b/search/ClkSkew.hh @@ -36,10 +36,43 @@ namespace sta { -class ClkSkew; class SearchPred; -typedef std::map ClkSkewMap; +// Source/target clock skew. +class ClkSkew +{ +public: + ClkSkew(); + ClkSkew(Path *src_path, + Path *tgt_path, + bool include_internal_latency, + StaState *sta); + ClkSkew(const ClkSkew &clk_skew); + void operator=(const ClkSkew &clk_skew); + Path *srcPath() { return src_path_; } + Path *tgtPath() { return tgt_path_; } + float srcLatency(const StaState *sta); + float tgtLatency(const StaState *sta); + float srcInternalClkLatency(const StaState *sta); + float tgtInternalClkLatency(const StaState *sta); + Crpr crpr(const StaState *sta); + float uncertainty(const StaState *sta); + float skew() const { return skew_; } + static bool srcTgtPathNameLess(ClkSkew &clk_skew1, + ClkSkew &clk_skew2, + const StaState *sta); + +private: + float clkTreeDelay(Path *clk_path, + const StaState *sta); + + Path *src_path_; + Path *tgt_path_; + bool include_internal_latency_; + float skew_; +}; + +typedef std::map ClkSkewMap; class FanOutSrchPred : public SearchPred1 { @@ -53,6 +86,7 @@ class ClkSkews : public StaState { public: ClkSkews(StaState *sta); + void clear(); // Report clk skews for clks. void reportClkSkew(ConstClockSeq &clks, const Corner *corner, @@ -65,10 +99,9 @@ public: bool include_internal_latency); protected: - ClkSkewMap findClkSkew(ConstClockSeq &clks, - const Corner *corner, - const SetupHold *setup_hold, - bool include_internal_latency); + void findClkSkew(ConstClockSeq &clks, + const Corner *corner, + bool include_internal_latency); bool hasClkPaths(Vertex *vertex); void findClkSkewFrom(Vertex *src_vertex, ClkSkewMap &skews); @@ -88,11 +121,12 @@ protected: void reportClkSkew(ClkSkew &clk_skew, int digits); + ConstClockSeq clks_; ConstClockSet clk_set_; const Corner *corner_; - const SetupHold *setup_hold_; bool include_internal_latency_; FanOutSrchPred fanout_pred_; + ClkSkewMap skews_; }; } // namespace diff --git a/search/Sta.cc b/search/Sta.cc index 99675388..51158cf8 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -310,6 +310,8 @@ Sta::makeComponents() makeSdcNetwork(); makeReportPath(); makePower(); + makeClkSkews(); + setCmdNamespace1(CmdNamespace::sdc); setThreadCount1(defaultThreadCount()); updateComponentsState(); @@ -371,8 +373,7 @@ Sta::updateComponentsState() if (check_timing_) check_timing_->copyState(this); clk_network_->copyState(this); - if (clk_skews_) - clk_skews_->copyState(this); + clk_skews_->copyState(this); if (power_) power_->copyState(this); } @@ -590,6 +591,7 @@ Sta::clear() check_min_pulse_widths_->clear(); if (check_min_periods_) check_min_periods_->clear(); + clk_skews_->clear(); delete graph_; graph_ = nullptr; current_instance_ = nullptr; @@ -611,6 +613,7 @@ Sta::networkChanged() check_min_pulse_widths_->clear(); if (check_min_periods_) check_min_periods_->clear(); + clk_skews_->clear(); delete graph_; graph_ = nullptr; graph_sdc_annotated_ = false; @@ -2481,6 +2484,7 @@ Sta::findPathEnds(ExceptionFrom *from, bool clk_gating_hold) { searchPreamble(); + clk_skews_->clear(); return search_->findPathEnds(from, thrus, to, unconstrained, corner, min_max, group_path_count, endpoint_path_count, @@ -2628,8 +2632,9 @@ float Sta::findWorstClkSkew(const SetupHold *setup_hold, bool include_internal_latency) { + clkSkewPreamble(); - return clk_skews_->findWorstClkSkew(cmd_corner_, setup_hold, + return clk_skews_->findWorstClkSkew(nullptr, setup_hold, include_internal_latency); } @@ -2637,8 +2642,12 @@ void Sta::clkSkewPreamble() { ensureClkArrivals(); - if (clk_skews_ == nullptr) - clk_skews_ = new ClkSkews(this); +} + +void +Sta::makeClkSkews() +{ + clk_skews_ = new ClkSkews(this); } //////////////////////////////////////////////////////////////// @@ -4367,6 +4376,7 @@ Sta::replaceCellBefore(const Instance *inst, } } delete pin_iter; + clk_skews_->clear(); } } @@ -4431,6 +4441,7 @@ Sta::connectPinAfter(const Pin *pin) } sdc_->connectPinAfter(pin); sim_->connectPinAfter(pin); + clk_skews_->clear(); } void @@ -4521,6 +4532,7 @@ Sta::disconnectPinBefore(const Pin *pin) } } } + clk_skews_->clear(); } } @@ -4671,6 +4683,7 @@ Sta::deletePinBefore(const Pin *pin) sim_->deletePinBefore(pin); clk_network_->deletePinBefore(pin); power_->deletePinBefore(pin); + clk_skews_->clear(); } void