# OpenSTA, Static Timing Analyzer # Copyright (c) 2019, Parallax Software, Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ################################################################ # # Power commands. # ################################################################ namespace eval sta { define_cmd_args "report_power" \ { [-instances instances]\ [-corner corner_name]\ [-digits digits]\ [> filename] [>> filename] } proc_redirect report_power { global sta_report_default_digits parse_key_args "report_power" args keys {-instances -corner -digits} flags {} 1 if [info exists keys(-digits)] { set digits $keys(-digits) check_positive_integer "-digits" $digits } else { set digits $sta_report_default_digits } set corner [parse_corner keys] if { [info exists keys(-instances)] } { set insts [get_instances_error "-instances" $keys(-instances)] report_power_insts $insts $corner $digits } else { report_power_design $corner $digits } } proc report_power_design { corner digits } { set power_result [design_power $corner] set totals [lrange $power_result 0 3] set sequential [lrange $power_result 4 7] set combinational [lrange $power_result 8 11] set macro [lrange $power_result 12 15] set pad [lrange $power_result 16 end] lassign $totals design_internal design_switching design_leakage design_total set field_width [max [expr $digits + 6] 10] report_power_title5 "Group" "Internal" "Switching" "Leakage" "Total" $field_width report_power_title5 " " "Power" "Power" "Power" "Power" $field_width report_title_dashes5 $field_width report_power_row "Sequential" $sequential $design_total $field_width $digits report_power_row "Combinational" $combinational $design_total $field_width $digits report_power_row "Macro" $macro $design_total $field_width $digits report_power_row "Pad" $pad $design_total $field_width $digits report_title_dashes5 $field_width report_power_row "Total" $power_result $design_total $field_width $digits puts -nonewline [format "%-20s" ""] report_power_col_percent $design_internal $design_total $field_width report_power_col_percent $design_switching $design_total $field_width report_power_col_percent $design_leakage $design_total $field_width puts "" } proc max { x y } { if { $x >= $y } { return $x } else { return $y } } proc report_power_title5 { title1 title2 title3 title4 title5 field_width } { puts -nonewline [format "%-20s" $title1] report_power_title4 $title2 $title3 $title4 $title5 $field_width } proc report_power_title4 { title1 title2 title3 title4 field_width } { puts -nonewline [format " %${field_width}s" $title1] puts -nonewline [format " %${field_width}s" $title2] puts -nonewline [format " %${field_width}s" $title3] puts [format " %${field_width}s" $title4] } proc report_title_dashes5 { field_width } { set count [expr 20 + ($field_width + 1) * 4] report_title_dashes $count } proc report_title_dashes4 { field_width } { set count [expr ($field_width + 1) * 4] report_title_dashes $count } proc report_title_dashes { count } { for {set i 0} {$i < $count} {incr i} { puts -nonewline "-" } puts "" } proc report_power_row { type row_result design_total field_width digits } { lassign $row_result internal switching leakage total if { $design_total == 0.0 } { set percent 0.0 } else { set percent [expr $total / $design_total * 100] } puts -nonewline [format "%-20s" $type] report_power_col $internal $field_width $digits report_power_col $switching $field_width $digits report_power_col $leakage $field_width $digits report_power_col $total $field_width $digits puts [format " %5.1f%%" $percent] } proc report_power_col { pwr field_width digits } { puts -nonewline [format " %$field_width.${digits}e" $pwr] } proc report_power_col_percent { col_total total field_width } { if { $total == 0.0 } { set percent 0.0 } else { set percent [expr $col_total / $total * 100] } puts -nonewline [format "%$field_width.1f%%" $percent] } proc report_power_line { type pwr digits } { puts [format "%-16s %.${digits}e" $type $pwr] } proc report_power_insts { insts corner digits } { set inst_pwrs {} foreach inst $insts { set power_result [instance_power $inst $corner] lappend inst_pwrs [list $inst $power_result] } set inst_pwrs [lsort -command inst_pwr_cmp $inst_pwrs] set field_width [max [expr $digits + 6] 10] report_power_title4 "Internal" "Switching" "Leakage" "Total" $field_width report_power_title4 "Power" "Power" "Power" "Power" $field_width report_title_dashes4 $field_width foreach inst_pwr $inst_pwrs { set inst [lindex $inst_pwr 0] set power [lindex $inst_pwr 1] report_power_inst $inst $power $field_width $digits } } proc inst_pwr_cmp { inst_pwr1 inst_pwr2 } { set pwr1 [lindex $inst_pwr1 1] set pwr2 [lindex $inst_pwr2 1] lassign $pwr1 internal1 switching1 leakage1 total1 lassign $pwr2 internal2 switching2 leakage2 total2 if { $total1 < $total2 } { return 1 } elseif { $total1 == $total2 } { return 0 } else { return -1 } } proc report_power_inst { inst power_result field_width digits } { lassign $power_result internal switching leakage total report_power_col $internal $field_width $digits report_power_col $switching $field_width $digits report_power_col $leakage $field_width $digits report_power_col $total $field_width $digits puts " [get_full_name $inst]" } ################################################################ set ::power_default_signal_toggle_rate 0.1 trace variable ::power_default_signal_toggle_rate "rw" \ sta::trace_power_default_signal_toggle_rate proc trace_power_default_signal_toggle_rate { name1 name2 op } { global power_default_signal_toggle_rate if { $op == "r" } { set power_default_signal_toggle_rate [power_default_signal_toggle_rate] } elseif { $op == "w" } { if { [string is double $power_default_signal_toggle_rate] \ && $power_default_signal_toggle_rate >= 0.0 } { set_power_default_signal_toggle_rate $power_default_signal_toggle_rate } else { sta_error "power_default_signal_toggle_rate must be a positive float." } } } # sta namespace end. }