diff --git a/power/Power.tcl b/power/Power.tcl index 420a97a99..279cb932f 100644 --- a/power/Power.tcl +++ b/power/Power.tcl @@ -35,13 +35,14 @@ define_cmd_args "report_power" \ [-highest_power_instances count]\ [-corner corner]\ [-digits digits]\ + [-format format]\ [> filename] [>> filename] } proc_redirect report_power { global sta_report_default_digits parse_key_args "report_power" args \ - keys {-instances -highest_power_instances -corner -digits} flags {} + keys {-instances -highest_power_instances -corner -digits -format} flags {} check_argc_eq0 "report_power" $args @@ -56,16 +57,37 @@ proc_redirect report_power { } set corner [parse_corner keys] + if { [info exists keys(-format)] } { + set format $keys(-format) + if { $format != "text" && $format != "json" } { + sta_error 311 "unknown power report -format $format" + } + } else { + set format "text" + } + if { [info exists keys(-instances)] } { set insts [get_instances_error "-instances" $keys(-instances)] - report_power_insts $insts $corner $digits + if { $format == "json" } { + report_power_insts_json $insts $corner $digits + } else { + report_power_insts $insts $corner $digits + } } elseif { [info exists keys(-highest_power_instances)] } { set count $keys(-highest_power_instances) check_positive_integer "-highest_power_instances" $count set insts [highest_power_instances $count $corner] - report_power_insts $insts $corner $digits + if { $format == "json" } { + report_power_insts_json $insts $corner $digits + } else { + report_power_insts $insts $corner $digits + } } else { - report_power_design $corner $digits + if { $format == "json" } { + report_power_design_json $corner $digits + } else { + report_power_design $corner $digits + } } } @@ -104,6 +126,35 @@ proc report_power_design { corner digits } { report_line "[format %-20s {}][power_col_percent $design_internal $design_total $field_width][power_col_percent $design_switching $design_total $field_width][power_col_percent $design_leakage $design_total $field_width]" } +proc report_power_design_json { 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 clock [lrange $power_result 12 15] + set macro [lrange $power_result 16 19] + set pad [lrange $power_result 20 end] + + report_line "\{" + report_power_row_json "Sequential" $sequential $digits "," + report_power_row_json "Combinational" $combinational $digits "," + report_power_row_json "Clock" $clock $digits "," + report_power_row_json "Macro" $macro $digits "," + report_power_row_json "Pad" $pad $digits "," + report_power_row_json "Total" $totals $digits "" + report_line "\}" +} + +proc report_power_row_json { name row_result digits separator } { + lassign $row_result internal switching leakage total + report_line " \"$name\": \{" + report_line " \"internal\": [format %.${digits}e $internal]," + report_line " \"switching\": [format %.${digits}e $switching]," + report_line " \"leakage\": [format %.${digits}e $leakage]," + report_line " \"total\": [format %.${digits}e $total]" + report_line " \}$separator" +} + proc max { x y } { if { $x >= $y } { return $x @@ -206,6 +257,42 @@ proc report_power_insts { insts corner digits } { } } +proc report_power_insts_json { 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] + + report_line "\[" + set count [llength $inst_pwrs] + set index 0 + foreach inst_pwr $inst_pwrs { + set inst [lindex $inst_pwr 0] + set power [lindex $inst_pwr 1] + incr index + if { $index < $count } { + report_power_inst_json $inst $power $digits "," + } else { + report_power_inst_json $inst $power $digits "" + } + } + report_line "\]" +} + +proc report_power_inst_json { inst power digits separator } { + lassign $power internal switching leakage total + set inst_name [get_full_name $inst] + report_line "\{" + report_line " \"name\": \"$inst_name\"," + report_line " \"internal\": [format %.${digits}e $internal]," + report_line " \"switching\": [format %.${digits}e $switching]," + report_line " \"leakage\": [format %.${digits}e $leakage]," + report_line " \"total\": [format %.${digits}e $total]" + report_line "\}$separator" +} + proc inst_pwr_cmp { inst_pwr1 inst_pwr2 } { set pwr1 [lindex $inst_pwr1 1] set pwr2 [lindex $inst_pwr2 1] diff --git a/test/power_json.ok b/test/power_json.ok new file mode 100644 index 000000000..602868fcc --- /dev/null +++ b/test/power_json.ok @@ -0,0 +1,76 @@ +Warning: ../examples/gcd_sky130hd.v line 527, module sky130_fd_sc_hd__tapvpwrvgnd_1 not found. Creating black box for TAP_11. +{ + "Sequential": { + "internal": 3.0660e-04, + "switching": 4.7564e-05, + "leakage": 2.9607e-10, + "total": 3.5417e-04 + }, + "Combinational": { + "internal": 1.5871e-04, + "switching": 2.0511e-04, + "leakage": 6.8590e-10, + "total": 3.6381e-04 + }, + "Clock": { + "internal": 4.6828e-05, + "switching": 1.2049e-04, + "leakage": 2.3004e-11, + "total": 1.6732e-04 + }, + "Macro": { + "internal": 0.0000e+00, + "switching": 0.0000e+00, + "leakage": 0.0000e+00, + "total": 0.0000e+00 + }, + "Pad": { + "internal": 0.0000e+00, + "switching": 0.0000e+00, + "leakage": 0.0000e+00, + "total": 0.0000e+00 + }, + "Total": { + "internal": 5.1214e-04, + "switching": 3.7316e-04, + "leakage": 1.0050e-09, + "total": 8.8530e-04 + } +} +[ +{ + "name": "clkbuf_2_3__f_clk", + "internal": 9.3880e-06, + "switching": 2.5721e-05, + "leakage": 4.6007e-12, + "total": 3.5109e-05 +}, +{ + "name": "clkbuf_2_0__f_clk", + "internal": 9.3814e-06, + "switching": 2.5163e-05, + "leakage": 4.6007e-12, + "total": 3.4544e-05 +}, +{ + "name": "clkbuf_2_1__f_clk", + "internal": 9.3672e-06, + "switching": 2.3965e-05, + "leakage": 4.6007e-12, + "total": 3.3332e-05 +}, +{ + "name": "clkbuf_2_2__f_clk", + "internal": 9.3592e-06, + "switching": 2.3293e-05, + "leakage": 4.6007e-12, + "total": 3.2652e-05 +}, +{ + "name": "clkbuf_0_clk", + "internal": 9.3319e-06, + "switching": 2.2346e-05, + "leakage": 4.6007e-12, + "total": 3.1678e-05 +} +] diff --git a/test/power_json.tcl b/test/power_json.tcl new file mode 100644 index 000000000..65aef4506 --- /dev/null +++ b/test/power_json.tcl @@ -0,0 +1,14 @@ +# report_power gcd +set sta_report_default_digits 4 +read_liberty ../examples/sky130hd_tt.lib.gz +read_verilog ../examples/gcd_sky130hd.v +link_design gcd + +read_sdc ../examples/gcd_sky130hd.sdc +set_propagated_clock clk +read_spef ../examples/gcd_sky130hd.spef +set_power_activity -input -activity .1 +set_power_activity -input_port reset -activity 0 + +report_power -format json +report_power -format json -instances "[get_cells -filter "name=~clkbuf*"]" diff --git a/test/regression_vars.tcl b/test/regression_vars.tcl index f3eb42e97..6641afc3c 100644 --- a/test/regression_vars.tcl +++ b/test/regression_vars.tcl @@ -155,6 +155,7 @@ record_sta_tests { path_group_names prima3 report_checks_sorted + power_json report_checks_src_attr report_json1 report_json2