diff --git a/include/sta/ExceptionPath.hh b/include/sta/ExceptionPath.hh index c67270ae..0b5e824e 100644 --- a/include/sta/ExceptionPath.hh +++ b/include/sta/ExceptionPath.hh @@ -66,6 +66,7 @@ public: virtual bool isLoop() const { return false; } virtual bool isMultiCycle() const { return false; } virtual bool isPathDelay() const { return false; } + virtual bool isPathMargin() const { return false; } virtual bool isGroupPath() const { return false; } virtual bool isFilter() const { return false; } virtual ExceptionPathType type() const = 0; @@ -101,6 +102,7 @@ public: static int pathDelayPriority() { return 3000; } static int multiCyclePathPriority() { return 2000; } static int filterPathPriority() { return 1000; } + static int pathMarginPriority() { return 500; } static int groupPathPriority() { return 0; } // Compare the value (path delay or cycle count) to another exception // of the same priority. Because the exception "values" are floats, @@ -130,6 +132,7 @@ public: virtual bool useEndClk() const { return false; } virtual int pathMultiplier() const { return 0; } virtual float delay() const { return 0.0; } + virtual float margin() const { return 0.0; } virtual std::string_view name() const { return {}; } virtual bool isDefault() const { return false; } virtual bool ignoreClkLatency() const { return false; } @@ -227,6 +230,34 @@ protected: float delay_; }; +// set_path_margin +class PathMargin : public ExceptionPath +{ +public: + PathMargin(ExceptionFrom *from, + ExceptionThruSeq *thrus, + ExceptionTo *to, + const MinMaxAll *min_max, + float margin, + bool own_pts, + std::string_view comment); + virtual ExceptionPath *clone(ExceptionFrom *from, + ExceptionThruSeq *thrus, + ExceptionTo *to, + bool own_pts); + virtual bool isPathMargin() const { return true; } + virtual ExceptionPathType type() const { return ExceptionPathType::path_margin; } + virtual std::string_view typeString() const; + virtual bool mergeable(ExceptionPath *exception) const; + virtual bool overrides(ExceptionPath *exception) const; + virtual float margin() const { return margin_; } + virtual int typePriority() const; + virtual bool tighterThan(ExceptionPath *exception) const; + +protected: + float margin_; +}; + // set_multicycle_path class MultiCyclePath : public ExceptionPath { diff --git a/include/sta/PathEnd.hh b/include/sta/PathEnd.hh index be54fa73..25327739 100644 --- a/include/sta/PathEnd.hh +++ b/include/sta/PathEnd.hh @@ -135,6 +135,8 @@ public: // Target clock uncertainty + inter-clk uncertainty. virtual float targetClkUncertainty(const StaState *sta) const; virtual float targetClkMcpAdjustment(const StaState *sta) const; + // Target clock path margin. + virtual float targetClkPathMargin(const StaState *sta) const; virtual const TimingRole *checkRole(const StaState *sta) const; const TimingRole *checkGenericRole(const StaState *sta) const; virtual bool pathDelayMarginIsExternal() const; @@ -260,6 +262,7 @@ public: float targetNonInterClkUncertainty(const StaState *sta) const override; float interClkUncertainty(const StaState *sta) const override; float targetClkUncertainty(const StaState *sta) const override; + float targetClkPathMargin(const StaState *sta) const override; Crpr crpr(const StaState *sta) const override; Required requiredTime(const StaState *sta) const override; Slack slack(const StaState *sta) const override; diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index 96c0fd8f..cf064c19 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -765,6 +765,12 @@ public: bool break_path, float delay, std::string_view comment); + void makePathMargin(ExceptionFrom *from, + ExceptionThruSeq *thrus, + ExceptionTo *to, + const MinMaxAll *min_max, + float margin, + std::string_view comment); bool pathDelaysWithoutTo() const { return path_delays_without_to_; } // Delete matching false/multicycle/path_delay exceptions. // Caller owns from, thrus, to exception points (and must delete them). diff --git a/include/sta/SdcClass.hh b/include/sta/SdcClass.hh index 57065089..a5459b85 100644 --- a/include/sta/SdcClass.hh +++ b/include/sta/SdcClass.hh @@ -69,6 +69,7 @@ class PortDelay; enum class AnalysisType { single, bc_wc, ocv }; enum class ExceptionPathType { false_path, loop, multi_cycle, path_delay, + path_margin, group_path, filter, any}; enum class ClockSense { positive, negative, stop }; diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 76264086..8e4a94db 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -659,6 +659,13 @@ public: float delay, std::string_view comment, Sdc *sdc); + void makePathMargin(ExceptionFrom *from, + ExceptionThruSeq *thrus, + ExceptionTo *to, + const MinMaxAll *min_max, + float margin, + std::string_view comment, + Sdc *sdc); void makeGroupPath(std::string_view name, bool is_default, ExceptionFrom *from, diff --git a/sdc/ExceptionPath.cc b/sdc/ExceptionPath.cc index 151c98ad..34aab4bc 100644 --- a/sdc/ExceptionPath.cc +++ b/sdc/ExceptionPath.cc @@ -559,6 +559,64 @@ PathDelay::overrides(ExceptionPath *exception) const //////////////////////////////////////////////////////////////// +PathMargin::PathMargin(ExceptionFrom *from, + ExceptionThruSeq *thrus, + ExceptionTo *to, + const MinMaxAll *min_max, + float margin, + bool own_pts, + std::string_view comment) : + ExceptionPath(from, thrus, to, min_max, own_pts, + pathMarginPriority() + fromThruToPriority(from, thrus, to), + comment), + margin_(margin) +{ +} + +ExceptionPath * +PathMargin::clone(ExceptionFrom *from, + ExceptionThruSeq *thrus, + ExceptionTo *to, + bool own_pts) +{ + return new PathMargin(from, thrus, to, min_max_, margin_, own_pts, comment_); +} + +int +PathMargin::typePriority() const +{ + return pathMarginPriority(); +} + +bool +PathMargin::tighterThan(ExceptionPath *) const +{ + return false; +} + +std::string_view +PathMargin::typeString() const +{ + return "Margin"; +} + +bool +PathMargin::mergeable(ExceptionPath *) const +{ + return false; +} + +bool +PathMargin::overrides(ExceptionPath *exception) const +{ + // A later set_path_margin with the same scope replaces the earlier one. + return exception->isPathMargin() + && exception->priority() == priority_ + && exception->minMax() == min_max_; +} + +//////////////////////////////////////////////////////////////// + FalsePath::FalsePath(ExceptionFrom *from, ExceptionThruSeq *thrus, ExceptionTo *to, diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 6bf69fd1..fc82ef54 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -4103,6 +4103,20 @@ Sdc::makePathDelay(ExceptionFrom *from, addException(exception); } +void +Sdc::makePathMargin(ExceptionFrom *from, + ExceptionThruSeq *thrus, + ExceptionTo *to, + const MinMaxAll *min_max, + float margin, + std::string_view comment) +{ + checkFromThrusTo(from, thrus, to); + PathMargin *exception = new PathMargin(from, thrus, to, min_max, + margin, true, comment); + addException(exception); +} + void Sdc::recordPathDelayInternalFrom(ExceptionPath *exception) { @@ -4510,7 +4524,8 @@ Sdc::addException1(ExceptionPath *exception) void Sdc::addException2(ExceptionPath *exception) { - if (exception->isMultiCycle() || exception->isPathDelay()) + if (exception->isMultiCycle() || exception->isPathDelay() + || exception->isPathMargin()) deleteMatchingExceptions(exception); recordException(exception); mergeException(exception); diff --git a/sdc/Sdc.i b/sdc/Sdc.i index e4953246..16e5bc40 100644 --- a/sdc/Sdc.i +++ b/sdc/Sdc.i @@ -855,6 +855,19 @@ make_path_delay(ExceptionFrom *from, delay, std::move(comment), sdc); } +void +make_path_margin(ExceptionFrom *from, + ExceptionThruSeq *thrus, + ExceptionTo *to, + const MinMaxAll *min_max, + float margin, + std::string_view comment) +{ + Sta *sta = Sta::sta(); + Sdc *sdc = sta->cmdSdc(); + sta->makePathMargin(from, thrus, to, min_max, margin, comment, sdc); +} + void reset_path_cmd(ExceptionFrom * from, ExceptionThruSeq *thrus, diff --git a/sdc/Sdc.tcl b/sdc/Sdc.tcl index 008d1891..b938b7b1 100644 --- a/sdc/Sdc.tcl +++ b/sdc/Sdc.tcl @@ -2475,6 +2475,61 @@ proc set_min_delay { args } { ################################################################ +define_cmd_args "set_path_margin" \ + {[-setup] [-hold] [-rise] [-fall] [-comment comment]\ + [-from from_list] [-rise_from from_list] [-fall_from from_list]\ + [-through|-thr|-th through_list] [-rise_through|-rise_thr|-rise_th through_list]\ + [-fall_through|-fall_thr|-fall_th through_list]\ + [-to to_list] [-rise_to to_list] [-fall_to to_list] margin} + +proc set_path_margin { args } { + parse_key_args "set_path_margin" args \ + keys {-from -rise_from -fall_from -to -rise_to -fall_to -comment} \ + flags {-rise -fall -setup -hold} 0 + + # Applies to setup, hold, or both. + set min_max "min_max" + if { [info exists flags(-setup)] && ![info exists flags(-hold)] } { + set min_max "max" + } elseif { [info exists flags(-hold)] && ![info exists flags(-setup)] } { + set min_max "min" + } + + # Validate arguments. + set cmd "set_path_margin" + set arg_error 0 + set from [parse_from_arg keys arg_error] + set thrus [parse_thrus_arg args arg_error] + set to [parse_to_arg keys flags arg_error] + check_exception_pins $from $to + if { $arg_error } { + delete_from_thrus_to $from $thrus $to + return + } + + # Validate margin value count and argument type. + check_for_key_args $cmd args + if { [llength $args] == 0 } { + delete_from_thrus_to $from $thrus $to + sta_error 1800 "missing margin argument." + } elseif { [llength $args] > 1 } { + sta_warn 1801 "'$args' ignored." + } + if { $from == "NULL" && $thrus == "" && $to == "NULL" } { + delete_from_thrus_to $from $thrus $to + sta_error 1802 "-from, -through or -to required." + } + + # Parse margin value. + set margin [lindex $args 0] + check_float "set_path_margin margin" $margin + set margin [time_ui_sta $margin] + set comment [parse_comment_key keys] + make_path_margin $from $thrus $to $min_max $margin $comment +} + +################################################################ + define_cmd_args "set_min_pulse_width" {[-low] [-high] value [objects]} proc set_min_pulse_width { args } { diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index 9ae97fea..22459122 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -1273,6 +1273,10 @@ WriteSdc::writeExceptionCmd(ExceptionPath *exception) const if (exception->ignoreClkLatency()) sta::print(stream_, " -ignore_clock_latency"); } + else if (exception->isPathMargin()) { + gzprintf(stream_, "set_path_margin"); + writeSetupHoldFlag(exception->minMax()); + } else if (exception->isGroupPath()) { if (exception->isDefault()) sta::print(stream_, "group_path -default"); @@ -1293,6 +1297,10 @@ WriteSdc::writeExceptionValue(ExceptionPath *exception) const sta::print(stream_, " "); writeTime(exception->delay()); } + else if (exception->isPathMargin()) { + gzprintf(stream_, " "); + writeTime(exception->margin()); + } } void diff --git a/search/PathEnd.cc b/search/PathEnd.cc index e917d89f..8dd8d845 100644 --- a/search/PathEnd.cc +++ b/search/PathEnd.cc @@ -222,6 +222,12 @@ PathEnd::targetClkMcpAdjustment(const StaState *) const return 0.0; } +float +PathEnd::targetClkPathMargin(const StaState *) const +{ + return 0.0; +} + const TimingRole * PathEnd::checkRole(const StaState *) const { @@ -630,8 +636,8 @@ PathEndClkConstrained::targetClkArrivalNoCrpr(const StaState *sta) const targetClkPath(), checkRole(sta), sdc); - return delaySum(delaySum(clk_arrival, uncertainty, sta), - targetClkMcpAdjustment(sta), sta); + return delaySum(delaySum(delaySum(clk_arrival, uncertainty, sta), + targetClkMcpAdjustment(sta), sta), targetClkPathMargin(sta), sta); } Delay @@ -692,6 +698,25 @@ PathEndClkConstrained::targetClkUncertainty(const StaState *sta) const targetClkPath(), checkRole(sta), sdc); } +float +PathEndClkConstrained::targetClkPathMargin(const StaState *sta) const +{ + Sdc *sdc = path_->sdc(sta); + ExceptionPath *exception = + sta->search()->exceptionTo(ExceptionPathType::path_margin, + path_, path_->pin(sta), + path_->transition(sta), + targetClkEdge(sta), + checkRole(sta)->pathMinMax(), + false, false, sdc); + if (!exception) + return 0.0; + float margin = exception->margin(); + if (checkRole(sta)->genericRole() == TimingRole::setup()) + margin = -margin; + return margin; +} + Crpr PathEndClkConstrained::crpr(const StaState *sta) const { @@ -1386,11 +1411,12 @@ PathEndOutputDelay::targetClkArrivalNoCrpr(const StaState *sta) const Arrival base = delaySum(targetClkTime(sta), tgtClkDelay(tgt_clk_edge, check_role, sta), sta); - return delaySum(delaySum(base, + return delaySum(delaySum(delaySum(base, targetClkUncertainty(sta), sta), checkMcpAdjustment(path_, tgt_clk_edge, sta), - sta); + sta), + targetClkPathMargin(sta), sta); } } @@ -1881,9 +1907,9 @@ PathEndPathDelay::targetClkArrivalNoCrpr(const StaState *sta) const { const ClockEdge *tgt_clk_edge = targetClkEdge(sta); if (tgt_clk_edge) - return delaySum(targetClkDelay(sta), + return delaySum(delaySum(targetClkDelay(sta), targetClkUncertainty(sta), - sta); + sta), targetClkPathMargin(sta), sta); else if (clk_path_) return clk_path_->arrival(); else diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 1333aa89..6ea84b93 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -1246,6 +1246,10 @@ ReportPath::reportJson(const PathEnd *end, delayAsFloat(end->checkCrpr(this))); result += sta::format(" \"margin\": {:.3e},\n", delayAsFloat(end->margin(this))); + float path_margin = end->targetClkPathMargin(this); + if (path_margin != 0.0) + result += sta::format(" \"path_margin\": {:.3e},\n", + path_margin); result += sta::format(" \"required_time\": {:.3e},\n", delayAsFloat(end->requiredTimeOffset(this))); result += sta::format(" \"slack\": {:.3e}\n", @@ -2681,6 +2685,10 @@ ReportPath::reportClkUncertainty(const PathEnd *end, if (inter_uncertainty != 0.0) reportLine("inter-clock uncertainty", inter_uncertainty, clk_arrival, early_late); + float margin = end->targetClkPathMargin(this); + clk_arrival = delaySum(clk_arrival, margin, this); + if (margin != 0.0) + reportLine("path margin", margin, clk_arrival, early_late); } //////////////////////////////////////////////////////////////// diff --git a/search/Sta.cc b/search/Sta.cc index 2e394985..8b5f0373 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -2069,6 +2069,19 @@ Sta::makePathDelay(ExceptionFrom *from, search_->arrivalsInvalid(); } +void +Sta::makePathMargin(ExceptionFrom *from, + ExceptionThruSeq *thrus, + ExceptionTo *to, + const MinMaxAll *min_max, + float margin, + std::string_view comment, + Sdc *sdc) +{ + sdc->makePathMargin(from, thrus, to, min_max, margin, comment); + search_->arrivalsInvalid(); +} + void Sta::resetPath(ExceptionFrom *from, ExceptionThruSeq *thrus, diff --git a/search/VisitPathEnds.cc b/search/VisitPathEnds.cc index 3a420aad..821dd16c 100644 --- a/search/VisitPathEnds.cc +++ b/search/VisitPathEnds.cc @@ -185,7 +185,8 @@ VisitPathEnds::visitCheckEnd(const Pin *pin, && (exception == nullptr || exception->isFilter() || exception->isGroupPath() - || exception->isMultiCycle())) { + || exception->isMultiCycle() + || exception->isPathMargin())) { MultiCyclePath *mcp=dynamic_cast(exception); if (network_->isLatchData(pin) && check_role == TimingRole::setup()) { @@ -369,7 +370,8 @@ VisitPathEnds::visitOutputDelayEnd1(OutputDelay *output_delay, && (exception == nullptr || exception->isFilter() || exception->isGroupPath() - || exception->isMultiCycle())) { + || exception->isMultiCycle() + || exception->isPathMargin())) { MultiCyclePath *mcp = dynamic_cast(exception); PathEndOutputDelay path_end(output_delay, path, ref_path, mcp, this); visitor->visit(&path_end); @@ -442,7 +444,8 @@ VisitPathEnds::visitGatedClkEnd(const Pin *pin, && (exception == nullptr || exception->isFilter() || exception->isGroupPath() - || exception->isMultiCycle()) + || exception->isMultiCycle() + || exception->isPathMargin()) && (!filtered || search_->matchesFilter(path, clk_edge))) { MultiCyclePath *mcp = @@ -565,7 +568,8 @@ VisitPathEnds::visitDataCheckEnd1(DataCheck *check, && (exception == nullptr || exception->isFilter() || exception->isGroupPath() - || exception->isMultiCycle()) + || exception->isMultiCycle() + || exception->isPathMargin()) && (!filtered || search_->matchesFilter(path, tgt_clk_edge))) { MultiCyclePath *mcp=dynamic_cast(exception); diff --git a/test/regression_vars.tcl b/test/regression_vars.tcl index c475c348..79371c16 100644 --- a/test/regression_vars.tcl +++ b/test/regression_vars.tcl @@ -186,6 +186,7 @@ record_public_tests { report_json1 report_json2 sdc_strip_escaped_bus + set_path_margin slash_port_test suppress_msg vcd_timestamp diff --git a/test/set_path_margin.ok b/test/set_path_margin.ok new file mode 100644 index 00000000..14e88b1d --- /dev/null +++ b/test/set_path_margin.ok @@ -0,0 +1,425 @@ +Startpoint: r2 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r2/CK (DFF_X1) + 0.0772 0.0772 v r2/Q (DFF_X1) + 0.0233 0.1006 v u1/Z (BUF_X1) + 0.0273 0.1278 v u2/ZN (AND2_X1) + 0.0000 0.1278 v r3/D (DFF_X1) + 0.1278 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + -0.5000 9.5000 path margin + 0.0000 9.5000 clock reconvergence pessimism + 9.5000 ^ r3/CK (DFF_X1) + -0.0390 9.4610 library setup time + 9.4610 data required time +------------------------------------------------------------- + 9.4610 data required time + -0.1278 data arrival time +------------------------------------------------------------- + 9.3332 slack (MET) + + +setup_to_tighten -5.000e-10 +Startpoint: r1 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: min + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r1/CK (DFF_X1) + 0.0772 0.0772 v r1/Q (DFF_X1) + 0.0254 0.1026 v u2/ZN (AND2_X1) + 0.0000 0.1026 v r3/D (DFF_X1) + 0.1026 data arrival time + + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.5000 0.5000 path margin + 0.0000 0.5000 clock reconvergence pessimism + 0.5000 ^ r3/CK (DFF_X1) + 0.0016 0.5016 library hold time + 0.5016 data required time +------------------------------------------------------------- + 0.5016 data required time + -0.1026 data arrival time +------------------------------------------------------------- + -0.3990 slack (VIOLATED) + + +hold_to_tighten 5.000e-10 +Startpoint: r2 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r2/CK (DFF_X1) + 0.0772 0.0772 v r2/Q (DFF_X1) + 0.0233 0.1006 v u1/Z (BUF_X1) + 0.0273 0.1278 v u2/ZN (AND2_X1) + 0.0000 0.1278 v r3/D (DFF_X1) + 0.1278 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + 67.0000 77.0000 path margin + 0.0000 77.0000 clock reconvergence pessimism + 77.0000 ^ r3/CK (DFF_X1) + -0.0390 76.9610 library setup time + 76.9610 data required time +------------------------------------------------------------- + 76.9610 data required time + -0.1278 data arrival time +------------------------------------------------------------- + 76.8332 slack (MET) + + +setup_to_loosen 6.700e-08 +Startpoint: r1 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: min + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r1/CK (DFF_X1) + 0.0772 0.0772 v r1/Q (DFF_X1) + 0.0254 0.1026 v u2/ZN (AND2_X1) + 0.0000 0.1026 v r3/D (DFF_X1) + 0.1026 data arrival time + + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + -0.5000 -0.5000 path margin + 0.0000 -0.5000 clock reconvergence pessimism + -0.5000 ^ r3/CK (DFF_X1) + 0.0016 -0.4984 library hold time + -0.4984 data required time +------------------------------------------------------------- + -0.4984 data required time + -0.1026 data arrival time +------------------------------------------------------------- + 0.6010 slack (MET) + + +hold_to_loosen -5.000e-10 +Startpoint: r1 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r1/CK (DFF_X1) + 0.0836 0.0836 ^ r1/Q (DFF_X1) + 0.0277 0.1113 ^ u2/ZN (AND2_X1) + 0.0000 0.1113 ^ r3/D (DFF_X1) + 0.1113 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + -2.0000 8.0000 path margin + 0.0000 8.0000 clock reconvergence pessimism + 8.0000 ^ r3/CK (DFF_X1) + -0.0311 7.9689 library setup time + 7.9689 data required time +------------------------------------------------------------- + 7.9689 data required time + -0.1113 data arrival time +------------------------------------------------------------- + 7.8576 slack (MET) + + +setup_from_r1 -2.000e-09 +Startpoint: r2 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r2/CK (DFF_X1) + 0.0772 0.0772 v r2/Q (DFF_X1) + 0.0233 0.1006 v u1/Z (BUF_X1) + 0.0273 0.1278 v u2/ZN (AND2_X1) + 0.0000 0.1278 v r3/D (DFF_X1) + 0.1278 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + 67.0000 77.0000 path margin + 0.0000 77.0000 clock reconvergence pessimism + 77.0000 ^ r3/CK (DFF_X1) + -0.0390 76.9610 library setup time + 76.9610 data required time +------------------------------------------------------------- + 76.9610 data required time + -0.1278 data arrival time +------------------------------------------------------------- + 76.8332 slack (MET) + + +setup_from_r2 6.700e-08 +Startpoint: r1 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r1/CK (DFF_X1) + 0.0836 0.0836 ^ r1/Q (DFF_X1) + 0.0277 0.1113 ^ u2/ZN (AND2_X1) + 0.0000 0.1113 ^ r3/D (DFF_X1) + 0.1113 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + -5.0000 5.0000 path margin + 0.0000 5.0000 clock reconvergence pessimism + 5.0000 ^ r3/CK (DFF_X1) + -0.0311 4.9689 library setup time + 4.9689 data required time +------------------------------------------------------------- + 4.9689 data required time + -0.1113 data arrival time +------------------------------------------------------------- + 4.8576 slack (MET) + + +setup_from_to_r1 -5.000e-09 +Startpoint: r2 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r2/CK (DFF_X1) + 0.0772 0.0772 v r2/Q (DFF_X1) + 0.0233 0.1006 v u1/Z (BUF_X1) + 0.0273 0.1278 v u2/ZN (AND2_X1) + 0.0000 0.1278 v r3/D (DFF_X1) + 0.1278 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + 0.0000 10.0000 clock reconvergence pessimism + 10.0000 ^ r3/CK (DFF_X1) + -0.0390 9.9610 library setup time + 9.9610 data required time +------------------------------------------------------------- + 9.9610 data required time + -0.1278 data arrival time +------------------------------------------------------------- + 9.8332 slack (MET) + + +setup_from_to_r2 none +Startpoint: r1 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r1/CK (DFF_X1) + 0.0836 0.0836 ^ r1/Q (DFF_X1) + 0.0277 0.1113 ^ u2/ZN (AND2_X1) + 0.0000 0.1113 ^ r3/D (DFF_X1) + 0.1113 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + -2.0000 8.0000 path margin + 0.0000 8.0000 clock reconvergence pessimism + 8.0000 ^ r3/CK (DFF_X1) + -0.0311 7.9689 library setup time + 7.9689 data required time +------------------------------------------------------------- + 7.9689 data required time + -0.1113 data arrival time +------------------------------------------------------------- + 7.8576 slack (MET) + + +setup_through_r1 -2.000e-09 +Startpoint: r2 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r2/CK (DFF_X1) + 0.0772 0.0772 v r2/Q (DFF_X1) + 0.0233 0.1006 v u1/Z (BUF_X1) + 0.0273 0.1278 v u2/ZN (AND2_X1) + 0.0000 0.1278 v r3/D (DFF_X1) + 0.1278 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + -3.0000 7.0000 path margin + 0.0000 7.0000 clock reconvergence pessimism + 7.0000 ^ r3/CK (DFF_X1) + -0.0390 6.9610 library setup time + 6.9610 data required time +------------------------------------------------------------- + 6.9610 data required time + -0.1278 data arrival time +------------------------------------------------------------- + 6.8332 slack (MET) + + +setup_through_r2 -3.000e-09 +Startpoint: r1 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r1/CK (DFF_X1) + 0.0836 0.0836 ^ r1/Q (DFF_X1) + 0.0277 0.1113 ^ u2/ZN (AND2_X1) + 0.0000 0.1113 ^ r3/D (DFF_X1) + 0.1113 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + -4.0000 6.0000 path margin + 0.0000 6.0000 clock reconvergence pessimism + 6.0000 ^ r3/CK (DFF_X1) + -0.0311 5.9689 library setup time + 5.9689 data required time +------------------------------------------------------------- + 5.9689 data required time + -0.1113 data arrival time +------------------------------------------------------------- + 5.8576 slack (MET) + + +setup_from_clk_r1 -4.000e-09 +Startpoint: r2 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r2/CK (DFF_X1) + 0.0772 0.0772 v r2/Q (DFF_X1) + 0.0233 0.1006 v u1/Z (BUF_X1) + 0.0273 0.1278 v u2/ZN (AND2_X1) + 0.0000 0.1278 v r3/D (DFF_X1) + 0.1278 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + -4.0000 6.0000 path margin + 0.0000 6.0000 clock reconvergence pessimism + 6.0000 ^ r3/CK (DFF_X1) + -0.0390 5.9610 library setup time + 5.9610 data required time +------------------------------------------------------------- + 5.9610 data required time + -0.1278 data arrival time +------------------------------------------------------------- + 5.8332 slack (MET) + + +setup_from_clk_r2 -4.000e-09 +Startpoint: r1 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r1/CK (DFF_X1) + 0.0836 0.0836 ^ r1/Q (DFF_X1) + 0.0277 0.1113 ^ u2/ZN (AND2_X1) + 0.0000 0.1113 ^ r3/D (DFF_X1) + 0.1113 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + -6.0000 4.0000 path margin + 0.0000 4.0000 clock reconvergence pessimism + 4.0000 ^ r3/CK (DFF_X1) + -0.0311 3.9689 library setup time + 3.9689 data required time +------------------------------------------------------------- + 3.9689 data required time + -0.1113 data arrival time +------------------------------------------------------------- + 3.8576 slack (MET) + + +setup_combo_r1 -6.000e-09 +Startpoint: r2 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +------------------------------------------------------------- + 0.0000 0.0000 clock clk (rise edge) + 0.0000 0.0000 clock network delay (ideal) + 0.0000 0.0000 ^ r2/CK (DFF_X1) + 0.0772 0.0772 v r2/Q (DFF_X1) + 0.0233 0.1006 v u1/Z (BUF_X1) + 0.0273 0.1278 v u2/ZN (AND2_X1) + 0.0000 0.1278 v r3/D (DFF_X1) + 0.1278 data arrival time + + 10.0000 10.0000 clock clk (rise edge) + 0.0000 10.0000 clock network delay (ideal) + 0.0000 10.0000 clock reconvergence pessimism + 10.0000 ^ r3/CK (DFF_X1) + -0.0390 9.9610 library setup time + 9.9610 data required time +------------------------------------------------------------- + 9.9610 data required time + -0.1278 data arrival time +------------------------------------------------------------- + 9.8332 slack (MET) + + +setup_combo_r2 none diff --git a/test/set_path_margin.tcl b/test/set_path_margin.tcl new file mode 100644 index 00000000..e84378cf --- /dev/null +++ b/test/set_path_margin.tcl @@ -0,0 +1,90 @@ +# set_path_margin: per-path slack adjustment on the capture clock. + +read_liberty ../examples/nangate45_typ.lib.gz +read_verilog ../examples/example1.v +link_design top +create_clock -name clk -period 10 {clk1 clk2 clk3} +set_input_delay -clock clk 0 {in1 in2} + +proc setup_at { args } { + report_checks {*}$args -path_delay max -digits 4 -fields {} -group_path_count 1 +} +proc hold_at { args } { + report_checks {*}$args -path_delay min -digits 4 -fields {} -group_path_count 1 +} +proc report_json_path_margin { label path_delay args } { + set cmd [concat [list report_checks] $args \ + [list -path_delay $path_delay -format json -group_path_count 1]] + with_output_to_variable json $cmd + if { [regexp {"path_margin": ([^,\n]+)} $json match margin] } { + puts "$label $margin" + } else { + puts "$label none" + } +} + +# Test -to and that -setup and -hold are properly applied. +set_path_margin -setup 0.50 -comment {tighten setup time} -to [get_pins r3/D] +setup_at -to [get_pins r3/D] +report_json_path_margin setup_to_tighten max -to [get_pins r3/D] +set_path_margin -hold 0.50 -comment {tighten hold time} -to [get_pins r3/D] +hold_at -to [get_pins r3/D] +report_json_path_margin hold_to_tighten min -to [get_pins r3/D] +set_path_margin -setup -67 -comment {loosen setup time} -to [get_pins r3/D] +setup_at -to [get_pins r3/D] +report_json_path_margin setup_to_loosen max -to [get_pins r3/D] +set_path_margin -hold -0.50 -comment {loosen hold time} -to [get_pins r3/D] +hold_at -to [get_pins r3/D] +report_json_path_margin hold_to_loosen min -to [get_pins r3/D] + +# Test -from +reset_path -through [get_pins u1/Z] +set_path_margin -setup 2.0 -from [get_pins r1/CK] +# Should see path margin. +setup_at -from [get_pins r1/CK] -to [get_pins r3/D] +report_json_path_margin setup_from_r1 max -from [get_pins r1/CK] -to [get_pins r3/D] +# Should not see path margin. +setup_at -from [get_pins r2/CK] -to [get_pins r3/D] +report_json_path_margin setup_from_r2 max -from [get_pins r2/CK] -to [get_pins r3/D] + +# Test -from and -to. +reset_path -to [get_pins r3/D] +set_path_margin -setup 5.0 -from [get_pins r1/CK] -to [get_pins r3/D] +# Should see path margin. +setup_at -from [get_pins r1/CK] -to [get_pins r3/D] +report_json_path_margin setup_from_to_r1 max -from [get_pins r1/CK] -to [get_pins r3/D] +# Should not see path margin. +setup_at -from [get_pins r2/CK] -to [get_pins r3/D] +report_json_path_margin setup_from_to_r2 max -from [get_pins r2/CK] -to [get_pins r3/D] + +# Test -through. +reset_path -to [get_pins r3/D] +set_path_margin -setup 3.0 -through [get_pins u1/Z] +# Should not see path margin. +setup_at -from [get_pins r1/CK] -to [get_pins r3/D] +report_json_path_margin setup_through_r1 max -from [get_pins r1/CK] -to [get_pins r3/D] +# Should see path margin. +setup_at -from [get_pins r2/CK] -to [get_pins r3/D] +report_json_path_margin setup_through_r2 max -from [get_pins r2/CK] -to [get_pins r3/D] + +# Test a clock-scoped startpoint. +reset_path -from [get_pins r1/CK] +reset_path -through [get_pins u1/Z] +set_path_margin -setup 4.0 -from [get_clocks clk] +# Should see path margin on the clock. +setup_at -from [get_pins r1/CK] -to [get_pins r3/D] +report_json_path_margin setup_from_clk_r1 max -from [get_pins r1/CK] -to [get_pins r3/D] +setup_at -from [get_pins r2/CK] -to [get_pins r3/D] +report_json_path_margin setup_from_clk_r2 max -from [get_pins r2/CK] -to [get_pins r3/D] + +# Test -from, -through, and -to. +reset_path -from [get_clocks clk] +set_path_margin -setup 6.0 -from [get_pins r1/CK] \ + -through [get_pins u2/A1] \ + -to [get_pins r3/D] +# Should see path margin. +setup_at -from [get_pins r1/CK] -to [get_pins r3/D] +report_json_path_margin setup_combo_r1 max -from [get_pins r1/CK] -to [get_pins r3/D] +# Should not see path margin. +setup_at -from [get_pins r2/CK] -to [get_pins r3/D] +report_json_path_margin setup_combo_r2 max -from [get_pins r2/CK] -to [get_pins r3/D]