diff --git a/dcalc/PrimaDelayCalc.cc b/dcalc/PrimaDelayCalc.cc index 51f16237..a90ace47 100644 --- a/dcalc/PrimaDelayCalc.cc +++ b/dcalc/PrimaDelayCalc.cc @@ -446,6 +446,14 @@ PrimaDelayCalc::driverResistance() const Pin *drvr_pin = (*dcalc_args_)[0].drvrPin(); LibertyPort *drvr_port = network_->libertyPort(drvr_pin); LibertyPort *scene_port = drvr_port->scenePort(scene_, min_max_); + if (scene_port == nullptr) { + report_->warn(1754, "Port {}/{}/{} has no equivalent in scene {}.", + drvr_port->libertyLibrary()->name(), + drvr_port->libertyCell()->name(), + drvr_port->name(), + scene_->name()); + scene_port = drvr_port; + } return scene_port->driveResistance(drvr_rf_, min_max_); } diff --git a/doc/ChangeLog.txt b/doc/ChangeLog.txt index add039d0..4b803497 100644 --- a/doc/ChangeLog.txt +++ b/doc/ChangeLog.txt @@ -4,6 +4,20 @@ OpenSTA Timing Analyzer Release Notes This file summarizes user visible changes for each release. See ApiChangeLog.txt for changes to the STA api. +2026/08/02 +---------- + +The set_path_margin command applies a signed slack adjustment to the +capture-clock side of matching timing paths. A positive margin +tightens the path and a negative margin loosens it. + + set_path_margin [-setup] [-hold] [-rise] [-fall] + [-from from_list|-rise_from from_list|-fall_from from_list] + [-through through_list|-rise_through through_list|-fall_through through_list] + [-to to_list|-rise_to to_list|-fall_to to_list] + [-comment comment] + margin + 2026/07/20 ---------- diff --git a/doc/OpenSTA.fodt b/doc/OpenSTA.fodt index a569482f..4ea0eeba 100644 --- a/doc/OpenSTA.fodt +++ b/doc/OpenSTA.fodt @@ -11986,7 +11986,7 @@ - The set_max_dynamic_power command is ignored. + The set_max_dynamic_power command is ignored during timing but is included in SDC files that are written. @@ -12028,7 +12028,7 @@ - The set_max_leakage_power command is ignored. + The set_max_leakage_power command is ignored during timing but is included in SDC files that are written. @@ -12579,6 +12579,91 @@ The set_output_delay command is used to specify the external delay to a setup/hold check on an output port or internal pin that is clocked by clock. Unless the -add_delay option is specified any existing output delays are replaced. The –reference_pin option is used to specify a timing check with respect to the arrival on a pin in the clock network. For propagated clocks, the timing check is relative to the clock arrival time at the reference pin (the clock source latency and network latency from the clock source to the reference pin). For ideal clocks, the timing check is relative to the reference pin clock source latency. With the -clock_fall flag the timing check is relative to the falling edge of the reference pin. If no clocks arrive at the reference pin the set_output_delay command is ignored. If no -clock is specified the timing check is with respect to all clocks that arrive at the reference pin. The -source_latency_included and -network_latency_included options cannot be used with -reference_pin. + + + + + + set_path_margin + + + [-setup][-hold][-rise][-fall][-from from_list][-rise_from from_list][-fall_from from_list][-through through_list][-rise_through through_list][-fall_through through_list][-to to_list][-rise_to to_list][-fall_to to_list][-comment comment]margin + + + + + -setup + + + Apply the margin to setup checks. + + + + + -hold + + + Apply the margin to hold checks. + + + + + -rise + + + Apply the margin to rising path edges. + + + + + -fall + + + Apply the margin to falling path edges. + + + + + -from from_list + + + A list of clocks, instances, ports or pins. + + + + + -through through_list + + + A list of instances, pins or nets. + + + + + -to to_list + + + A list of clocks, instances, ports or pins. + + + + + -comment comment + + + Optional comment written by write_sdc. + + + + + margin + + + Signed slack adjustment applied on the capture clock. A positive margin tightens the path and a negative margin loosens it. + + + + The set_path_margin command applies a signed slack adjustment to matching timing paths on the capture-clock side. A positive margin makes the path harder to meet and a negative margin makes it easier. If neither -setup nor -hold is specified the margin applies to both. See set_false_path for a description of allowed from_list, through_list and to_list objects. At least one of -from, -through, or -to is required. Matching exceptions are removed with unset_path_exceptions. @@ -13724,7 +13809,7 @@ - The unset_path_exceptions command removes any matching set_false_path, set_multicycle_path, set_max_delay, and set_min_delay exceptions. + The unset_path_exceptions command removes any matching set_false_path, set_multicycle_path, set_max_delay, set_min_delay, and set_path_margin exceptions. @@ -14587,6 +14672,7 @@ set_multicycle_path67 set_operating_conditions68 set_output_delay69 + set_path_margin70 set_port_fanout_number70 set_power_activity70 set_propagated_clock71 diff --git a/doc/OpenSTA.pdf b/doc/OpenSTA.pdf index 971a4c0c..b261ba45 100644 Binary files a/doc/OpenSTA.pdf and b/doc/OpenSTA.pdf differ diff --git a/include/sta/ExceptionPath.hh b/include/sta/ExceptionPath.hh index c67270ae..67f5a2bd 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,35 @@ 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); + ExceptionPath *clone(ExceptionFrom *from, + ExceptionThruSeq *thrus, + ExceptionTo *to, + bool own_pts) override; + bool isPathMargin() const override { return true; } + ExceptionPathType type() const override + { return ExceptionPathType::path_margin; } + std::string_view typeString() const override; + bool mergeable(ExceptionPath *exception) const override; + bool overrides(ExceptionPath *exception) const override; + float margin() const override { return margin_; } + int typePriority() const override; + bool tighterThan(ExceptionPath *exception) const override; + +protected: + float margin_; +}; + // set_multicycle_path class MultiCyclePath : public ExceptionPath { diff --git a/include/sta/PathEnd.hh b/include/sta/PathEnd.hh index be54fa73..a496af76 100644 --- a/include/sta/PathEnd.hh +++ b/include/sta/PathEnd.hh @@ -135,6 +135,10 @@ 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 (set_path_margin). + virtual float targetClkPathMargin(const StaState *sta) const; + virtual bool hasPathMargin() const { return false; } + virtual PathMargin *pathMargin() const { return nullptr; } virtual const TimingRole *checkRole(const StaState *sta) const; const TimingRole *checkGenericRole(const StaState *sta) const; virtual bool pathDelayMarginIsExternal() const; @@ -260,6 +264,9 @@ 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; + bool hasPathMargin() const override { return path_margin_ != nullptr; } + PathMargin *pathMargin() const override { return path_margin_; } Crpr crpr(const StaState *sta) const override; Required requiredTime(const StaState *sta) const override; Slack slack(const StaState *sta) const override; @@ -270,7 +277,8 @@ public: protected: PathEndClkConstrained(Path *path, - Path *clk_path); + Path *clk_path, + PathMargin *path_margin); float sourceClkOffset(const ClockEdge *src_clk_edge, const ClockEdge *tgt_clk_edge, const TimingRole *check_role, @@ -280,6 +288,7 @@ protected: virtual Required requiredTimeNoCrpr(const StaState *sta) const; Path *clk_path_; + PathMargin *path_margin_; mutable Crpr crpr_; mutable bool crpr_valid_{false}; }; @@ -295,7 +304,8 @@ public: protected: PathEndClkConstrainedMcp(Path *path, Path *clk_path, - MultiCyclePath *mcp); + MultiCyclePath *mcp, + PathMargin *path_margin); float checkMcpAdjustment(const Path *path, const ClockEdge *tgt_clk_edge, const StaState *sta) const; @@ -316,6 +326,7 @@ public: Edge *check_edge, Path *clk_path, MultiCyclePath *mcp, + PathMargin *path_margin, const StaState *sta); PathEnd *copy() const override; Type type() const override; @@ -348,6 +359,7 @@ public: Edge *check_edge, Path *disable_path, MultiCyclePath *mcp, + PathMargin *path_margin, PathDelay *path_delay, const StaState *sta); Type type() const override; @@ -404,6 +416,7 @@ public: Path *path, Path *clk_path, MultiCyclePath *mcp, + PathMargin *path_margin, const StaState *sta); PathEnd *copy() const override; Type type() const override; @@ -443,6 +456,7 @@ public: Path *clk_path, const TimingRole *check_role, MultiCyclePath *mcp, + PathMargin *path_margin, ArcDelay margin, const StaState *sta); PathEnd *copy() const override; @@ -468,6 +482,7 @@ public: Path *data_path, Path *data_clk_path, MultiCyclePath *mcp, + PathMargin *path_margin, const StaState *sta); PathEnd *copy() const override; Type type() const override; diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index e585e440..3f043ae7 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -377,6 +377,10 @@ public: float fanout); void setMaxArea(float area); float maxArea() const; + void setMaxDynamicPower(float power); + float maxDynamicPower() const; + void setMaxLeakagePower(float power); + float maxLeakagePower() const; Clock *makeClock(std::string_view name, const PinSet &pins, bool add_to_pins, @@ -753,6 +757,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). @@ -1424,6 +1434,8 @@ protected: InstMinPulseWidthMap inst_min_pulse_width_map_; ClockMinPulseWidthMap clk_min_pulse_width_map_; float max_area_; + float max_dynamic_power_; + float max_leakage_power_; Wireload *wireload_[MinMax::index_count]; WireloadMode wireload_mode_; const WireloadSelection *wireload_selection_[MinMax::index_count]; diff --git a/include/sta/SdcClass.hh b/include/sta/SdcClass.hh index 62c24efe..b1fe7360 100644 --- a/include/sta/SdcClass.hh +++ b/include/sta/SdcClass.hh @@ -44,6 +44,7 @@ class InputDelay; class OutputDelay; class FalsePath; class PathDelay; +class PathMargin; class MultiCyclePath; class FilterPath; class GroupPath; @@ -69,6 +70,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 274fac6b..e6198008 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -346,6 +346,13 @@ public: Sdc *sdc); void setMaxArea(float area, Sdc *sdc); + float maxArea(const Sdc *sdc) const; + void setMaxDynamicPower(float power, + Sdc *sdc); + float maxDynamicPower(const Sdc *sdc) const; + void setMaxLeakagePower(float power, + Sdc *sdc); + float maxLeakagePower(const Sdc *sdc) const; void makeClock(std::string_view name, const PinSet &pins, @@ -647,6 +654,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/include/sta/VisitPathEnds.hh b/include/sta/VisitPathEnds.hh index 8ac723f5..93081cbb 100644 --- a/include/sta/VisitPathEnds.hh +++ b/include/sta/VisitPathEnds.hh @@ -131,6 +131,11 @@ protected: const Pin *pin, const RiseFall *rf, const MinMax *min_max); + PathMargin *pathMarginTo(const Path *path, + const Pin *pin, + const RiseFall *rf, + const ClockEdge *clk_edge, + const MinMax *min_max) const; ExceptionPath *exceptionTo(const Path *path, const Pin *pin, const RiseFall *rf, diff --git a/network/NetworkEdit.tcl b/network/NetworkEdit.tcl index d135db40..cfddb753 100644 --- a/network/NetworkEdit.tcl +++ b/network/NetworkEdit.tcl @@ -108,7 +108,7 @@ proc parse_connect_pin { arg } { set port [$pin port] } elseif { $object_type == "Port" } { # Explicit port arg - convert to pin. - set pin [find_pin [get_name $arg]] + set pin [get_port_pin $arg] set inst [$pin instance] set port [$pin port] } else { 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 9b30c470..f538cb50 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -244,6 +244,8 @@ Sdc::initVariables() analysis_type_ = AnalysisType::ocv; wireload_mode_ = WireloadMode::unknown; max_area_ = 0.0; + max_dynamic_power_ = 0.0; + max_leakage_power_ = 0.0; path_delays_without_to_ = false; clk_hpin_disables_valid_ = false; have_clk_slew_limits_ = false; @@ -951,6 +953,30 @@ Sdc::maxArea() const return max_area_; } +void +Sdc::setMaxDynamicPower(float power) +{ + max_dynamic_power_ = power; +} + +float +Sdc::maxDynamicPower() const +{ + return max_dynamic_power_; +} + +void +Sdc::setMaxLeakagePower(float power) +{ + max_leakage_power_ = power; +} + +float +Sdc::maxLeakagePower() const +{ + return max_leakage_power_; +} + //////////////////////////////////////////////////////////////// Clock * @@ -3932,6 +3958,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) { @@ -4339,7 +4379,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 3ac13d81..d08c6e9f 100644 --- a/sdc/Sdc.i +++ b/sdc/Sdc.i @@ -838,6 +838,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, @@ -1229,6 +1242,43 @@ set_max_area_cmd(float area) sta->setMaxArea(area, sdc); } +float +max_area() +{ + Sta *sta = Sta::sta(); + return sta->maxArea(sta->cmdSdc()); +} + +void +set_max_dynamic_power_cmd(float power) +{ + Sta *sta = Sta::sta(); + Sdc *sdc = sta->cmdSdc(); + sta->setMaxDynamicPower(power, sdc); +} + +float +max_dynamic_power() +{ + Sta *sta = Sta::sta(); + return sta->maxDynamicPower(sta->cmdSdc()); +} + +void +set_max_leakage_power_cmd(float power) +{ + Sta *sta = Sta::sta(); + Sdc *sdc = sta->cmdSdc(); + sta->setMaxLeakagePower(power, sdc); +} + +float +max_leakage_power() +{ + Sta *sta = Sta::sta(); + return sta->maxLeakagePower(sta->cmdSdc()); +} + void set_port_fanout_limit(Port *port, const MinMax *min_max, diff --git a/sdc/Sdc.tcl b/sdc/Sdc.tcl index e444eea8..64fdbfc3 100644 --- a/sdc/Sdc.tcl +++ b/sdc/Sdc.tcl @@ -2430,6 +2430,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 } { @@ -3599,7 +3654,9 @@ proc set_level_shifter_threshold { args } { define_cmd_args "set_max_dynamic_power" {power [unit]} proc set_max_dynamic_power { power {unit {}} } { - # ignored + check_positive_float "power" $power + # Optional SDC unit argument is accepted but ignored; use set_units. + set_max_dynamic_power_cmd $power } ################################################################ @@ -3607,7 +3664,9 @@ proc set_max_dynamic_power { power {unit {}} } { define_cmd_args "set_max_leakage_power" {power [unit]} proc set_max_leakage_power { power {unit {}} } { - # ignored + check_positive_float "power" $power + # Optional SDC unit argument is accepted but ignored; use set_units. + set_max_leakage_power_cmd $power } ################################################################ diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index 1733a050..f979d9eb 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -1231,6 +1231,10 @@ WriteSdc::writeExceptionCmd(ExceptionPath *exception) const if (exception->ignoreClkLatency()) sta::print(stream_, " -ignore_clock_latency"); } + else if (exception->isPathMargin()) { + sta::print(stream_, "set_path_margin"); + writeSetupHoldFlag(exception->minMax()); + } else if (exception->isGroupPath()) { if (exception->isDefault()) sta::print(stream_, "group_path -default"); @@ -1251,6 +1255,10 @@ WriteSdc::writeExceptionValue(ExceptionPath *exception) const sta::print(stream_, " "); writeTime(exception->delay()); } + else if (exception->isPathMargin()) { + sta::print(stream_, " "); + writeTime(exception->margin()); + } } void @@ -2031,6 +2039,8 @@ WriteSdc::writeDesignRules() const writeCapLimits(); writeFanoutLimits(); writeMaxArea(); + writeMaxDynamicPower(); + writeMaxLeakagePower(); } void @@ -2262,6 +2272,28 @@ WriteSdc::writeMaxArea() const } } +void +WriteSdc::writeMaxDynamicPower() const +{ + float max_power = sdc_->maxDynamicPower(); + if (max_power > 0.0) { + sta::print(stream_, "set_max_dynamic_power "); + writeFloat(max_power); + sta::print(stream_, "\n"); + } +} + +void +WriteSdc::writeMaxLeakagePower() const +{ + float max_power = sdc_->maxLeakagePower(); + if (max_power > 0.0) { + sta::print(stream_, "set_max_leakage_power "); + writeFloat(max_power); + sta::print(stream_, "\n"); + } +} + void WriteSdc::writeFanoutLimits() const { diff --git a/sdc/WriteSdcPvt.hh b/sdc/WriteSdcPvt.hh index b7bc9338..1d0b0f08 100644 --- a/sdc/WriteSdcPvt.hh +++ b/sdc/WriteSdcPvt.hh @@ -169,6 +169,8 @@ public: void writeCapLimits(const MinMax *min_max, std::string_view cmd) const; void writeMaxArea() const; + void writeMaxDynamicPower() const; + void writeMaxLeakagePower() const; void writeFanoutLimits() const; void writeFanoutLimits(const MinMax *min_max, std::string_view cmd) const; diff --git a/search/PathEnd.cc b/search/PathEnd.cc index e917d89f..b4d6c036 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 { @@ -511,9 +517,11 @@ PathEndUnconstrained::typeName() const //////////////////////////////////////////////////////////////// PathEndClkConstrained::PathEndClkConstrained(Path *path, - Path *clk_path) : + Path *clk_path, + PathMargin *path_margin) : PathEnd(path), clk_path_(clk_path), + path_margin_(path_margin), crpr_(0.0) { } @@ -630,8 +638,9 @@ 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 +701,17 @@ PathEndClkConstrained::targetClkUncertainty(const StaState *sta) const targetClkPath(), checkRole(sta), sdc); } +float +PathEndClkConstrained::targetClkPathMargin(const StaState *sta) const +{ + if (!path_margin_) + return 0.0; + float margin = path_margin_->margin(); + if (checkRole(sta)->genericRole() == TimingRole::setup()) + margin = -margin; + return margin; +} + Crpr PathEndClkConstrained::crpr(const StaState *sta) const { @@ -752,8 +772,9 @@ PathEndClkConstrained::exceptPathCmp(const PathEnd *path_end, PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path, Path *clk_path, - MultiCyclePath *mcp) : - PathEndClkConstrained(path, clk_path), + MultiCyclePath *mcp, + PathMargin *path_margin) : + PathEndClkConstrained(path, clk_path, path_margin), mcp_(mcp) { } @@ -921,8 +942,9 @@ PathEndCheck::PathEndCheck(Path *path, Edge *check_edge, Path *clk_path, MultiCyclePath *mcp, + PathMargin *path_margin, const StaState *) : - PathEndClkConstrainedMcp(path, clk_path, mcp), + PathEndClkConstrainedMcp(path, clk_path, mcp, path_margin), check_arc_(check_arc), check_edge_(check_edge) { @@ -1082,9 +1104,10 @@ PathEndLatchCheck::PathEndLatchCheck(Path *path, Edge *check_edge, Path *disable_path, MultiCyclePath *mcp, + PathMargin *path_margin, PathDelay *path_delay, const StaState *sta) : - PathEndCheck(path, check_arc, check_edge, nullptr, mcp, sta), + PathEndCheck(path, check_arc, check_edge, nullptr, mcp, path_margin, sta), disable_path_(disable_path), path_delay_(path_delay), src_clk_arrival_(0.0) @@ -1300,9 +1323,10 @@ PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay, Path *path, Path *clk_path, MultiCyclePath *mcp, + PathMargin *path_margin, const StaState *) : // No target clk_path_ for output delays. - PathEndClkConstrainedMcp(path, clk_path, mcp), + PathEndClkConstrainedMcp(path, clk_path, mcp, path_margin), output_delay_(output_delay) { } @@ -1494,9 +1518,10 @@ PathEndGatedClock::PathEndGatedClock(Path *gating_ref, Path *clk_path, const TimingRole *check_role, MultiCyclePath *mcp, + PathMargin *path_margin, ArcDelay margin, const StaState *) : - PathEndClkConstrainedMcp(gating_ref, clk_path, mcp), + PathEndClkConstrainedMcp(gating_ref, clk_path, mcp, path_margin), check_role_(check_role), margin_(margin) { @@ -1564,8 +1589,9 @@ PathEndDataCheck::PathEndDataCheck(DataCheck *check, Path *data_path, Path *data_clk_path, MultiCyclePath *mcp, + PathMargin *path_margin, const StaState *sta) : - PathEndClkConstrainedMcp(data_path, nullptr, mcp), + PathEndClkConstrainedMcp(data_path, nullptr, mcp, path_margin), data_clk_path_(data_clk_path), check_(check) { @@ -1711,7 +1737,7 @@ PathEndDataCheck::exceptPathCmp(const PathEnd *path_end, PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay, Path *path, const StaState *sta): - PathEndClkConstrained(path, nullptr), + PathEndClkConstrained(path, nullptr, nullptr), path_delay_(path_delay), check_arc_(nullptr), check_edge_(nullptr), @@ -1724,7 +1750,7 @@ PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay, Path *path, OutputDelay *output_delay, const StaState *sta): - PathEndClkConstrained(path, nullptr), + PathEndClkConstrained(path, nullptr, nullptr), path_delay_(path_delay), check_arc_(nullptr), check_edge_(nullptr), @@ -1739,7 +1765,7 @@ PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay, TimingArc *check_arc, Edge *check_edge, const StaState *sta) : - PathEndClkConstrained(path, clk_path), + PathEndClkConstrained(path, clk_path, nullptr), path_delay_(path_delay), check_arc_(check_arc), check_edge_(check_edge), diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 1bfcdfc6..12e3b2af 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -1134,6 +1134,9 @@ ReportPath::reportJson(const PathEnd *end, delayAsFloat(end->checkCrpr(this))); result += sta::format(" \"margin\": {:.3e},\n", delayAsFloat(end->margin(this))); + if (end->hasPathMargin()) + result += sta::format(" \"path_margin\": {:.3e},\n", + end->targetClkPathMargin(this)); result += sta::format(" \"required_time\": {:.3e},\n", delayAsFloat(end->requiredTimeOffset(this))); result += sta::format(" \"slack\": {:.3e}\n", @@ -2569,6 +2572,11 @@ ReportPath::reportClkUncertainty(const PathEnd *end, if (inter_uncertainty != 0.0) reportLine("inter-clock uncertainty", inter_uncertainty, clk_arrival, early_late); + if (end->hasPathMargin()) { + float margin = end->targetClkPathMargin(this); + clk_arrival = delaySum(clk_arrival, margin, this); + reportLine("path margin", margin, clk_arrival, early_late); + } } //////////////////////////////////////////////////////////////// diff --git a/search/Sta.cc b/search/Sta.cc index 1a207f75..ec8d7a8c 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -1149,6 +1149,38 @@ Sta::setMaxArea(float area, sdc->setMaxArea(area); } +float +Sta::maxArea(const Sdc *sdc) const +{ + return sdc->maxArea(); +} + +void +Sta::setMaxDynamicPower(float power, + Sdc *sdc) +{ + sdc->setMaxDynamicPower(power); +} + +float +Sta::maxDynamicPower(const Sdc *sdc) const +{ + return sdc->maxDynamicPower(); +} + +void +Sta::setMaxLeakagePower(float power, + Sdc *sdc) +{ + sdc->setMaxLeakagePower(power); +} + +float +Sta::maxLeakagePower(const Sdc *sdc) const +{ + return sdc->maxLeakagePower(); +} + void Sta::makeClock(std::string_view name, const PinSet &pins, @@ -1730,8 +1762,9 @@ Sta::isDisabledConstraint(Edge *edge, { Pin *from_pin = edge->from(graph_)->pin(); Pin *to_pin = edge->to(graph_)->pin(); - return sdc->isDisabledConstraint(from_pin) || sdc->isDisabledConstraint(to_pin) - || sdc->isDisabledConstraint(edge); + return sdc->isDisabledConstraint(from_pin) + || sdc->isDisabledConstraint(to_pin) + || sdc->isDisabledConstraint(edge); } bool @@ -2038,6 +2071,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..98b05d1c 100644 --- a/search/VisitPathEnds.cc +++ b/search/VisitPathEnds.cc @@ -185,19 +185,22 @@ VisitPathEnds::visitCheckEnd(const Pin *pin, && (exception == nullptr || exception->isFilter() || exception->isGroupPath() - || exception->isMultiCycle())) { + || exception->isMultiCycle() + || exception->isPathMargin())) { MultiCyclePath *mcp=dynamic_cast(exception); + PathMargin *path_margin = pathMarginTo(path, pin, end_rf, + tgt_clk_edge, min_max); if (network_->isLatchData(pin) && check_role == TimingRole::setup()) { PathEndLatchCheck path_end(path, check_arc, edge, - tgt_clk_path, mcp, nullptr, - this); + tgt_clk_path, mcp, path_margin, + nullptr, this); visitor->visit(&path_end); is_constrained = true; } else { PathEndCheck path_end(path, check_arc, edge, - tgt_clk_path, mcp, this); + tgt_clk_path, mcp, path_margin, this); visitor->visit(&path_end); is_constrained = true; } @@ -210,7 +213,7 @@ VisitPathEnds::visitCheckEnd(const Pin *pin, if (network_->isLatchData(pin) && check_role == TimingRole::setup()) { PathEndLatchCheck path_end(path, check_arc, edge, - tgt_clk_path, nullptr, + tgt_clk_path, nullptr, nullptr, path_delay, this); visitor->visit(&path_end); } @@ -369,9 +372,13 @@ 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); + PathMargin *path_margin = pathMarginTo(path, pin, end_rf, + tgt_clk_edge, min_max); + PathEndOutputDelay path_end(output_delay, path, ref_path, mcp, + path_margin, this); visitor->visit(&path_end); is_constrained = true; } @@ -442,13 +449,16 @@ 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 = dynamic_cast(exception); + PathMargin *path_margin = pathMarginTo(path, pin, end_rf, + clk_edge, min_max); PathEndGatedClock path_end(path, clk_path, check_role, - mcp, margin, this); + mcp, path_margin, margin, this); visitor->visit(&path_end); is_constrained = true; } @@ -565,11 +575,15 @@ 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); - PathEndDataCheck path_end(check, path, tgt_clk_path, mcp, this); + PathMargin *path_margin = pathMarginTo(path, pin, end_rf, + tgt_clk_edge, min_max); + PathEndDataCheck path_end(check, path, tgt_clk_path, mcp, + path_margin, this); visitor->visit(&path_end); is_constrained = true; } @@ -639,6 +653,19 @@ VisitPathEnds::pathDelayTo(Path *path, return dynamic_cast(exception); } +PathMargin * +VisitPathEnds::pathMarginTo(const Path *path, + const Pin *pin, + const RiseFall *rf, + const ClockEdge *clk_edge, + const MinMax *min_max) const +{ + ExceptionPath *exception = + search_->exceptionTo(ExceptionPathType::path_margin, path, pin, rf, + clk_edge, min_max, false, false, path->sdc(this)); + return dynamic_cast(exception); +} + ExceptionPath * VisitPathEnds::exceptionTo(const Path *path, const Pin *pin, diff --git a/tcl/CmdArgs.tcl b/tcl/CmdArgs.tcl index 71232ef1..525a48c7 100644 --- a/tcl/CmdArgs.tcl +++ b/tcl/CmdArgs.tcl @@ -226,7 +226,7 @@ proc parse_clk_inst_port_pin_arg { objects clks_var insts_var pins_var } { set ports {} get_object_args $objects clks {} {} {} insts ports pins {} {} {} foreach port $ports { - lappend pins [[top_instance] find_pin [get_name $port]] + lappend pins [get_port_pin $port] } } @@ -238,7 +238,7 @@ proc parse_clk_port_pin_arg { objects clks_var pins_var } { set ports {} get_object_args $objects clks {} {} {} {} ports pins {} {} {} foreach port $ports { - lappend pins [[top_instance] find_pin [get_name $port]] + lappend pins [get_port_pin $port] } } @@ -325,7 +325,7 @@ proc parse_inst_port_pin_arg { objects insts_var pins_var } { set ports {} get_object_args $objects {} {} {} {} insts ports pins {} {} {} foreach port $ports { - lappend pins [[top_instance] find_pin [get_name $port]] + lappend pins [get_port_pin $port] } } @@ -347,7 +347,7 @@ proc parse_inst_port_pin_net_arg { objects insts_var pins_var nets_var } { set nets {} get_object_args $objects {} {} {} {} insts ports pins nets {} {} foreach port $ports { - lappend pins [[top_instance] find_pin [get_name $port]] + lappend pins [get_port_pin $port] } } @@ -368,7 +368,7 @@ proc parse_port_pin_net_arg { objects pins_var nets_var } { get_object_args $objects {} {} {} {} {} ports pins nets {} {} foreach port $ports { - lappend pins [[top_instance] find_pin [get_name $port]] + lappend pins [get_port_pin $port] } } @@ -857,7 +857,7 @@ proc get_port_pin_arg { arg_name arg warn_error } { set pin $arg } elseif { $object_type == "Port" } { # Explicit port arg - convert to pin. - set pin [find_pin [get_name $arg]] + set pin [get_port_pin $arg] } else { sta_warn_error 129 $warn_error "$arg_name type '$object_type' is not a pin or port." } @@ -868,7 +868,7 @@ proc get_port_pin_arg { arg_name arg warn_error } { if { $port == "NULL" } { set pin [find_pin $arg] } else { - set pin [$top_instance find_pin [get_name $port]] + set pin [get_port_pin $port] } if { $pin == "NULL" } { sta_warn_error 130 $warn_error "pin $arg not found." @@ -880,7 +880,7 @@ proc get_port_pin_arg { arg_name arg warn_error } { proc get_port_pins_error { arg_name arglist } { set pins {} # Copy backslashes that will be removed by foreach. - set arglilst [string map {\\ \\\\} $arglist] + set arglist [string map {\\ \\\\} $arglist] foreach arg $arglist { if {[llength $arg] > 1} { # Embedded list. @@ -891,7 +891,7 @@ proc get_port_pins_error { arg_name arglist } { lappend pins $arg } elseif { $object_type == "Port" } { # Convert port to pin. - lappend pins [find_pin [get_name $arg]] + lappend pins [get_port_pin $arg] } else { sta_error 131 "$arg_name type '$object_type' is not a pin or port." } diff --git a/test/max_power_area.ok b/test/max_power_area.ok new file mode 100644 index 00000000..6848c1f8 --- /dev/null +++ b/test/max_power_area.ok @@ -0,0 +1,6 @@ +max_area 123.5 +max_dynamic_power 1.25 +max_leakage_power 0.75 +set_max_area 123.5000 +set_max_dynamic_power 1.2500 +set_max_leakage_power 0.7500 diff --git a/test/max_power_area.tcl b/test/max_power_area.tcl new file mode 100644 index 00000000..017da8df --- /dev/null +++ b/test/max_power_area.tcl @@ -0,0 +1,25 @@ +# Store/retrieve/write max area and power SDC constraints. +source helpers.tcl +read_liberty asap7_small.lib.gz +read_verilog reg1_asap7.v +link_design top + +set_max_area 123.5 +set_max_dynamic_power 1.25 +set_max_leakage_power 0.75 + +puts "max_area [sta::max_area]" +puts "max_dynamic_power [sta::max_dynamic_power]" +puts "max_leakage_power [sta::max_leakage_power]" + +set sdc_file [make_result_file max_power_area.sdc] +write_sdc -no_timestamp $sdc_file +set stream [open $sdc_file r] +gets $stream line +while { ![eof $stream] } { + if {[string match "set_max_*" $line]} { + puts $line + } + gets $stream line +} +close $stream diff --git a/test/regression_vars.tcl b/test/regression_vars.tcl index e9976ce6..ec03cdc3 100644 --- a/test/regression_vars.tcl +++ b/test/regression_vars.tcl @@ -157,6 +157,7 @@ record_public_tests { liberty_float_as_str liberty_latch3 make_concrete_parasitics_leak + max_power_area package_require path_group_names power_json @@ -167,6 +168,13 @@ record_public_tests { report_checks_src_attr report_json1 report_json2 + set_path_margin1 + set_path_margin2 + set_path_margin3 + set_path_margin4 + set_path_margin5 + set_path_margin6 + slash_port_test suppress_msg user_properties vcd_begin_end_time diff --git a/test/set_path_margin1.ok b/test/set_path_margin1.ok new file mode 100644 index 00000000..c0967df7 --- /dev/null +++ b/test/set_path_margin1.ok @@ -0,0 +1,122 @@ +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 diff --git a/test/set_path_margin1.tcl b/test/set_path_margin1.tcl new file mode 100644 index 00000000..41793261 --- /dev/null +++ b/test/set_path_margin1.tcl @@ -0,0 +1,37 @@ +# set_path_margin -to with -setup/-hold + +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" + } +} + +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] diff --git a/test/set_path_margin2.ok b/test/set_path_margin2.ok new file mode 100644 index 00000000..2c1eaf37 --- /dev/null +++ b/test/set_path_margin2.ok @@ -0,0 +1,60 @@ +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) + 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_r2 none diff --git a/test/set_path_margin2.tcl b/test/set_path_margin2.tcl new file mode 100644 index 00000000..ebc1de59 --- /dev/null +++ b/test/set_path_margin2.tcl @@ -0,0 +1,29 @@ +# set_path_margin -from + +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 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" + } +} + +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] diff --git a/test/set_path_margin3.ok b/test/set_path_margin3.ok new file mode 100644 index 00000000..f18e9b7a --- /dev/null +++ b/test/set_path_margin3.ok @@ -0,0 +1,60 @@ +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 diff --git a/test/set_path_margin3.tcl b/test/set_path_margin3.tcl new file mode 100644 index 00000000..ad4cc813 --- /dev/null +++ b/test/set_path_margin3.tcl @@ -0,0 +1,29 @@ +# set_path_margin -from and -to + +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 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" + } +} + +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] diff --git a/test/set_path_margin4.ok b/test/set_path_margin4.ok new file mode 100644 index 00000000..d24d46cd --- /dev/null +++ b/test/set_path_margin4.ok @@ -0,0 +1,60 @@ +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) + 0.0000 10.0000 clock reconvergence pessimism + 10.0000 ^ r3/CK (DFF_X1) + -0.0311 9.9689 library setup time + 9.9689 data required time +------------------------------------------------------------- + 9.9689 data required time + -0.1113 data arrival time +------------------------------------------------------------- + 9.8576 slack (MET) + + +setup_through_r1 none +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 diff --git a/test/set_path_margin4.tcl b/test/set_path_margin4.tcl new file mode 100644 index 00000000..bf1f2e2e --- /dev/null +++ b/test/set_path_margin4.tcl @@ -0,0 +1,29 @@ +# set_path_margin -through + +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 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" + } +} + +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] diff --git a/test/set_path_margin5.ok b/test/set_path_margin5.ok new file mode 100644 index 00000000..0c83dfdd --- /dev/null +++ b/test/set_path_margin5.ok @@ -0,0 +1,61 @@ +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 diff --git a/test/set_path_margin5.tcl b/test/set_path_margin5.tcl new file mode 100644 index 00000000..797ffa8e --- /dev/null +++ b/test/set_path_margin5.tcl @@ -0,0 +1,28 @@ +# set_path_margin -from 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 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" + } +} + +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] diff --git a/test/set_path_margin6.ok b/test/set_path_margin6.ok new file mode 100644 index 00000000..3f3ce897 --- /dev/null +++ b/test/set_path_margin6.ok @@ -0,0 +1,60 @@ +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_margin6.tcl b/test/set_path_margin6.tcl new file mode 100644 index 00000000..dcd33e67 --- /dev/null +++ b/test/set_path_margin6.tcl @@ -0,0 +1,31 @@ +# set_path_margin -from/-through/-to + +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 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" + } +} + +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] diff --git a/test/slash_port_test.ok b/test/slash_port_test.ok new file mode 100644 index 00000000..003de6d2 --- /dev/null +++ b/test/slash_port_test.ok @@ -0,0 +1,51 @@ +get_ports * +a/b +level1/Y +level1/level2/level3 +out +all_inputs +a/b +level1/Y +level1/level2/level3 +all_outputs +out +get_pins * +a/A +a/Y +level1/A +level1/Y +u3/A +u3/B +u3/Y +u4/A +u4/Y +get_cells * +a +level1 +u3 +u4 +get_nets * +a/b +and_out +buf_out +buf_out2 +level1/Y +level1/level2/level3 +out +get_ports * -filter direction==input +a/b +level1/Y +level1/level2/level3 +get_ports * -filter direction==output +out +set_input_delay -clock clk 0 [all_inputs] +set_input_delay -clock clk 0 +set_input_delay -clock clk 0 +set_input_delay -clock clk 0 +set_false_path -from [all_inputs] -to [all_outputs] +set_data_check -from -to 0 +set_case_analysis 0 +set_case_analysis 0 +set_case_analysis 0 +report_checks +No paths found. diff --git a/test/slash_port_test.tcl b/test/slash_port_test.tcl new file mode 100644 index 00000000..e51ad82d --- /dev/null +++ b/test/slash_port_test.tcl @@ -0,0 +1,62 @@ +# Test: ports with escaped names containing slashes +# Exercises Port-to-Pin conversion paths with escaped Verilog identifiers +# like \level1/level2/level3 that contain hierarchy separators +read_liberty asap7_small.lib.gz +read_verilog slash_port_test.v +link_design slash_port_test + +create_clock -name clk -period 500 [get_ports out] + +puts {get_ports *} +report_object_full_names [get_ports *] + +puts {all_inputs} +report_object_full_names [all_inputs] + +puts {all_outputs} +report_object_full_names [all_outputs] + +puts {get_pins *} +report_object_full_names [get_pins *] + +puts {get_cells *} +report_object_full_names [get_cells *] + +puts {get_nets *} +report_object_full_names [get_nets *] + +puts {get_ports * -filter direction==input} +report_object_full_names [get_ports * -filter {direction == input}] + +puts {get_ports * -filter direction==output} +report_object_full_names [get_ports * -filter {direction == output}] + +# get_port_pins_error: Port objects via set_input_delay [all_inputs] +puts {set_input_delay -clock clk 0 [all_inputs]} +set_input_delay -clock clk 0 [all_inputs] + +# get_port_pins_error: individual Port objects +foreach port [all_inputs] { + puts "set_input_delay -clock clk 0 " + set_input_delay -clock clk 0 $port +} + +# parse_clk_inst_port_pin_arg: Port objects via set_false_path +puts {set_false_path -from [all_inputs] -to [all_outputs]} +set_false_path -from [all_inputs] -to [all_outputs] + +# get_port_pin_error (singular): set_data_check with Port objects +set input_ports [all_inputs] +set from_port [lindex $input_ports 0] +set to_port [lindex $input_ports 1] +puts "set_data_check -from -to 0" +set_data_check -from $from_port -to $to_port 0 + +# get_port_pin_error (singular): set_case_analysis with Port objects +foreach port [all_inputs] { + puts "set_case_analysis 0 " + set_case_analysis 0 $port +} + +puts {report_checks} +report_checks diff --git a/test/slash_port_test.v b/test/slash_port_test.v new file mode 100644 index 00000000..293f5e58 --- /dev/null +++ b/test/slash_port_test.v @@ -0,0 +1,20 @@ +module slash_port_test ( + \level1/level2/level3 , + \a/b , + \level1/Y , + out +); + input \level1/level2/level3 ; + input \a/b ; + input \level1/Y ; + output out; + + wire buf_out, buf_out2, and_out; + + // Instance named "level1" — collides with the prefix of port \level1/level2/level3 + BUFx2_ASAP7_75t_R level1 (.A(\level1/level2/level3 ), .Y(buf_out)); + // Instance named "a" — collides with the prefix of port \a/b + BUFx2_ASAP7_75t_R a (.A(\a/b ), .Y(buf_out2)); + AND2x2_ASAP7_75t_R u3 (.A(buf_out), .B(buf_out2), .Y(and_out)); + BUFx2_ASAP7_75t_R u4 (.A(and_out), .Y(out)); +endmodule