From 8a4b1e7f06f42deba05d987fe729065b32b2bfe8 Mon Sep 17 00:00:00 2001 From: Kareem Farid Date: Wed, 5 Apr 2023 23:58:56 +0200 Subject: [PATCH] Hierarchical Static Timing Analysis (#1675) \+ Add `EXTRA_SPEFS` \+ Use `VERILOG_FILES_BLACKBOX` in sta. Allow skipping a file by adding a comment `/// sta-blackbox` \+ Detect blackboxed modules in typical-corner STA during sign off and warn the user about it \+ Add `run_sta_script` used in multicorner sta \+ Support sta in `or_issue.py` \+ Support sta in `run_tcl_script` \+ Check if regex defined in `FP_PDN_MACRO_HOOKS` has a match. Fixes https://github.com/The-OpenROAD-Project/OpenLane/issues/1599 \~ Wrap `set_global_connections` around a flag since it is not supported by opensta \~ Run multicorner sta using standalone sta application for hierarchical sta support \~ Move `sta_multi_corner.tcl` to `scripts/openroad/sta/multi_corner.tcl` \~ Don't delete target directory of `-save` for multicorner spef files \~ Merge multi_corner sta and single corner into one script. \~ Split `RUN_STANDALONE` embedded inside openroad steps, which calls sta after, to another sta step run after said openroad step \- Remove `report_design_area` in `multi_corner.tcl` since it is not supported by standalone OpenSTA \- Remove `scripts/openroad/sta.tcl` --- designs/caravel_upw/src/user_proj_example.v | 1 + designs/caravel_upw/src/user_proj_example2.v | 1 + docs/source/reference/configuration.md | 3 +- docs/source/tutorials/digital_guide.md | 2 +- scripts/openroad/common/io.tcl | 137 +++++++++----- .../common/set_global_connections.tcl | 15 +- scripts/openroad/cts.tcl | 8 - scripts/openroad/floorplan.tcl | 4 +- scripts/openroad/gpl.tcl | 3 - scripts/openroad/groute.tcl | 3 - scripts/openroad/rcx.tcl | 4 +- scripts/openroad/resizer.tcl | 2 - scripts/openroad/resizer_routing_design.tcl | 2 - scripts/openroad/resizer_routing_timing.tcl | 2 - scripts/openroad/resizer_timing.tcl | 2 - .../{sta.tcl => sta/multi_corner.tcl} | 92 ++++++---- scripts/openroad/sta_multi_corner.tcl | 171 ------------------ scripts/or_issue.py | 4 +- scripts/report/report.py | 1 - scripts/tcl_commands/all.tcl | 16 +- scripts/tcl_commands/cts.tcl | 4 + scripts/tcl_commands/placement.tcl | 5 +- scripts/tcl_commands/routing.tcl | 6 +- scripts/tcl_commands/sta.tcl | 31 +++- scripts/utils/utils.tcl | 15 +- 25 files changed, 236 insertions(+), 298 deletions(-) rename scripts/openroad/{sta.tcl => sta/multi_corner.tcl} (65%) delete mode 100755 scripts/openroad/sta_multi_corner.tcl diff --git a/designs/caravel_upw/src/user_proj_example.v b/designs/caravel_upw/src/user_proj_example.v index 26081e98..55da4624 100644 --- a/designs/caravel_upw/src/user_proj_example.v +++ b/designs/caravel_upw/src/user_proj_example.v @@ -35,6 +35,7 @@ *------------------------------------------------------------- */ +/// sta-blackbox module user_proj_example #( parameter BITS = 32 )( diff --git a/designs/caravel_upw/src/user_proj_example2.v b/designs/caravel_upw/src/user_proj_example2.v index 49497b98..e00a1b1e 100644 --- a/designs/caravel_upw/src/user_proj_example2.v +++ b/designs/caravel_upw/src/user_proj_example2.v @@ -13,6 +13,7 @@ // limitations under the License. // SPDX-License-Identifier: Apache-2.0 +/// sta-blackbox `default_nettype none /* *------------------------------------------------------------- diff --git a/docs/source/reference/configuration.md b/docs/source/reference/configuration.md index fa4fa8c0..66702175 100644 --- a/docs/source/reference/configuration.md +++ b/docs/source/reference/configuration.md @@ -34,7 +34,7 @@ These variables are optional that can be specified in the design configuration f |Variable|Description| |-|-| -| `VERILOG_FILES_BLACKBOX` | Black-boxed, Verilog files where the implementation is ignored. Useful for pre-hardened macros you incorporate into your design, used during synthesis. | +| `VERILOG_FILES_BLACKBOX` | Black-boxed, Verilog files where the implementation is ignored. Useful for pre-hardened macros you incorporate into your design, used during synthesis and opensta. `/// sta-blackbox` can be added to a file in order skip that file while doing sta. This will blackbox all the modules definied inside that file. It is recommended to provide a gatelevel netlist whenever possible to do full sta. | | `EXTRA_LEFS` | Specifies LEF files of pre-hardened macros used in the current design, used in placement and routing. | | `EXTRA_LIBS` | Specifies LIB files of pre-hardened macros used in the current design, used during timing analysis. (Optional) | | `EXTRA_GDS_FILES` | Specifies GDS files of pre-hardened macros used in the current design, used during tape-out. | @@ -71,6 +71,7 @@ These variables are optional that can be specified in the design configuration f | Variable | Description | |-|-| +| `EXTRA_SPEFS` | Specifies min, nom, max spef files for modules(s). Variable should be provided as a json/tcl list or a space delimited tcl string. Note that a module name is provided not an instance name. A module may have multiple instances. Each module must have define 3 files, one for each corner. For example: `module1 min1 nom1 max1 module2 min2 nom2 max2`. A file can be used multiple time in case of absence of other corner files. For example: `module nom nom nom`. In this case, the nom file will be used in all corners of sta. At all times a module must specify 3 files.
(Default: NONE) | | `STA_WRITE_LIB` | Controls whether a timing model is written using OpenROAD OpenSTA after static timing analysis. This is an option as it in its current state, the timing model generation (and the model itself) can be quite buggy.
(Default: `1`) | ### Floorplanning diff --git a/docs/source/tutorials/digital_guide.md b/docs/source/tutorials/digital_guide.md index b6312922..4b75b396 100644 --- a/docs/source/tutorials/digital_guide.md +++ b/docs/source/tutorials/digital_guide.md @@ -541,7 +541,7 @@ Startpoint: write_addr[1] (input port clocked by clk) Endpoint: _3436_ (rising edge-triggered flip-flop clocked by clk) Path Group: clk Path Type: max -Corner: ss +Corner: Slowest Fanout Cap Slew Delay Time Description ----------------------------------------------------------------------------- diff --git a/scripts/openroad/common/io.tcl b/scripts/openroad/common/io.tcl index 46de043e..4b3966b7 100644 --- a/scripts/openroad/common/io.tcl +++ b/scripts/openroad/common/io.tcl @@ -14,14 +14,46 @@ source $::env(SCRIPTS_DIR)/openroad/common/set_global_connections.tcl -proc read_netlist {args} { - puts "Reading netlist..." +proc is_blackbox {file_path blackbox_wildcard} { + set not_found [catch { + exec bash -c "grep '$blackbox_wildcard' \ + $file_path" + }] + return [expr !$not_found] +} - if {[catch {read_verilog $::env(CURRENT_NETLIST)} errmsg]} { +proc read_netlist {args} { + sta::parse_key_args "read_netlists" args \ + keys {}\ + flags {-powered -all} + set netlist $::env(CURRENT_NETLIST) + if { [info exists flags(-powered)] } { + set netlist $::env(CURRENT_POWERED_NETLIST) + } + + puts "Reading netlist $netlist ..." + + if {[catch {read_verilog $netlist} errmsg]} { puts stderr $errmsg exit 1 } + if { [info exists flags(-all)] } { + set blackbox_wildcard {/// sta-blackbox} + if { [info exists ::env(VERILOG_FILES_BLACKBOX)] } { + foreach verilog_file $::env(VERILOG_FILES_BLACKBOX) { + if { [is_blackbox $verilog_file $blackbox_wildcard] } { + puts "Found $blackbox_wildcard in $verilog_file skipping..." + } elseif { [catch {read_verilog $verilog_file} err] } { + puts "Error while reading $verilog_file:" + puts "Make sure that this a gate-level netlist not an RTL file" + puts "Add $blackbox_wildcard to skip this file and blackbox the modules if needed." + puts $err + exit 1 + } + } + } + } link_design $::env(DESIGN_NAME) if { [info exists ::env(CURRENT_SDC)] } { @@ -35,49 +67,31 @@ proc read_netlist {args} { proc read_libs {args} { sta::parse_key_args "read_libs" args \ - keys {-override}\ - flags {-multi_corner} + keys {-typical -slowest -fastest}\ + flags {-multi_corner_libs} - set libs $::env(LIB_SYNTH_COMPLETE) - - if { [info exists keys(-override)] } { - set libs $keys(-override) + if { ![info exists keys(-typical)] } { + puts "read_libs -typical is required" + exit 1 } + if { [info exists keys(-slowest)] } { + set corner(Slowest) $keys(-slowest) + } + if { [info exists keys(-fastest)] } { + set corner(Fastest) $keys(-fastest) + } + set corner(Typical) $keys(-typical) + puts "define_corners [array name corner]" + define_corners {*}[array name corner] - if { [info exists flags(-multi_corner)] } { - # Note that the one defined first is the "default": meaning you - # shouldn't use -multi_corner for scripts that do not explicitly - # specify the corners for STA calls. - define_corners ss tt ff; - - foreach lib $::env(LIB_SLOWEST) { - read_liberty -corner ss $lib - } - foreach lib $::env(LIB_TYPICAL) { - read_liberty -corner tt $lib - } - foreach lib $::env(LIB_FASTEST) { - read_liberty -corner ff $lib - } - - foreach corner {ss tt ff} { - if { [info exists ::env(EXTRA_LIBS) ] } { - foreach lib $::env(EXTRA_LIBS) { - read_liberty -corner $corner $lib - } - } - } - } else { - foreach lib $libs { - read_liberty $lib - } - + foreach corner_name [array name corner] { + puts "read_liberty -corner $corner_name $corner($corner_name)" + read_liberty -corner $corner_name $corner($corner_name) if { [info exists ::env(EXTRA_LIBS) ] } { foreach lib $::env(EXTRA_LIBS) { - read_liberty $lib + read_liberty -corner $corner_name $lib } } - } } @@ -106,11 +120,13 @@ proc read {args} { set read_libs_args [list] if { [info exists keys(-override_libs)]} { - lappend read_libs_args -override $keys(-override_libs) + lappend read_libs_args -typical $keys(-override_libs) + } else { + lappend read_libs_args -typical $::env(LIB_TYPICAL) } if { [info exists flags(-multi_corner_libs)] } { - lappend read_libs_args -multi_corner + lappend read_libs_args -fastest $::env(LIB_FASTEST) -slowest $::env(LIB_SLOWEST) } read_libs {*}$read_libs_args @@ -129,9 +145,10 @@ proc write {args} { # attempt to write a corresponding view to the specified location. sta::parse_key_args "write" args \ keys {}\ - flags {} + flags {-no_global_connect} - if { [info exists ::env(VDD_NET)] } { + if { [info exists ::env(VDD_NET)] \ + && ![info exist flags(-no_global_connect)] } { puts "Setting global connections for newly added cells..." set_global_connections } @@ -207,3 +224,37 @@ proc write {args} { } } } + + +proc read_spefs {} { + set corners [sta::corners] + if { [info exists ::env(CURRENT_SPEF)] } { + foreach corner $corners { + read_spef -corner [$corner name] $::env(CURRENT_SPEF) + read_spef -corner [$corner name] $::env(CURRENT_SPEF) + read_spef -corner [$corner name] $::env(CURRENT_SPEF) + } + } + + if { [info exists ::env(EXTRA_SPEFS)] } { + foreach {module_name spef_file_min spef_file_nom spef_file_max} \ + "$::env(EXTRA_SPEFS)" { + set matched 0 + foreach cell [get_cells *] { + if { "[get_property $cell ref_name]" eq "$module_name" && !$matched } { + puts "Matched [get_property $cell name] with $module_name" + set matched 1 + foreach corner $corners { + read_spef -path [get_property $cell name] -corner [$corner name] $spef_file_min + read_spef -path [get_property $cell name] -corner [$corner name] $spef_file_nom + read_spef -path [get_property $cell name] -corner [$corner name] $spef_file_max + } + } + } + if { $matched != 1 } { + puts "Error: Module $module_name specified in EXTRA_SPEFS not found." + exit 1 + } + } + } +} diff --git a/scripts/openroad/common/set_global_connections.tcl b/scripts/openroad/common/set_global_connections.tcl index d2107e18..6c0e9d37 100644 --- a/scripts/openroad/common/set_global_connections.tcl +++ b/scripts/openroad/common/set_global_connections.tcl @@ -45,7 +45,18 @@ proc set_global_connections {} { if { $power_pin == "" || $ground_pin == "" } { puts "FP_PDN_MACRO_HOOKS missing power and ground pin names" - exit -1 + exit 1 + } + + set matched 0 + foreach cell [[ord::get_db_block] getInsts] { + if { [regexp "\^$instance_name" [$cell getName]] } { + set matched 1 + } + } + if { $matched != 1 } { + puts "No regex match found for $instance_name defined in FP_PDN_MACRO_HOOKS" + exit 1 } add_global_connection \ @@ -61,4 +72,4 @@ proc set_global_connections {} { -ground } } -} \ No newline at end of file +} diff --git a/scripts/openroad/cts.tcl b/scripts/openroad/cts.tcl index 7def8832..b9e5c3d0 100755 --- a/scripts/openroad/cts.tcl +++ b/scripts/openroad/cts.tcl @@ -81,11 +81,3 @@ puts "cts_report" report_cts puts "cts_report_end" -if {[info exists ::env(CLOCK_PORT)]} { - if { [info exists ::env(CTS_REPORT_TIMING)] && $::env(CTS_REPORT_TIMING) } { - set ::env(RUN_STANDALONE) 0 - source $::env(SCRIPTS_DIR)/openroad/sta.tcl - } -} else { - puts "\[WARN\]: No CLOCK_PORT found. Skipping STA..." -} diff --git a/scripts/openroad/floorplan.tcl b/scripts/openroad/floorplan.tcl index bd95e3bb..e950305c 100755 --- a/scripts/openroad/floorplan.tcl +++ b/scripts/openroad/floorplan.tcl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. source $::env(SCRIPTS_DIR)/openroad/common/io.tcl -read_libs -override "$::env(LIB_SYNTH_COMPLETE)" +read_libs -typical "$::env(LIB_SYNTH_COMPLETE)" read_lef $::env(MERGED_LEF) read_netlist @@ -108,4 +108,4 @@ puts -nonewline $core_area_file $::env(CORE_AREA) close $core_area_file close $die_area_file -write \ No newline at end of file +write diff --git a/scripts/openroad/gpl.tcl b/scripts/openroad/gpl.tcl index 9dbc183f..bec4b9a8 100755 --- a/scripts/openroad/gpl.tcl +++ b/scripts/openroad/gpl.tcl @@ -78,9 +78,6 @@ if {[info exists ::env(CLOCK_PORT)]} { # set rc values source $::env(SCRIPTS_DIR)/openroad/common/set_rc.tcl estimate_parasitics -placement - - set ::env(RUN_STANDALONE) 0 - source $::env(SCRIPTS_DIR)/openroad/sta.tcl } } else { puts "\[WARN\]: No CLOCK_PORT found. Skipping STA..." diff --git a/scripts/openroad/groute.tcl b/scripts/openroad/groute.tcl index c06b441c..2eb61291 100644 --- a/scripts/openroad/groute.tcl +++ b/scripts/openroad/groute.tcl @@ -48,9 +48,6 @@ if {[info exists ::env(CLOCK_PORT)]} { source $::env(SCRIPTS_DIR)/openroad/common/set_rc.tcl # estimate wire rc parasitics estimate_parasitics -global_routing - - set ::env(RUN_STANDALONE) 0 - source $::env(SCRIPTS_DIR)/openroad/sta.tcl } } else { puts "\[WARN\]: No CLOCK_PORT found. Skipping STA..." diff --git a/scripts/openroad/rcx.tcl b/scripts/openroad/rcx.tcl index b1140e4e..b12e2f69 100644 --- a/scripts/openroad/rcx.tcl +++ b/scripts/openroad/rcx.tcl @@ -14,7 +14,7 @@ source $::env(SCRIPTS_DIR)/openroad/common/io.tcl read_lef $::env(RCX_LEF) read_def $::env(RCX_DEF) -read_libs -override "$::env(RCX_LIB)" +read_libs -typical "$::env(RCX_LIB)" set_propagated_clock [all_clocks] @@ -31,4 +31,4 @@ extract_parasitics $rcx_flags\ -lef_res puts "Writing result to $::env(SAVE_SPEF)..." -write \ No newline at end of file +write diff --git a/scripts/openroad/resizer.tcl b/scripts/openroad/resizer.tcl index bf84b7b4..402ce5ab 100644 --- a/scripts/openroad/resizer.tcl +++ b/scripts/openroad/resizer.tcl @@ -76,5 +76,3 @@ write # Run post design optimizations STA estimate_parasitics -placement -set ::env(RUN_STANDALONE) 0 -source $::env(SCRIPTS_DIR)/openroad/sta.tcl diff --git a/scripts/openroad/resizer_routing_design.tcl b/scripts/openroad/resizer_routing_design.tcl index fb47f41a..977bb96c 100644 --- a/scripts/openroad/resizer_routing_design.tcl +++ b/scripts/openroad/resizer_routing_design.tcl @@ -74,5 +74,3 @@ write # Run post timing optimizations STA estimate_parasitics -global_routing -set ::env(RUN_STANDALONE) 0 -source $::env(SCRIPTS_DIR)/openroad/sta.tcl diff --git a/scripts/openroad/resizer_routing_timing.tcl b/scripts/openroad/resizer_routing_timing.tcl index 4fefe52e..82530dfa 100644 --- a/scripts/openroad/resizer_routing_timing.tcl +++ b/scripts/openroad/resizer_routing_timing.tcl @@ -78,5 +78,3 @@ write # Run post timing optimizations STA estimate_parasitics -global_routing -set ::env(RUN_STANDALONE) 0 -source $::env(SCRIPTS_DIR)/openroad/sta.tcl diff --git a/scripts/openroad/resizer_timing.tcl b/scripts/openroad/resizer_timing.tcl index 08625fc4..c61dfbce 100644 --- a/scripts/openroad/resizer_timing.tcl +++ b/scripts/openroad/resizer_timing.tcl @@ -65,5 +65,3 @@ write # Run post timing optimizations STA estimate_parasitics -placement -set ::env(RUN_STANDALONE) 0 -source $::env(SCRIPTS_DIR)/openroad/sta.tcl diff --git a/scripts/openroad/sta.tcl b/scripts/openroad/sta/multi_corner.tcl similarity index 65% rename from scripts/openroad/sta.tcl rename to scripts/openroad/sta/multi_corner.tcl index 9c342de7..82dc5164 100644 --- a/scripts/openroad/sta.tcl +++ b/scripts/openroad/sta/multi_corner.tcl @@ -11,54 +11,65 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -if { $::env(RUN_STANDALONE) == 1 } { - source $::env(SCRIPTS_DIR)/openroad/common/io.tcl - if { $::env(CURRENT_ODB) != "0" } { - read - } else { - read_libs - read_lef $::env(MERGED_LEF) - read_netlist - } +source $::env(SCRIPTS_DIR)/openroad/common/io.tcl - if { $::env(STA_PRE_CTS) == 1 } { - unset_propagated_clock [all_clocks] - } else { - set_propagated_clock [all_clocks] - } +set arg_list [list] +lappend arg_list -typical $::env(LIB_TYPICAL) +if { $::env(STA_MULTICORNER) } { + lappend arg_list -fastest $::env(LIB_FASTEST) + lappend arg_list -slowest $::env(LIB_SLOWEST) } +read_libs {*}$arg_list + +read_netlist -all +read_spefs + set_cmd_units -time ns -capacitance pF -current mA -voltage V -resistance kOhm -distance um -if { [info exists ::env(CURRENT_SPEF)] } { - read_spef $::env(CURRENT_SPEF) +if { $::env(STA_PRE_CTS) == 1 } { + unset_propagated_clock [all_clocks] +} else { + set_propagated_clock [all_clocks] } puts "min_report" puts "\n===========================================================================" puts "report_checks -path_delay min (Hold)" puts "============================================================================" -report_checks -path_delay min -fields {slew cap input nets fanout} -format full_clock_expanded -group_count 5 +foreach corner [sta::corners] { + puts "\n======================= [$corner name] Corner ===================================\n" + report_checks -path_delay min -fields {slew cap input nets fanout} -format full_clock_expanded -group_count 1000 -corner [$corner name] +} puts "min_report_end" + puts "max_report" puts "\n===========================================================================" puts "report_checks -path_delay max (Setup)" puts "============================================================================" -report_checks -path_delay max -fields {slew cap input nets fanout} -format full_clock_expanded -group_count 5 +foreach corner [sta::corners] { + puts "\n======================= [$corner name] Corner ===================================\n" + report_checks -path_delay max -fields {slew cap input nets fanout} -format full_clock_expanded -group_count 1000 -corner [$corner name] +} puts "max_report_end" puts "check_report" puts "\n===========================================================================" puts "report_checks -unconstrained" -puts "============================================================================" -report_checks -unconstrained -fields {slew cap input nets fanout} -format full_clock_expanded +foreach corner [sta::corners] { +puts "\n======================= [$corner name] Corner ===================================\n" + report_checks -unconstrained -fields {slew cap input nets fanout} -format full_clock_expanded -corner [$corner name] +} puts "\n===========================================================================" puts "report_checks --slack_max -0.01" puts "============================================================================" -report_checks -slack_max -0.01 -fields {slew cap input nets fanout} -format full_clock_expanded +foreach corner [sta::corners] { + puts "\n======================= [$corner name] Corner ===================================\n" + report_checks -slack_max -0.01 -fields {slew cap input nets fanout} -format full_clock_expanded -corner [$corner name] +} puts "check_report_end" puts "parastic_annotation_check" @@ -66,14 +77,16 @@ puts "\n======================================================================== puts "report_parasitic_annotation -report_unannotated" puts "============================================================================" report_parasitic_annotation -report_unannotated -puts "parastic_annotation_check" +puts "parastic_annotation_check_end" puts "check_slew" puts "\n===========================================================================" puts " report_check_types -max_slew -max_cap -max_fanout -violators" puts "============================================================================" -report_check_types -max_slew -max_capacitance -max_fanout -violators - +foreach corner [sta::corners] { + puts "\n======================= [$corner name] Corner ===================================\n" + report_check_types -max_slew -max_capacitance -max_fanout -violators -corner [$corner name] +} puts "\n===========================================================================" puts "max slew violation count [sta::max_slew_violation_count]" @@ -96,6 +109,7 @@ puts "========================================================================== report_wns puts "wns_report_end" + puts "worst_slack" puts "\n===========================================================================" puts " report_worst_slack -max (Setup)" @@ -108,6 +122,7 @@ puts "========================================================================== report_worst_slack -min puts "worst_slack_end" + # report clock skew if the clock port is defined # OR hangs if this command is run on clockless designs if { $::env(CLOCK_PORT) != "__VIRTUAL_CLK__" && $::env(CLOCK_PORT) != "" } { @@ -115,25 +130,22 @@ if { $::env(CLOCK_PORT) != "__VIRTUAL_CLK__" && $::env(CLOCK_PORT) != "" } { puts "\n===========================================================================" puts " report_clock_skew" puts "============================================================================" - report_clock_skew + foreach corner [sta::corners] { + puts "\n======================= [$corner name] Corner ===================================\n" + report_clock_skew -corner [$corner name] + } puts "clock_skew_end" } -# This segfaults sometimes. -if { $::env(STA_REPORT_POWER) } { - puts "power_report" - puts "\n===========================================================================" - puts " report_power" - puts "============================================================================" - report_power - puts "power_report_end" -} - -puts "area_report" +puts "power_report" puts "\n===========================================================================" -puts " report_design_area" +puts " report_power" puts "============================================================================" -report_design_area -puts "area_report_end" +foreach corner [sta::corners] { + puts "\n======================= [$corner name] Corner ===================================\n" + report_power -corner [$corner name] +} +puts "power_report_end" -write + +write -no_global_connect diff --git a/scripts/openroad/sta_multi_corner.tcl b/scripts/openroad/sta_multi_corner.tcl deleted file mode 100755 index 3d16f06a..00000000 --- a/scripts/openroad/sta_multi_corner.tcl +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright 2020-2022 Efabless Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -source $::env(SCRIPTS_DIR)/openroad/common/io.tcl - -read -multi_corner_libs - -set_cmd_units -time ns -capacitance pF -current mA -voltage V -resistance kOhm -distance um - -# Read parasitics if they are generated prior to this point -if { [info exists ::env(CURRENT_SPEF)] } { - read_spef -corner ss $::env(CURRENT_SPEF) - read_spef -corner tt $::env(CURRENT_SPEF) - read_spef -corner ff $::env(CURRENT_SPEF) -} - -if { $::env(STA_PRE_CTS) == 1 } { - unset_propagated_clock [all_clocks] -} else { - set_propagated_clock [all_clocks] -} - -puts "min_report" -puts "\n===========================================================================" -puts "report_checks -path_delay min (Hold)" -puts "============================================================================" -puts "\n======================= Slowest Corner ===================================\n" -report_checks -path_delay min -fields {slew cap input nets fanout} -format full_clock_expanded -group_count 1000 -corner ss -puts "\n======================= Typical Corner ===================================\n" -report_checks -path_delay min -fields {slew cap input nets fanout} -format full_clock_expanded -group_count 1000 -corner tt -puts "\n======================= Fastest Corner ===================================\n" -report_checks -path_delay min -fields {slew cap input nets fanout} -format full_clock_expanded -group_count 1000 -corner ff -puts "min_report_end" - - -puts "max_report" -puts "\n===========================================================================" -puts "report_checks -path_delay max (Setup)" -puts "============================================================================" -puts "\n======================= Slowest Corner ===================================\n" -report_checks -path_delay max -fields {slew cap input nets fanout} -format full_clock_expanded -group_count 1000 -corner ss -puts "\n======================= Typical Corner ===================================\n" -report_checks -path_delay max -fields {slew cap input nets fanout} -format full_clock_expanded -group_count 1000 -corner tt -puts "\n======================= Fastest Corner ===================================\n" -report_checks -path_delay max -fields {slew cap input nets fanout} -format full_clock_expanded -group_count 1000 -corner ff -puts "max_report_end" - - -puts "check_report" -puts "\n===========================================================================" -puts "report_checks -unconstrained" -puts "============================================================================" -puts "\n======================= Slowest Corner ===================================\n" -report_checks -unconstrained -fields {slew cap input nets fanout} -format full_clock_expanded -corner ss -puts "\n======================= Typical Corner ===================================\n" -report_checks -unconstrained -fields {slew cap input nets fanout} -format full_clock_expanded -corner tt -puts "\n======================= Fastest Corner ===================================\n" -report_checks -unconstrained -fields {slew cap input nets fanout} -format full_clock_expanded -corner ff - - -puts "\n===========================================================================" -puts "report_checks --slack_max -0.01" -puts "============================================================================" -puts "\n======================= Slowest Corner ===================================\n" -report_checks -slack_max -0.01 -fields {slew cap input nets fanout} -format full_clock_expanded -corner ss -puts "\n======================= Typical Corner ===================================\n" -report_checks -slack_max -0.01 -fields {slew cap input nets fanout} -format full_clock_expanded -corner tt -puts "\n======================= Fastest Corner ===================================\n" -report_checks -slack_max -0.01 -fields {slew cap input nets fanout} -format full_clock_expanded -corner ff -puts "check_report_end" - -puts "parastic_annotation_check" -puts "\n===========================================================================" -puts "report_parasitic_annotation -report_unannotated" -puts "============================================================================" -report_parasitic_annotation -report_unannotated -puts "parastic_annotation_check_end" - -puts "check_slew" -puts "\n===========================================================================" -puts " report_check_types -max_slew -max_cap -max_fanout -violators" -puts "============================================================================" -puts "\n======================= Slowest Corner ===================================\n" -report_check_types -max_slew -max_capacitance -max_fanout -violators -corner ss -puts "\n======================= Typical Corner ===================================\n" -report_check_types -max_slew -max_capacitance -max_fanout -violators -corner tt -puts "\n======================= Fastest Corner ===================================\n" -report_check_types -max_slew -max_capacitance -max_fanout -violators -corner ff - -puts "\n===========================================================================" -puts "max slew violation count [sta::max_slew_violation_count]" -puts "max fanout violation count [sta::max_fanout_violation_count]" -puts "max cap violation count [sta::max_capacitance_violation_count]" -puts "============================================================================" -puts "check_slew_end" - -puts "tns_report" -puts "\n===========================================================================" -puts " report_tns" -puts "============================================================================" -report_tns -puts "tns_report_end" - -puts "wns_report" -puts "\n===========================================================================" -puts " report_wns" -puts "============================================================================" -report_wns -puts "wns_report_end" - - -puts "worst_slack" -puts "\n===========================================================================" -puts " report_worst_slack -max (Setup)" -puts "============================================================================" -report_worst_slack -max - -puts "\n===========================================================================" -puts " report_worst_slack -min (Hold)" -puts "============================================================================" -report_worst_slack -min -puts "worst_slack_end" - - -# report clock skew if the clock port is defined -# OR hangs if this command is run on clockless designs -if { $::env(CLOCK_PORT) != "__VIRTUAL_CLK__" && $::env(CLOCK_PORT) != "" } { - puts "clock_skew" - puts "\n===========================================================================" - puts " report_clock_skew" - puts "============================================================================" - puts "\n======================== Slowest Corner ==================================\n" - report_clock_skew -corner ss - puts "\n======================= Typical Corner ===================================\n" - report_clock_skew -corner tt - puts "\n======================= Fastest Corner ===================================\n" - report_clock_skew -corner ff - puts "clock_skew_end" -} - -puts "power_report" -puts "\n===========================================================================" -puts " report_power" -puts "============================================================================" -puts "\n\n======================= Slowest Corner =================================\n" -report_power -corner ss -puts "\n======================= Typical Corner ===================================\n" -report_power -corner tt -puts "\n\n======================= Fastest Corner =================================\n" -report_power -corner ff -puts "power_report_end" - - -puts "area_report" -puts "\n===========================================================================" -puts " report_design_area" -puts "============================================================================" -report_design_area -puts "area_report_end" - -write diff --git a/scripts/or_issue.py b/scripts/or_issue.py index cb5935ed..ba3455f8 100755 --- a/scripts/or_issue.py +++ b/scripts/or_issue.py @@ -85,7 +85,7 @@ ws = re.compile(r"\s+") @click.option("--output-dir", default=None, help="Output to this directory.") @click.option( "--tool", - type=click.Choice(["openroad", "magic", "yosys"]), + type=click.Choice(["sta", "openroad", "magic", "yosys"]), help="The tool used for the desired Tcl script. [required]", ) @click.argument("input_file") @@ -363,6 +363,8 @@ def issue( run_cmd = "$TOOL_BIN -exit $PACKAGED_SCRIPT_0" elif tool == "magic": run_cmd = "$TOOL_BIN -dnull -noconsole -rcfile $MAGIC_MAGICRC < $PACKAGED_SCRIPT_0" + elif tool == "sta": + run_cmd = "$TOOL_BIN -exit $PACKAGED_SCRIPT_0" elif tool == "yosys": run_cmd = "$TOOL_BIN -c $PACKAGED_SCRIPT_0" f.write( diff --git a/scripts/report/report.py b/scripts/report/report.py index 53ef89fd..2060c55e 100755 --- a/scripts/report/report.py +++ b/scripts/report/report.py @@ -255,7 +255,6 @@ class Report(object): ("_sta.worst_slack.rpt", "worst_slack"), ("_sta.clock_skew.rpt", "clock_skew"), ("_sta.power.rpt", "power_report"), - ("_sta.area.rpt", "area_report"), ] for name, log in [ diff --git a/scripts/tcl_commands/all.tcl b/scripts/tcl_commands/all.tcl index fc33677f..f671aade 100755 --- a/scripts/tcl_commands/all.tcl +++ b/scripts/tcl_commands/all.tcl @@ -889,6 +889,18 @@ proc prep {args} { assert_files_exist "$::env(EXTRA_GDS_FILES)" } + if { [info exists ::env(VERILOG_STA_NETLISTS)] } { + puts_verbose "Verifying existence of files defined in ::env(VERILOG_STA_NETLISTS)..." + assert_files_exist "$::env(VERILOG_STA_NETLISTS)" + } + + if { [info exists ::env(EXTRA_SPEFS)] } { + if { [expr [llength $::env(EXTRA_SPEFS)] % 4] != 0 } { + puts_err "Please define EXTRA_SPEFS correctly. i.e. : ..." + flow_fail + } + } + TIMER::timer_stop exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "openlane design prep" return -code ok @@ -1051,8 +1063,8 @@ proc save_views {args} { if { [info exists arg_values(-mc_spef_dir)] } { set destination $path/spef/multicorner if { [file exists $arg_values(-mc_spef_dir)] } { - file delete -force $destination - file copy -force $arg_values(-mc_spef_dir) $destination + file mkdir $destination + file copy -force {*}[glob $arg_values(-mc_spef_dir)/*] $destination } } diff --git a/scripts/tcl_commands/cts.tcl b/scripts/tcl_commands/cts.tcl index 665c9116..08b88be3 100755 --- a/scripts/tcl_commands/cts.tcl +++ b/scripts/tcl_commands/cts.tcl @@ -46,6 +46,10 @@ proc run_cts {args} { exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "cts - openroad" scrot_klayout -layout $::env(CURRENT_DEF) -log $::env(cts_logs)/screenshot.log + + if { [info exists ::env(CTS_REPORT_TIMING)] && $::env(CTS_REPORT_TIMING) } { + run_sta -no_save $::env(cts_results) -log $::env(cts_logs)/sta.log + } } } diff --git a/scripts/tcl_commands/placement.tcl b/scripts/tcl_commands/placement.tcl index 01251485..bc800d79 100755 --- a/scripts/tcl_commands/placement.tcl +++ b/scripts/tcl_commands/placement.tcl @@ -25,12 +25,14 @@ proc global_placement_or {args} { run_openroad_script $::env(SCRIPTS_DIR)/openroad/gpl.tcl\ -indexed_log [index_file $::env(placement_logs)/global.log]\ - -save "to=$::env(placement_tmpfiles),name=global,def,odb" + -save "to=$::env(placement_tmpfiles),name=global,def,odb,netlist,powered_netlist" check_replace_divergence TIMER::timer_stop exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "global placement - openroad" + + run_sta -no_save -log $::env(placement_logs)/sta-global.log } proc global_placement {args} { @@ -189,6 +191,7 @@ proc run_placement {args} { detailed_placement_or scrot_klayout -layout $::env(CURRENT_DEF) -log $::env(placement_logs)/screenshot.log + run_sta -no_save -log $::env(placement_logs)/sta.log } proc run_resizer_design {args} { diff --git a/scripts/tcl_commands/routing.tcl b/scripts/tcl_commands/routing.tcl index 98488768..189dc577 100755 --- a/scripts/tcl_commands/routing.tcl +++ b/scripts/tcl_commands/routing.tcl @@ -100,6 +100,7 @@ proc global_routing_fastroute {args} { -indexed_log [index_file $::env(routing_logs)/global_write_netlist.log] TIMER::timer_stop + run_sta -no_save -log $::env(routing_logs)/sta-groute.log exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "global routing - openroad" } @@ -418,7 +419,6 @@ proc run_routing {args} { #legalize if not yet legalized - global_routing if { $::env(RUN_FILL_INSERTION) } { @@ -453,7 +453,7 @@ proc run_resizer_design_routing {args} { TIMER::timer_stop exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "resizer design optimizations - openroad" - + run_sta -no_save -log $::env(routing_logs)/sta-resizer_design.log } else { puts_info "Skipping Global Routing Resizer Design Optimizations." } @@ -472,7 +472,7 @@ proc run_resizer_timing_routing {args} { TIMER::timer_stop exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "resizer timing optimizations - openroad" - + run_sta -no_save -log $::env(routing_logs)/sta-resizer_timing.log } else { puts_info "Skipping Global Routing Resizer Timing Optimizations." } diff --git a/scripts/tcl_commands/sta.tcl b/scripts/tcl_commands/sta.tcl index 3d7b4594..5b21be91 100644 --- a/scripts/tcl_commands/sta.tcl +++ b/scripts/tcl_commands/sta.tcl @@ -27,6 +27,8 @@ proc run_sta {args} { -multi_corner -pre_cts -netlist_in + -blackbox_check + -no_save } parse_key_args "run_sta" args arg_values $options flags_map $flags @@ -60,13 +62,28 @@ proc run_sta {args} { set arg_list [list] lappend arg_list -indexed_log $log - lappend arg_list -save "to=$arg_values(-save_to),noindex,sdf,$lib_option" + if { ![info exist flags_map(-no_save)] } { + lappend arg_list -save "to=$arg_values(-save_to),noindex,sdf,$lib_option" + } if { [info exists flags_map(-netlist_in)] } { lappend arg_list -netlist_in } + proc blackbox_modules_check {file_path} { + set fp [open $file_path r] + set file_path [read $fp] + foreach line [split $file_path "\n"] { + if { [regexp {module\s+(\S+)\s+not\s+found} $line match first_group] } { + puts_warn "Module $first_group blackboxed during sta" + } + } + close $fp + } + + set ::env(STA_MULTICORNER) 0 if { $multi_corner == 1 } { - run_openroad_script $::env(SCRIPTS_DIR)/openroad/sta_multi_corner.tcl \ + set ::env(STA_MULTICORNER) 1 + run_sta_script $::env(SCRIPTS_DIR)/openroad/sta/multi_corner.tcl \ -no_update_current\ {*}$arg_list @@ -75,12 +92,17 @@ proc run_sta {args} { } unset ::env(SAVE_SDF) } else { - run_openroad_script $::env(SCRIPTS_DIR)/openroad/sta.tcl {*}$arg_list + run_sta_script $::env(SCRIPTS_DIR)/openroad/sta/multi_corner.tcl {*}$arg_list + if { [info exists flags_map(-blackbox_check)] } { + blackbox_modules_check $log + } } + unset ::env(STA_MULTICORNER) TIMER::timer_stop exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "sta - openroad" } + proc run_parasitics_sta {args} { set options { {-out_directory optional} @@ -137,7 +159,8 @@ proc run_parasitics_sta {args} { run_sta\ -log $::env(signoff_logs)/rcx_sta.log\ -process_corner $process_corner\ - -save_to $directory + -save_to $directory \ + -blackbox_check set ::env(LAST_TIMING_REPORT_TAG) [index_file $::env(signoff_reports)/rcx_sta] } diff --git a/scripts/utils/utils.tcl b/scripts/utils/utils.tcl index ee049515..561f7226 100755 --- a/scripts/utils/utils.tcl +++ b/scripts/utils/utils.tcl @@ -221,6 +221,10 @@ proc run_openroad_script {args} { run_tcl_script -tool openroad -no_consume {*}$args } +proc run_sta_script {args} { + run_tcl_script -tool sta -no_consume {*}$args +} + proc run_magic_script {args} { run_tcl_script -tool magic -no_consume {*}$args } @@ -621,8 +625,14 @@ proc run_tcl_script {args} { set args "magic -noconsole -dnull -rcfile $::env(MAGIC_MAGICRC) < $script |& tee $::env(TERMINAL_OUTPUT) $arg_values(-indexed_log)" } elseif { $arg_values(-tool) == "yosys" } { set args "$::env(SYNTH_BIN) -c $script |& tee $::env(TERMINAL_OUTPUT) $arg_values(-indexed_log)" + } elseif { $arg_values(-tool) == "sta" } { + set args "sta -exit -no_init $script |& tee $::env(TERMINAL_OUTPUT) $arg_values(-indexed_log)" + foreach {element value} $save_list { + set cap [string toupper $element] + set ::env(SAVE_${cap}) $value + } } else { - puts_err "run_tcl_script only supports tools 'magic', 'yosys' or 'openroad' for now." + puts_err "run_tcl_script only supports tools 'magic', 'yosys', 'sta', or 'openroad' for now." throw_error } @@ -685,6 +695,8 @@ proc run_tcl_script {args} { lappend or_issue_arg_list --input-type "netlist" $::env(CURRENT_NETLIST) } elseif { $tool != "openroad" || [info exists flag_map(-def_in)]} { lappend or_issue_arg_list --input-type "def" $::env(CURRENT_DEF) + } elseif { $tool != "sta" } { + lappend or_issue_arg_list --input-type "netlist" $::env(CURRENT_NETLIST) } else { lappend or_issue_arg_list --input-type "odb" $::env(CURRENT_ODB) } @@ -730,5 +742,4 @@ proc run_tcl_script {args} { } } - package provide openlane_utils 0.9