diff --git a/docs/contrib/EndpointSlackTracking.md b/docs/contrib/EndpointSlackTracking.md index ef9a30a27e..1bab138900 100644 --- a/docs/contrib/EndpointSlackTracking.md +++ b/docs/contrib/EndpointSlackTracking.md @@ -27,19 +27,21 @@ cells) re-time the design if it is loaded, or else copy the previous step's snapshot. Intermediate `.odb` files written through `orfs_write_db` (e.g. CTS `save_progress`) also get a snapshot; `*-failed` ones don't. -So that all steps are timed the same way, parasitics are estimated before -reporting as in `open.tcl`, based on the step number: +A placed step is timed with the parasitics OpenROAD has for it: a bare +`estimate_parasitics` estimates from the global routes when there are any, +else from placement, and does nothing once `read_spef` has read the +extracted parasitics: | Steps | Parasitics | | --- | --- | -| 1, 2 | none (cells are not placed) | -| 3, 4 | `estimate_parasitics -placement` | -| 5, `6_1_fill` | `estimate_parasitics -global_routing` if global routes exist | -| `6_final` | `rcx`: the extracted `6_final.spef`, as in `6_finish.rpt` (`global_routing` on platforms without `RCX_RULES`) | +| before placement, and `3_1_place_gp_skip_io` while the pins are unplaced | `none` | +| placed, before global route | `placement` | +| global route and later | `global_routing` | +| `6_final` | `spef`: the extracted `6_final.spef`, as in `6_finish.rpt` (`global_routing` on platforms without `RCX_RULES`, or with `SKIP_DETAILED_ROUTE=1`) | The parasitics model is recorded in each snapshot and shown by `endpointSlack.py`. Slack changes between steps with different models (e.g. -`2_4_floorplan_pdn` to `3_1_place_gp_skip_io`, `4_1_cts` to `5_1_grt`, or +`2_4_floorplan_pdn` to the first placed step, `4_1_cts` to `5_1_grt`, or `6_1_fill` to `6_final`) include the change of model. Detailed routing is only extracted in `6_final`, so `5_2_route` to `6_1_fill` show global routing estimates. diff --git a/docs/user/FlowVariables.md b/docs/user/FlowVariables.md index b1339b4928..3f7073ee14 100644 --- a/docs/user/FlowVariables.md +++ b/docs/user/FlowVariables.md @@ -654,6 +654,7 @@ configuration file. ## generate_abstract variables - [ABSTRACT_SOURCE](#ABSTRACT_SOURCE) +- [SKIP_DETAILED_ROUTE](#SKIP_DETAILED_ROUTE) ## Uncategorized variables diff --git a/flow/Makefile b/flow/Makefile index 759e13578d..f8d18fe5a6 100644 --- a/flow/Makefile +++ b/flow/Makefile @@ -694,6 +694,10 @@ $(RESULTS_DIR)/6_final.sdc: $(LOG_DIR)/6_report.log $(RESULTS_DIR)/6_final.def: $(LOG_DIR)/6_report.log +# Written only when final extracts parasitics (RCX_RULES set, detailed +# route not skipped); generate_abstract reads it in that case. +$(RESULTS_DIR)/6_final.spef: $(LOG_DIR)/6_report.log + # The final results are called 6_final.*, so it is convenient when scripting # to have the names of the artifacts match the name of the target .PHONY: do-final @@ -707,7 +711,7 @@ do-finish: $(UNSET_AND_MAKE) do-6_1_fill do-6_1_fill.sdc do-6_report elapsed .PHONY: generate_abstract -generate_abstract: $(RESULTS_DIR)/6_final.gds $(RESULTS_DIR)/6_final.def $(RESULTS_DIR)/6_final.v $(RESULTS_DIR)/6_final.sdc +generate_abstract: $(RESULTS_DIR)/6_final.gds $(RESULTS_DIR)/6_final.def $(RESULTS_DIR)/6_final.v $(RESULTS_DIR)/6_final.sdc $(RESULTS_DIR)/6_final.spef $(UNSET_AND_MAKE) do-generate_abstract # Set ABSTRACT_SOURCE if you want to create an abstract from another stage than 6_final. diff --git a/flow/scripts/cts.tcl b/flow/scripts/cts.tcl index e90c6f0698..7439569d12 100644 --- a/flow/scripts/cts.tcl +++ b/flow/scripts/cts.tcl @@ -36,7 +36,7 @@ set_dont_use $::env(DONT_USE_CELLS) log_cmd clock_tree_synthesis {*}$cts_args utl::push_metrics_stage "cts__{}__pre_repair_timing" -log_cmd estimate_parasitics -placement +log_cmd estimate_parasitics if { $::env(DETAILED_METRICS) } { report_metrics 4 "cts pre-repair-timing" } @@ -52,7 +52,7 @@ if { $result != 0 } { error "Detailed placement failed in CTS: $msg" } -log_cmd estimate_parasitics -placement +log_cmd estimate_parasitics if { $::env(CTS_SNAPSHOTS) } { save_progress 4_1_pre_repair_setup_hold @@ -79,7 +79,7 @@ if { !$::env(SKIP_CTS_REPAIR_TIMING) } { log_cmd check_placement -placeable -verbose - log_cmd estimate_parasitics -placement + log_cmd estimate_parasitics } report_metrics 4 "cts final" diff --git a/flow/scripts/detail_place.tcl b/flow/scripts/detail_place.tcl index 20aee94c3a..6a4216f717 100644 --- a/flow/scripts/detail_place.tcl +++ b/flow/scripts/detail_place.tcl @@ -26,7 +26,7 @@ proc do_dpl { } { utl::info FLW 12 "Placement violations [check_placement -placeable -verbose]." - log_cmd estimate_parasitics -placement + log_cmd estimate_parasitics } set result [catch { do_dpl } errMsg] diff --git a/flow/scripts/final_outputs.tcl b/flow/scripts/final_outputs.tcl index 520b9d0374..2b14224ea6 100644 --- a/flow/scripts/final_outputs.tcl +++ b/flow/scripts/final_outputs.tcl @@ -20,10 +20,7 @@ if { $::env(SEC_CHECK) } { } # Run extraction and STA -if { - [env_var_exists_and_non_empty RCX_RULES] - && !$::env(SKIP_DETAILED_ROUTE) -} { +if { [final_extracts_parasitics] } { # RCX section define_process_corner -ext_model_index 0 X set_extraction_rules_file $::env(RCX_RULES) @@ -35,7 +32,6 @@ if { # Read Spef for OpenSTA read_spef $::env(RESULTS_DIR)/6_final.spef - set final_parasitics rcx # Static IR drop analysis if { [env_var_exists_and_non_empty PWR_NETS_VOLTAGES] } { @@ -57,12 +53,10 @@ if { puts "IR drop analysis for ground nets is skipped because GND_NETS_VOLTAGES is undefined" } } else { - puts "OpenRCX is not enabled for this platform." - puts "Falling back to global route-based estimates." - log_cmd estimate_parasitics -global_routing - set final_parasitics global_routing + puts "OpenRCX is not enabled for this platform or detailed route was skipped." + log_cmd estimate_parasitics } -write_endpoint_slack 6_final $final_parasitics +write_endpoint_slack 6_final 0 report_cell_usage diff --git a/flow/scripts/generate_abstract.tcl b/flow/scripts/generate_abstract.tcl index 7b6ec30cbd..733a2df7e1 100644 --- a/flow/scripts/generate_abstract.tcl +++ b/flow/scripts/generate_abstract.tcl @@ -13,13 +13,7 @@ set sdc_file [lindex $result 1] log_cmd load_design $stem.odb [file tail $sdc_file] -if { $design_stage >= 6 && [file exists $::env(RESULTS_DIR)/$stem.spef] } { - log_cmd read_spef $::env(RESULTS_DIR)/$stem.spef -} elseif { $design_stage >= 5 } { - log_cmd estimate_parasitics -global_routing -} elseif { $design_stage >= 3 } { - log_cmd estimate_parasitics -placement -} +orfs_load_parasitics $stem if { $design_stage >= 4 } { set_propagated_clock [all_clocks] diff --git a/flow/scripts/global_place.tcl b/flow/scripts/global_place.tcl index 6a2d583d26..4a125954e2 100644 --- a/flow/scripts/global_place.tcl +++ b/flow/scripts/global_place.tcl @@ -77,11 +77,11 @@ if { $result != 0 } { error $errMsg } -log_cmd estimate_parasitics -placement +log_cmd estimate_parasitics if { $::env(CLUSTER_FLOPS) } { log_cmd cluster_flops {*}[env_var_or_empty CLUSTER_FLOPS_ARGS] - log_cmd estimate_parasitics -placement + log_cmd estimate_parasitics } report_metrics 3 "global place" false false diff --git a/flow/scripts/global_route.tcl b/flow/scripts/global_route.tcl index fb9d41945f..c504826cc9 100644 --- a/flow/scripts/global_route.tcl +++ b/flow/scripts/global_route.tcl @@ -39,7 +39,8 @@ proc global_route_helper { } { error $errMsg } orfs_write_sdc $::env(RESULTS_DIR)/5_1_grt.sdc - orfs_write_db $::env(RESULTS_DIR)/5_1_grt.odb + # A route that failed has no parasitics to time the endpoints with. + orfs_write_db $::env(RESULTS_DIR)/5_1_grt.odb 0 return 0 } return 1 @@ -74,7 +75,7 @@ proc global_route_helper { } { -right $::env(CELL_PAD_IN_SITES_DETAIL_PLACEMENT) set_propagated_clock [all_clocks] - log_cmd estimate_parasitics -global_routing + log_cmd estimate_parasitics if { [env_var_exists_and_non_empty DONT_USE_CELLS] } { set_dont_use $::env(DONT_USE_CELLS) @@ -106,7 +107,7 @@ proc global_route_helper { } { # Repair timing using global route parasitics puts "Repair setup and hold violations..." - log_cmd estimate_parasitics -global_routing + log_cmd estimate_parasitics repair_timing_helper @@ -126,7 +127,7 @@ proc global_route_helper { } { return } - log_cmd estimate_parasitics -global_routing + log_cmd estimate_parasitics if { $::env(OPT_POST_GRT_WNS) } { set repair_timing_args \ @@ -171,7 +172,7 @@ proc global_route_helper { } { } puts "Estimate parasitics..." - log_cmd estimate_parasitics -global_routing + log_cmd estimate_parasitics report_metrics 5 "global route" diff --git a/flow/scripts/open.tcl b/flow/scripts/open.tcl index c8061687ab..dc490e790e 100644 --- a/flow/scripts/open.tcl +++ b/flow/scripts/open.tcl @@ -59,17 +59,7 @@ proc read_timing { input_file } { set_propagated_clock [all_clocks] } - if { $design_stage >= 6 && [file exist $::env(RESULTS_DIR)/6_final.spef] } { - log_cmd read_spef $::env(RESULTS_DIR)/6_final.spef - } elseif { $design_stage >= 5 } { - if { [log_cmd grt::have_routes] } { - log_cmd estimate_parasitics -global_routing - } else { - puts "No global routing results available, skipping estimate_parasitics" - } - } elseif { $design_stage >= 3 } { - log_cmd estimate_parasitics -placement - } + orfs_load_parasitics [file rootname [file tail $input_file]] # Warm up OpenSTA, so clicking on timing related buttons reacts faster set _tmp [log_cmd sta::find_timing] diff --git a/flow/scripts/resize.tcl b/flow/scripts/resize.tcl index e46ac4b328..fa8a26da3d 100644 --- a/flow/scripts/resize.tcl +++ b/flow/scripts/resize.tcl @@ -4,7 +4,7 @@ erase_non_stage_variables place load_design 3_3_place_gp.odb 2_floorplan.sdc source_step_tcl PRE RESIZE -log_cmd estimate_parasitics -placement +log_cmd estimate_parasitics set instance_count_before [sta::network_leaf_instance_count] set pin_count_before [sta::network_leaf_pin_count] @@ -28,7 +28,7 @@ repair_design_helper if { $::env(ENABLE_PLACE_REPAIR_TIMING) } { # Repair timing using placement parasitics. puts "Repair setup and hold violations..." - log_cmd estimate_parasitics -placement + log_cmd estimate_parasitics repair_timing_helper } diff --git a/flow/scripts/util.tcl b/flow/scripts/util.tcl index 293572e39e..90d7376dc1 100644 --- a/flow/scripts/util.tcl +++ b/flow/scripts/util.tcl @@ -345,32 +345,46 @@ proc endpoint_slack_file { step } { return $::env(REPORTS_DIR)/${step}_endpoint_slack.json } +# The final stage extracts parasitics into 6_final.spef when the platform +# has OpenRCX rules and the design is detail routed. 6_final.odb is timed +# with that SPEF; whether a .spef file exists says nothing. +proc final_extracts_parasitics { } { + return [expr { + [env_var_exists_and_non_empty RCX_RULES] + && !$::env(SKIP_DETAILED_ROUTE) + }] +} + +# Load the parasitics that step is timed with and return where they came +# from: the extracted 6_final.spef when final writes one, else, once the +# design is placed, what OpenROAD estimates (global routes if there are +# any, else placement), else none. +proc orfs_load_parasitics { step } { + if { $step == "6_final" && [final_extracts_parasitics] } { + log_cmd read_spef $::env(RESULTS_DIR)/6_final.spef + } elseif { [grt::design_is_placed] } { + log_cmd estimate_parasitics + } else { + return none + } + return [est::parasitics_source] +} + # Write the setup and hold slack of every endpoint at the end of a flow # step so they can be compared across steps with -# flow/util/endpointSlack.py. Parasitics are estimated the same way as -# open.tcl so that every step is timed consistently, unless the caller -# has already loaded parasitics (e.g. extracted ones) and passes their -# name as parasitics. -proc write_endpoint_slack { step { parasitics "" } } { +# flow/util/endpointSlack.py. load_parasitics 0 is for a caller that has +# just loaded the parasitics itself, e.g. 6_final after extraction. +proc write_endpoint_slack { step { load_parasitics 1 } } { if { !$::env(REPORT_ENDPOINT_SLACK) || [string match "*-failed" $step] } { return } set filename [endpoint_slack_file $step] puts "Writing endpoint slack to $filename" - if { $parasitics == "" } { - set design_stage [lindex [split $step _] 0] - set parasitics none - if { $design_stage >= 5 } { - if { [grt::have_routes] } { - set parasitics global_routing - } - } elseif { $design_stage >= 3 } { - set parasitics placement - } - if { $parasitics != "none" } { - estimate_parasitics -$parasitics - } + if { $load_parasitics } { + set parasitics [orfs_load_parasitics $step] + } else { + set parasitics [est::parasitics_source] } # Update timing before sta::endpoints: the endpoint set is cached the # first time it is requested and misses gated clock enable checks if the diff --git a/flow/scripts/variables.json b/flow/scripts/variables.json index 50c1517476..e9faf2a802 100644 --- a/flow/scripts/variables.json +++ b/flow/scripts/variables.json @@ -1222,7 +1222,8 @@ "description": "Skips detailed route.\n", "stages": [ "route", - "final" + "final", + "generate_abstract" ] }, "SKIP_FLOORPLAN_REPAIR_TIMING": { diff --git a/flow/scripts/variables.yaml b/flow/scripts/variables.yaml index 2cd82356fd..acd66dfeb3 100644 --- a/flow/scripts/variables.yaml +++ b/flow/scripts/variables.yaml @@ -1634,6 +1634,7 @@ SKIP_DETAILED_ROUTE: stages: - route - final + - generate_abstract MAX_REPAIR_ANTENNAS_ITER_DRT: default: 5 description: >