diff --git a/include/sta/PathEnd.hh b/include/sta/PathEnd.hh index e5f983d4..82e16883 100644 --- a/include/sta/PathEnd.hh +++ b/include/sta/PathEnd.hh @@ -142,6 +142,7 @@ public: virtual TimingArc *checkArc() const { return nullptr; } // PathEndDataCheck data clock path. virtual const PathVertex *dataClkPath() const { return nullptr; } + virtual int setupDefaultCycles() const { return 1; } static bool less(const PathEnd *path_end1, const PathEnd *path_end2, @@ -181,6 +182,7 @@ public: static float checkSetupMcpAdjustment(const ClockEdge *src_clk_edge, const ClockEdge *tgt_clk_edge, const MultiCyclePath *mcp, + int default_cycles, Sdc *sdc); protected: @@ -545,6 +547,8 @@ protected: Crpr crpr, bool crpr_valid); Arrival requiredTimeNoCrpr(const StaState *sta) const; + // setup uses zero cycle default + virtual int setupDefaultCycles() const { return 0; } private: PathVertex data_clk_path_; diff --git a/search/Latches.cc b/search/Latches.cc index 687ecfec..629ce6fe 100644 --- a/search/Latches.cc +++ b/search/Latches.cc @@ -92,7 +92,7 @@ Latches::latchRequired(const Path *data_path, + open_latency + open_uncertainty + PathEnd::checkSetupMcpAdjustment(data_clk_edge, enable_clk_edge, mcp, - sdc_) + 1, sdc_) + open_crpr; debugPrint3(debug_, "latch", 1, "latch data %s %s enable %s\n", network_->pathName(data_path->pin(this)), diff --git a/search/PathEnd.cc b/search/PathEnd.cc index ff7a9b32..8e1ab6be 100644 --- a/search/PathEnd.cc +++ b/search/PathEnd.cc @@ -358,7 +358,9 @@ PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path, const RiseFall *tgt_clk_rf = tgt_clk_edge->transition(); insertion = search->clockInsertion(tgt_clk, tgt_src_pin, tgt_clk_rf, min_max, early_late, tgt_path_ap); - if (clk_info->isPropagated()) { + if (clk_info->isPropagated() + // Data check target clock is always propagated. + || check_role->isDataCheck()) { // Propagated clock. Propagated arrival is seeded with // early_late==path_min_max insertion delay. Arrival clk_arrival = tgt_clk_path->arrival(sta); @@ -824,7 +826,7 @@ PathEndClkConstrainedMcp::checkMcpAdjustment(const Path *path, Sdc *sdc = sta->sdc(); if (min_max == MinMax::max()) return PathEnd::checkSetupMcpAdjustment(src_clk_edge, tgt_clk_edge, - mcp_, sdc); + mcp_, setupDefaultCycles(), sdc); else { // Hold check. // Default arrival clock is a proxy for the target clock. @@ -874,6 +876,7 @@ float PathEnd::checkSetupMcpAdjustment(const ClockEdge *src_clk_edge, const ClockEdge *tgt_clk_edge, const MultiCyclePath *mcp, + int default_cycles, Sdc *sdc) { if (mcp) { @@ -887,7 +890,7 @@ PathEnd::checkSetupMcpAdjustment(const ClockEdge *src_clk_edge, const ClockEdge *clk_edge = mcp->useEndClk() ? tgt_clk_edge : src_clk_edge; float period = clk_edge->clock()->period(); - return (mult - 1) * period; + return (mult - default_cycles) * period; } else return 0.0; diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 2a9187d9..367d5c27 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -947,8 +947,8 @@ ReportPath::reportFull(const PathEndDataCheck *end, reportShort(end, expanded, result); reportSrcPathArrival(end, expanded, result); - // Capture/target clock path reporting resembles both source (reportSrcPath) - // and target (reportTgtClk) clocks. + // Data check target clock path reporting resembles + // both source (reportSrcPath) and target (reportTgtClk) clocks. // It is like a source because it can be a non-clock path. // It is like a target because crpr and uncertainty are reported. // It is always propagated, even if the clock is ideal. @@ -960,12 +960,14 @@ ReportPath::reportFull(const PathEndDataCheck *end, float src_offset = end->sourceClkOffset(this); Delay clk_delay = end->targetClkDelay(this); Arrival clk_arrival = end->targetClkArrival(this); - float offset = delayAsFloat(clk_arrival - clk_delay + src_offset); + ClockEdge *tgt_clk_edge = end->targetClkEdge(this); + float prev = delayAsFloat(clk_arrival) + src_offset; + float offset = prev - delayAsFloat(clk_delay) - tgt_clk_edge->time(); reportPath5(data_clk_path, clk_expanded, clk_expanded.startIndex(), clk_expanded.size() - 1, data_clk_path->clkInfo(search_)->isPropagated(), false, // Delay to startpoint is already included. - clk_arrival + src_offset, offset, result); + prev, offset, result); } reportRequired(end, checkRoleReason(end), result); reportSlack(end, result); diff --git a/search/VisitPathEnds.cc b/search/VisitPathEnds.cc index d3bd3da7..99e1152a 100644 --- a/search/VisitPathEnds.cc +++ b/search/VisitPathEnds.cc @@ -556,8 +556,8 @@ VisitPathEnds::visitDataCheckEnd1(DataCheck *check, || exception->isMultiCycle()) && (!filtered || search_->matchesFilter(path, tgt_clk_edge))) { - // No mcp for data checks. - PathEndDataCheck path_end(check, path, tgt_clk_path, nullptr, this); + MultiCyclePath *mcp=dynamic_cast(exception); + PathEndDataCheck path_end(check, path, tgt_clk_path, mcp, this); visitor->visit(&path_end); is_constrained = true; }