From 2447d20128b1d9f8830d3326de26d66cedabfa63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Fri, 16 Oct 2026 13:44:18 +0200 Subject: [PATCH 1/4] flow: OpenROAD picks the parasitics, the flow says when MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flow decided which parasitics to time with in four places, open.tcl, generate_abstract.tcl, write_endpoint_slack and final_outputs.tcl, from the stage number, grt::have_routes and whether a .spef file exists. A file on disk says nothing about whether it belongs to the design being timed: re-running a flow from place or global route leaves the previous final's SPEF in the results directory. estimate_parasitics without a flag now picks the source itself: global routes when there are any, else placement, nothing after read_spef. The stage scripts call it bare, under log_cmd, where they want to pay for an estimate. 6_final is timed with 6_final.spef when the final stage extracted it, which final_extracts_parasitics says from RCX_RULES and SKIP_DETAILED_ROUTE; read_spef fails if the file is missing. A placed design is timed with parasitics, a design before placement without. Changes in behavior: - With RCX configured, a missing 6_final.spef fails open and generate_abstract instead of falling back to an estimate. - A global route that is congested and was not accepted fails estimate_parasitics instead of timing without parasitics; open with GUI_TIMING=0 to look at it. A failed route written with GENERATE_ARTIFACTS_ON_FAILURE gets no endpoint slack snapshot. - generate_abstract from global route or later is timed with global route parasitics instead of placement parasitics. - The endpoint slack snapshot records where OpenROAD's parasitics came from: 6_final says spef instead of rcx, and 3_1_place_gp_skip_io with unplaced pins says none instead of placement. SKIP_DETAILED_ROUTE reaches generate_abstract, which needs it to know whether 6_final has a SPEF. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Øyvind Harboe --- docs/contrib/EndpointSlackTracking.md | 16 ++++++------ docs/user/FlowVariables.md | 1 + flow/scripts/cts.tcl | 6 ++--- flow/scripts/detail_place.tcl | 2 +- flow/scripts/final_outputs.tcl | 14 +++-------- flow/scripts/generate_abstract.tcl | 9 ++++--- flow/scripts/global_place.tcl | 4 +-- flow/scripts/global_route.tcl | 11 +++++---- flow/scripts/open.tcl | 16 ++++++------ flow/scripts/resize.tcl | 4 +-- flow/scripts/util.tcl | 35 ++++++++++++--------------- flow/scripts/variables.json | 3 ++- flow/scripts/variables.yaml | 1 + 13 files changed, 59 insertions(+), 63 deletions(-) diff --git a/docs/contrib/EndpointSlackTracking.md b/docs/contrib/EndpointSlackTracking.md index ef9a30a27e..2d8efb5209 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`) | 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 4faa3cf80c..cd88ca4c9e 100644 --- a/docs/user/FlowVariables.md +++ b/docs/user/FlowVariables.md @@ -639,6 +639,7 @@ configuration file. ## generate_abstract variables - [ABSTRACT_SOURCE](#ABSTRACT_SOURCE) +- [SKIP_DETAILED_ROUTE](#SKIP_DETAILED_ROUTE) ## Uncategorized variables diff --git a/flow/scripts/cts.tcl b/flow/scripts/cts.tcl index 18ebf9c3dd..1886a2eb94 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) } { check_placement -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 b552218cdb..bc08c19ec2 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 -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..99d97a0faa 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 report_cell_usage diff --git a/flow/scripts/generate_abstract.tcl b/flow/scripts/generate_abstract.tcl index 3f860034f5..586e89f7ba 100644 --- a/flow/scripts/generate_abstract.tcl +++ b/flow/scripts/generate_abstract.tcl @@ -13,10 +13,11 @@ 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 >= 3 } { - log_cmd estimate_parasitics -placement +if { $stem == "6_final" && [final_extracts_parasitics] } { + log_cmd read_spef $::env(RESULTS_DIR)/6_final.spef +} +if { [grt::design_is_placed] } { + log_cmd estimate_parasitics } if { $design_stage >= 4 } { diff --git a/flow/scripts/global_place.tcl b/flow/scripts/global_place.tcl index 5822ef47c2..d4889dd12c 100644 --- a/flow/scripts/global_place.tcl +++ b/flow/scripts/global_place.tcl @@ -68,11 +68,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 45f3852f39..677b13f295 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..fdc0ea6f57 100644 --- a/flow/scripts/open.tcl +++ b/flow/scripts/open.tcl @@ -59,16 +59,14 @@ proc read_timing { input_file } { set_propagated_clock [all_clocks] } - if { $design_stage >= 6 && [file exist $::env(RESULTS_DIR)/6_final.spef] } { + if { + [file rootname [file tail $input_file]] == "6_final" + && [final_extracts_parasitics] + } { 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 + } + if { [grt::design_is_placed] } { + log_cmd estimate_parasitics } # Warm up OpenSTA, so clicking on timing related buttons reacts faster 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 49ab5fd80f..5c63b913c7 100644 --- a/flow/scripts/util.tcl +++ b/flow/scripts/util.tcl @@ -306,32 +306,29 @@ 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) + }] +} + # 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. A placed design is timed with the parasitics +# OpenROAD has for it, a design before placement without any. +proc write_endpoint_slack { step } { 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 { [grt::design_is_placed] } { + log_cmd estimate_parasitics } # Update timing before sta::endpoints: the endpoint set is cached the # first time it is requested and misses gated clock enable checks if the @@ -342,7 +339,7 @@ proc write_endpoint_slack { step { parasitics "" } } { puts $fileId "{" puts $fileId "\"design\": \"$::env(DESIGN_NAME)\"," puts $fileId "\"step\": \"$step\"," - puts $fileId "\"parasitics\": \"$parasitics\"," + puts $fileId "\"parasitics\": \"[est::parasitics_source]\"," # Seconds per reported time unit puts $fileId "\"time_unit\": [sta::time_ui_sta 1]," # endpoint: [setup slack, hold slack], null if unconstrained diff --git a/flow/scripts/variables.json b/flow/scripts/variables.json index c79940855c..a6b1be6401 100644 --- a/flow/scripts/variables.json +++ b/flow/scripts/variables.json @@ -1205,7 +1205,8 @@ "description": "Skips detailed route.\n", "stages": [ "route", - "final" + "final", + "generate_abstract" ] }, "SKIP_GATE_CLONING": { diff --git a/flow/scripts/variables.yaml b/flow/scripts/variables.yaml index ac913b71ad..a92c2e14a1 100644 --- a/flow/scripts/variables.yaml +++ b/flow/scripts/variables.yaml @@ -1582,6 +1582,7 @@ SKIP_DETAILED_ROUTE: stages: - route - final + - generate_abstract MAX_REPAIR_ANTENNAS_ITER_DRT: default: 5 description: > From 3da44b6968a5e99df4aea643ede6cd4f52c835d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Tue, 3 Nov 2026 08:36:29 +0100 Subject: [PATCH 2/4] docs: 6_final is timed with global routes when detailed route is skipped MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The endpoint-slack table left out the SKIP_DETAILED_ROUTE=1 fallback that final_extracts_parasitics takes. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Øyvind Harboe --- docs/contrib/EndpointSlackTracking.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contrib/EndpointSlackTracking.md b/docs/contrib/EndpointSlackTracking.md index 2d8efb5209..1bab138900 100644 --- a/docs/contrib/EndpointSlackTracking.md +++ b/docs/contrib/EndpointSlackTracking.md @@ -37,7 +37,7 @@ extracted parasitics: | 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`) | +| `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. From e8398b52c8e2ee6dbe0952f8340917251bc010c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Tue, 3 Nov 2026 08:36:50 +0100 Subject: [PATCH 3/4] flow: generate_abstract declares 6_final.spef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit generate_abstract.tcl reads 6_final.spef when final extracts parasitics, so the target lists it with the other 6_final files. The file is a result of 6_report like 6_final.def; without RCX_RULES, or with detailed route skipped, no SPEF is written and make goes on without it, so the graph stays the same for every design. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Øyvind Harboe --- flow/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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. From 92bda58f19cc571f8675b8a4618ee1965734a670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Tue, 3 Nov 2026 08:37:47 +0100 Subject: [PATCH 4/4] flow: one proc loads the parasitics a stage is timed with MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit open.tcl, generate_abstract.tcl and write_endpoint_slack each had the same two tests: read 6_final.spef when final extracts parasitics, and estimate when the design is placed. orfs_load_parasitics in util.tcl now holds them, as one if/elseif: a design timed with the extracted SPEF is never also estimated. orfs_load_parasitics returns where the parasitics came from, and the endpoint-slack snapshot records that, so the label always describes the parasitics the snapshot was timed with. est::parasitics_source on its own reported the last estimate in the process, which is stale for a step that does not estimate. final_outputs.tcl loads its parasitics itself, by extraction or by an estimate, and now tells write_endpoint_slack not to load them again. Without RCX_RULES, 6_final was estimated twice in a row. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Øyvind Harboe --- flow/scripts/final_outputs.tcl | 2 +- flow/scripts/generate_abstract.tcl | 7 +------ flow/scripts/open.tcl | 10 +--------- flow/scripts/util.tcl | 29 +++++++++++++++++++++++------ 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/flow/scripts/final_outputs.tcl b/flow/scripts/final_outputs.tcl index 99d97a0faa..2b14224ea6 100644 --- a/flow/scripts/final_outputs.tcl +++ b/flow/scripts/final_outputs.tcl @@ -56,7 +56,7 @@ if { [final_extracts_parasitics] } { puts "OpenRCX is not enabled for this platform or detailed route was skipped." log_cmd estimate_parasitics } -write_endpoint_slack 6_final +write_endpoint_slack 6_final 0 report_cell_usage diff --git a/flow/scripts/generate_abstract.tcl b/flow/scripts/generate_abstract.tcl index 586e89f7ba..733a2df7e1 100644 --- a/flow/scripts/generate_abstract.tcl +++ b/flow/scripts/generate_abstract.tcl @@ -13,12 +13,7 @@ set sdc_file [lindex $result 1] log_cmd load_design $stem.odb [file tail $sdc_file] -if { $stem == "6_final" && [final_extracts_parasitics] } { - log_cmd read_spef $::env(RESULTS_DIR)/6_final.spef -} -if { [grt::design_is_placed] } { - log_cmd estimate_parasitics -} +orfs_load_parasitics $stem if { $design_stage >= 4 } { set_propagated_clock [all_clocks] diff --git a/flow/scripts/open.tcl b/flow/scripts/open.tcl index fdc0ea6f57..dc490e790e 100644 --- a/flow/scripts/open.tcl +++ b/flow/scripts/open.tcl @@ -59,15 +59,7 @@ proc read_timing { input_file } { set_propagated_clock [all_clocks] } - if { - [file rootname [file tail $input_file]] == "6_final" - && [final_extracts_parasitics] - } { - log_cmd read_spef $::env(RESULTS_DIR)/6_final.spef - } - if { [grt::design_is_placed] } { - log_cmd estimate_parasitics - } + 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/util.tcl b/flow/scripts/util.tcl index 91deac978c..90d7376dc1 100644 --- a/flow/scripts/util.tcl +++ b/flow/scripts/util.tcl @@ -355,19 +355,36 @@ proc final_extracts_parasitics { } { }] } +# 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. A placed design is timed with the parasitics -# OpenROAD has for it, a design before placement without any. -proc write_endpoint_slack { step } { +# 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 { [grt::design_is_placed] } { - log_cmd estimate_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 @@ -378,7 +395,7 @@ proc write_endpoint_slack { step } { puts $fileId "{" puts $fileId "\"design\": \"$::env(DESIGN_NAME)\"," puts $fileId "\"step\": \"$step\"," - puts $fileId "\"parasitics\": \"[est::parasitics_source]\"," + puts $fileId "\"parasitics\": \"$parasitics\"," # Seconds per reported time unit puts $fileId "\"time_unit\": [sta::time_ui_sta 1]," # endpoint: [setup slack, hold slack], null if unconstrained