From b5222c4a1a9797158b61176bed3a66746122bf66 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Sat, 11 Jul 2026 13:54:38 -0700 Subject: [PATCH] Implement set_max_dynamic_power and set_max_leakage_power. Store max dynamic/leakage power like max area, expose getters through Sta, write them in write_sdc, and document that they are ignored during timing. Co-authored-by: Cursor --- doc/OpenSTA.fodt | 4 ++-- include/sta/Sdc.hh | 6 ++++++ include/sta/Sta.hh | 7 +++++++ sdc/Sdc.cc | 26 ++++++++++++++++++++++++++ sdc/Sdc.i | 37 +++++++++++++++++++++++++++++++++++++ sdc/Sdc.tcl | 26 ++++++++++++++++++++++++-- sdc/WriteSdc.cc | 24 ++++++++++++++++++++++++ sdc/WriteSdcPvt.hh | 2 ++ search/Sta.cc | 32 ++++++++++++++++++++++++++++++++ test/max_power_area.ok | 6 ++++++ test/max_power_area.tcl | 25 +++++++++++++++++++++++++ test/regression_vars.tcl | 1 + 12 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 test/max_power_area.ok create mode 100644 test/max_power_area.tcl diff --git a/doc/OpenSTA.fodt b/doc/OpenSTA.fodt index 3b13720ce..dcaf83abf 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. diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index a93569fe2..948efe10d 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, @@ -1420,6 +1424,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/Sta.hh b/include/sta/Sta.hh index bf482f55a..e2f5ced34 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, diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 9b30c4702..77f3ba89d 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 * diff --git a/sdc/Sdc.i b/sdc/Sdc.i index 3ac13d812..d326512e7 100644 --- a/sdc/Sdc.i +++ b/sdc/Sdc.i @@ -1229,6 +1229,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 e444eea8f..468081945 100644 --- a/sdc/Sdc.tcl +++ b/sdc/Sdc.tcl @@ -2989,6 +2989,12 @@ proc set_max_area { area } { set_max_area_cmd $area } +define_cmd_args "get_max_area" {} + +proc get_max_area {} { + return [max_area] +} + ################################################################ define_cmd_args "set_max_capacitance" {cap objects} @@ -3599,7 +3605,15 @@ 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 +} + +define_cmd_args "get_max_dynamic_power" {} + +proc get_max_dynamic_power {} { + return [max_dynamic_power] } ################################################################ @@ -3607,7 +3621,15 @@ 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 +} + +define_cmd_args "get_max_leakage_power" {} + +proc get_max_leakage_power {} { + return [max_leakage_power] } ################################################################ diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index 1733a050f..4fa346563 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -2031,6 +2031,8 @@ WriteSdc::writeDesignRules() const writeCapLimits(); writeFanoutLimits(); writeMaxArea(); + writeMaxDynamicPower(); + writeMaxLeakagePower(); } void @@ -2262,6 +2264,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 b7bc93385..1d0b0f082 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/Sta.cc b/search/Sta.cc index 843061dfa..1b7d7111e 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -1148,6 +1148,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, diff --git a/test/max_power_area.ok b/test/max_power_area.ok new file mode 100644 index 000000000..6848c1f8b --- /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 000000000..4d64f79ba --- /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 [get_max_area]" +puts "max_dynamic_power [get_max_dynamic_power]" +puts "max_leakage_power [get_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 fcb2c291b..05db84e2d 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