From d779ebd9fcefbfe9aaf3f56c3a3b22b6df1f7e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Tue, 27 Oct 2026 23:02:22 +0100 Subject: [PATCH] flow: every .odb has its .sdc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every step that writes N.odb writes N.sdc beside it, and every step reads the .sdc beside the .odb it loads. Before synthesis the .sdc is the user's (1_2_yosys.sdc); from 1_synth on, every .odb has its own. This deletes find_sdc_file, which picked an .sdc by name order and gave open_*/gui_* another stage's constraints for a .def or a failed .odb; the second argument of load_design, which named by hand which earlier step's .sdc a script borrowed; the separate orfs_write_sdc and flow_write_sdc calls, now part of orfs_write_db, orfs_copy_db and flow_write_db; and every .sdc rule and prerequisite in the Makefile except the user's, since a step's input .odb comes with its .sdc. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Øyvind Harboe --- flow/Makefile | 102 ++++++++++---------------- flow/scripts/cdl.tcl | 2 +- flow/scripts/cts.tcl | 4 +- flow/scripts/density_fill.tcl | 2 +- flow/scripts/detail_place.tcl | 3 +- flow/scripts/detail_route.tcl | 2 +- flow/scripts/fillcell.tcl | 2 +- flow/scripts/final_connect.tcl | 2 +- flow/scripts/final_report.tcl | 1 - flow/scripts/floorplan.tcl | 3 +- flow/scripts/flow.tcl | 31 +++----- flow/scripts/generate_abstract.tcl | 6 +- flow/scripts/global_place.tcl | 2 +- flow/scripts/global_place_skip_io.tcl | 2 +- flow/scripts/global_route.tcl | 5 +- flow/scripts/io_placement.tcl | 2 +- flow/scripts/load.tcl | 5 +- flow/scripts/macro_place.tcl | 2 +- flow/scripts/open.tcl | 10 +-- flow/scripts/pdn.tcl | 2 +- flow/scripts/resize.tcl | 2 +- flow/scripts/synth_metrics.tcl | 2 +- flow/scripts/synth_odb.tcl | 10 +-- flow/scripts/synth_syn.tcl | 8 +- flow/scripts/tapcell.tcl | 2 +- flow/scripts/util.tcl | 36 +++------ flow/util/write_rc.tcl | 2 +- 27 files changed, 88 insertions(+), 164 deletions(-) diff --git a/flow/Makefile b/flow/Makefile index 759e13578d..2dc84027ba 100644 --- a/flow/Makefile +++ b/flow/Makefile @@ -325,8 +325,7 @@ clean_synth: # |_| |_____\___/ \___/|_| \_\_| |_____/_/ \_\_| \_| # .PHONY: floorplan -floorplan: $(RESULTS_DIR)/2_floorplan.odb \ - $(RESULTS_DIR)/2_floorplan.sdc +floorplan: $(RESULTS_DIR)/2_floorplan.odb # ============================================================================== @@ -407,33 +406,32 @@ do-$(1): $(DO_STEP_DEPS_$(1)) $(OBJECTS_DIR)/copyright.txt $(SCRIPTS_DIR)/flow.sh $(1) $(3) endef -# generate make rules to copy a file, if a dependency change and -# a do- sibling rule that copies the file unconditionally. +# generate make rules to copy an .odb and its .sdc, if a dependency +# change and a do- sibling rule that copies them unconditionally. # -# The file is copied within the $(RESULTS_DIR) +# The files are copied within the $(RESULTS_DIR) # -# $(1) stem of target, e.g. 2_1_floorplan -# $(2) basename of file to be copied -# $(3) further dependencies -# $(4) target extension, default .odb +# $(1) stem of target, e.g. 2_floorplan +# $(2) stem of the files to be copied, e.g. 2_4_floorplan_pdn define do-copy -$(RESULTS_DIR)/$(1)$(if $(4),$(4),.odb): $(RESULTS_DIR)/$(2) $(3) - $$(UNSET_AND_MAKE) do-$(1)$(if $(4),$(4),) +$(RESULTS_DIR)/$(1).odb: $(RESULTS_DIR)/$(2).odb + $$(UNSET_AND_MAKE) do-$(1) -.PHONY: do-$(1)$(if $(4),$(4),) -do-$(1)$(if $(4),$(4),): - cp $(RESULTS_DIR)/$(2) $(RESULTS_DIR)/$(1)$(if $(4),$(4),.odb) +.PHONY: do-$(1) +do-$(1): + cp $(RESULTS_DIR)/$(2).odb $(RESULTS_DIR)/$(1).odb + cp $(RESULTS_DIR)/$(2).sdc $(RESULTS_DIR)/$(1).sdc endef # ============================================================================== # Custom target to go from synthesis to placement in a single OpenROAD run -$(eval $(call do-step,1_3_floorplan_to_place, $(RESULTS_DIR)/1_synth.odb $(RESULTS_DIR)/1_synth.sdc,floorplan_to_place)) +$(eval $(call do-step,1_3_floorplan_to_place, $(RESULTS_DIR)/1_synth.odb,floorplan_to_place)) $(eval $(call OPEN_GUI_SHORTCUT,yosys,1_2_yosys.v)) .PHONY: floorplan_to_place -floorplan_to_place: $(RESULTS_DIR)/1_synth.odb $(RESULTS_DIR)/1_synth.sdc +floorplan_to_place: $(RESULTS_DIR)/1_synth.odb $(UNSET_AND_MAKE) do-1_3_floorplan_to_place # ============================================================================== @@ -444,8 +442,6 @@ else $(eval $(call do-step,1_synth,$(RESULTS_DIR)/1_2_yosys.v $(RESULTS_DIR)/1_2_yosys.sdc $(TECH_LEF) $(SC_LEF) $(ADDITIONAL_LEFS) $(LIB_FILES),synth_odb)) endif -$(RESULTS_DIR)/1_synth.sdc: $(RESULTS_DIR)/1_synth.odb - FORMAL_CHECK_DEPS = ifneq ($(filter 1,$(LEC_CHECK) $(SEC_CHECK)),) FORMAL_CHECK_DEPS += $(RESULTS_DIR)/1_synth_lec.v @@ -459,20 +455,18 @@ check-kepler-formal: exit 1; \ fi -$(RESULTS_DIR)/1_synth_lec.v: $(RESULTS_DIR)/1_synth.odb $(RESULTS_DIR)/1_synth.sdc +$(RESULTS_DIR)/1_synth_lec.v: $(RESULTS_DIR)/1_synth.odb $(UNSET_AND_MAKE) do-1_synth ifneq ($(filter 1,$(LEC_CHECK) $(SEC_CHECK)),) $(RESULTS_DIR)/1_synth_lec.v: | check-kepler-formal endif -$(eval $(call do-step,2_1_floorplan,$(RESULTS_DIR)/1_synth.odb $(RESULTS_DIR)/1_synth.sdc $(TECH_LEF) $(SC_LEF) $(ADDITIONAL_LEFS) $(FOOTPRINT) $(SIG_MAP_FILE) $(FOOTPRINT_TCL) $(LIB_FILES) $(IO_CONSTRAINTS),floorplan)) - -$(eval $(call do-copy,2_floorplan,2_1_floorplan.sdc,,.sdc)) +$(eval $(call do-step,2_1_floorplan,$(RESULTS_DIR)/1_synth.odb $(TECH_LEF) $(SC_LEF) $(ADDITIONAL_LEFS) $(FOOTPRINT) $(SIG_MAP_FILE) $(FOOTPRINT_TCL) $(LIB_FILES) $(IO_CONSTRAINTS),floorplan)) # STEP 2: Macro Placement #------------------------------------------------------------------------------- -$(eval $(call do-step,2_2_floorplan_macro,$(RESULTS_DIR)/2_1_floorplan.odb $(RESULTS_DIR)/1_synth.sdc $(MACRO_PLACEMENT) $(MACRO_PLACEMENT_TCL),macro_place)) +$(eval $(call do-step,2_2_floorplan_macro,$(RESULTS_DIR)/2_1_floorplan.odb $(MACRO_PLACEMENT) $(MACRO_PLACEMENT_TCL),macro_place)) # STEP 3: Tapcell and Welltie insertion #------------------------------------------------------------------------------- @@ -482,17 +476,15 @@ $(eval $(call do-step,2_3_floorplan_tapcell,$(RESULTS_DIR)/2_2_floorplan_macro.o #------------------------------------------------------------------------------- $(eval $(call do-step,2_4_floorplan_pdn,$(RESULTS_DIR)/2_3_floorplan_tapcell.odb $(PDN_TCL),pdn)) -$(eval $(call do-copy,2_floorplan,2_4_floorplan_pdn.odb,)) - -$(RESULTS_DIR)/2_floorplan.sdc: $(RESULTS_DIR)/2_1_floorplan.odb +$(eval $(call do-copy,2_floorplan,2_4_floorplan_pdn)) .PHONY: do-floorplan do-floorplan: - $(UNSET_AND_MAKE) do-2_1_floorplan do-2_2_floorplan_macro do-2_3_floorplan_tapcell do-2_4_floorplan_pdn do-2_floorplan do-2_floorplan.sdc + $(UNSET_AND_MAKE) do-2_1_floorplan do-2_2_floorplan_macro do-2_3_floorplan_tapcell do-2_4_floorplan_pdn do-2_floorplan .PHONY: clean_floorplan clean_floorplan: - rm -f $(RESULTS_DIR)/2_*floorplan*.odb $(RESULTS_DIR)/2_floorplan.sdc $(RESULTS_DIR)/2_*.v $(RESULTS_DIR)/2_*.def + rm -f $(RESULTS_DIR)/2_*floorplan*.odb $(RESULTS_DIR)/2_*floorplan*.sdc $(RESULTS_DIR)/2_*.v $(RESULTS_DIR)/2_*.def rm -f $(REPORTS_DIR)/2_* rm -f $(LOG_DIR)/2_* @@ -504,22 +496,21 @@ clean_floorplan: # |_| |_____/_/ \_\____|_____| # .PHONY: place -place: $(RESULTS_DIR)/3_place.odb \ - $(RESULTS_DIR)/3_place.sdc +place: $(RESULTS_DIR)/3_place.odb # ============================================================================== # STEP 1: Global placement without placed IOs, timing-driven, and routability-driven. #------------------------------------------------------------------------------- -$(eval $(call do-step,3_1_place_gp_skip_io,$(RESULTS_DIR)/2_floorplan.odb $(RESULTS_DIR)/2_floorplan.sdc $(LIB_FILES),global_place_skip_io)) +$(eval $(call do-step,3_1_place_gp_skip_io,$(RESULTS_DIR)/2_floorplan.odb $(LIB_FILES),global_place_skip_io)) $(eval $(call do-step,3_2_place_iop,$(RESULTS_DIR)/3_1_place_gp_skip_io.odb,io_placement)) # STEP 3: Global placement with placed IOs, timing-driven, and routability-driven. #------------------------------------------------------------------------------- -$(eval $(call do-step,3_3_place_gp,$(RESULTS_DIR)/3_2_place_iop.odb $(RESULTS_DIR)/2_floorplan.sdc $(LIB_FILES),global_place)) +$(eval $(call do-step,3_3_place_gp,$(RESULTS_DIR)/3_2_place_iop.odb $(LIB_FILES),global_place)) # STEP 4: Resizing & Buffering #------------------------------------------------------------------------------- -$(eval $(call do-step,3_4_place_resized,$(RESULTS_DIR)/3_3_place_gp.odb $(RESULTS_DIR)/2_floorplan.sdc,resize)) +$(eval $(call do-step,3_4_place_resized,$(RESULTS_DIR)/3_3_place_gp.odb,resize)) .PHONY: clean_resize clean_resize: @@ -529,11 +520,7 @@ clean_resize: #------------------------------------------------------------------------------- $(eval $(call do-step,3_5_place_dp,$(RESULTS_DIR)/3_4_place_resized.odb,detail_place)) -$(eval $(call do-copy,3_place,3_5_place_dp.odb,)) - -# detail_place writes 3_place.sdc alongside 3_5_place_dp.odb (constraints -# are unchanged during placement), mirroring how synth writes 1_synth.sdc. -$(RESULTS_DIR)/3_place.sdc: $(RESULTS_DIR)/3_5_place_dp.odb +$(eval $(call do-copy,3_place,3_5_place_dp)) .PHONY: do-place do-place: @@ -544,7 +531,7 @@ do-place: .PHONY: clean_place clean_place: rm -f $(RESULTS_DIR)/3_*place*.odb - rm -f $(RESULTS_DIR)/3_place.sdc + rm -f $(RESULTS_DIR)/3_*place*.sdc rm -f $(RESULTS_DIR)/3_*.def $(RESULTS_DIR)/3_*.v rm -f $(REPORTS_DIR)/3_* rm -f $(LOG_DIR)/3_* @@ -558,8 +545,7 @@ clean_place: # \____| |_| |____/ # .PHONY: cts -cts: $(RESULTS_DIR)/4_cts.odb \ - $(RESULTS_DIR)/4_cts.sdc +cts: $(RESULTS_DIR)/4_cts.odb # ============================================================================== # Run TritonCTS @@ -568,15 +554,13 @@ ifeq ($(LEC_CHECK),1) DO_STEP_DEPS_4_1_cts += check-kepler-formal endif -$(eval $(call do-step,4_1_cts,$(RESULTS_DIR)/3_place.odb $(RESULTS_DIR)/3_place.sdc,cts)) +$(eval $(call do-step,4_1_cts,$(RESULTS_DIR)/3_place.odb,cts)) ifeq ($(LEC_CHECK),1) $(RESULTS_DIR)/4_1_cts.odb: | check-kepler-formal endif -$(RESULTS_DIR)/4_cts.sdc: $(RESULTS_DIR)/4_cts.odb - -$(eval $(call do-copy,4_cts,4_1_cts.odb)) +$(eval $(call do-copy,4_cts,4_1_cts)) .PHONY: do-cts do-cts: @@ -584,7 +568,7 @@ do-cts: .PHONY: clean_cts clean_cts: - rm -rf $(RESULTS_DIR)/4_*cts*.odb $(RESULTS_DIR)/4_cts.sdc $(RESULTS_DIR)/4_*.v $(RESULTS_DIR)/4_*.def + rm -rf $(RESULTS_DIR)/4_*cts*.odb $(RESULTS_DIR)/4_*cts*.sdc $(RESULTS_DIR)/4_*.v $(RESULTS_DIR)/4_*.def rm -f $(REPORTS_DIR)/4_* rm -rf $(LOG_DIR)/4_* @@ -597,8 +581,7 @@ clean_cts: # |_| \_\\___/ \___/ |_| |___|_| \_|\____| # .PHONY: route -route: $(RESULTS_DIR)/5_route.odb \ - $(RESULTS_DIR)/5_route.sdc +route: $(RESULTS_DIR)/5_route.odb .PHONY: grt globalroute globalroute: grt @@ -617,13 +600,11 @@ $(eval $(call do-step,5_2_route,$(RESULTS_DIR)/5_1_grt.odb,detail_route)) $(eval $(call do-step,5_3_fillcell,$(RESULTS_DIR)/5_2_route.odb,fillcell)) -$(eval $(call do-copy,5_route,5_3_fillcell.odb)) - -$(eval $(call do-copy,5_route,5_1_grt.sdc,,.sdc)) +$(eval $(call do-copy,5_route,5_3_fillcell)) .PHONY: do-route do-route: - $(UNSET_AND_MAKE) do-5_1_grt do-5_2_route do-5_3_fillcell do-5_route do-5_route.sdc + $(UNSET_AND_MAKE) do-5_1_grt do-5_2_route do-5_3_fillcell do-5_route .PHONY: do-grt do-grt: @@ -632,7 +613,7 @@ do-grt: .PHONY: clean_route clean_route: rm -rf $(RESULTS_DIR)/route.guide $(RESULTS_DIR)/output_guide.mod $(RESULTS_DIR)/updated_clks.sdc - rm -rf $(RESULTS_DIR)/5_*.odb $(RESULTS_DIR)/5_route.sdc $(RESULTS_DIR)/5_*.def $(RESULTS_DIR)/5_*.v + rm -rf $(RESULTS_DIR)/5_*.odb $(RESULTS_DIR)/5_*.sdc $(RESULTS_DIR)/5_*.def $(RESULTS_DIR)/5_*.v rm -f $(REPORTS_DIR)/5_* rm -f $(LOG_DIR)/5_* @@ -661,7 +642,6 @@ klayout_guides: $(RESULTS_DIR)/5_route.def $(OBJECTS_DIR)/klayout.lyt .PHONY: finish finish: $(LOG_DIR)/6_report.log \ $(RESULTS_DIR)/6_final.v \ - $(RESULTS_DIR)/6_final.sdc \ $(GDS_FINAL_FILE) $(UNSET_AND_MAKE) elapsed @@ -674,24 +654,18 @@ elapsed: elapsed-all: @$(PYTHON_EXE) $(UTILS_DIR)/genElapsedTime.py -d $(shell find $(WORK_HOME)/logs/$(PLATFORM)/*/*/ -type d) -$(eval $(call do-step,6_1_fill,$(RESULTS_DIR)/5_route.odb $(RESULTS_DIR)/5_route.sdc $(FILL_CONFIG),density_fill)) - -$(eval $(call do-copy,6_1_fill,5_route.sdc,,.sdc)) +$(eval $(call do-step,6_1_fill,$(RESULTS_DIR)/5_route.odb $(FILL_CONFIG),density_fill)) ifneq ($(filter 1,$(LEC_CHECK) $(SEC_CHECK)),) DO_STEP_DEPS_6_report += check-kepler-formal endif -$(eval $(call do-step,6_report,$(RESULTS_DIR)/6_1_fill.odb $(RESULTS_DIR)/6_1_fill.sdc $(FORMAL_CHECK_DEPS),final_report,.log,$(LOG_DIR))) +$(eval $(call do-step,6_report,$(RESULTS_DIR)/6_1_fill.odb $(FORMAL_CHECK_DEPS),final_report,.log,$(LOG_DIR))) ifneq ($(filter 1,$(LEC_CHECK) $(SEC_CHECK)),) $(LOG_DIR)/6_report.log: | check-kepler-formal endif -# final_report writes 6_final.sdc alongside 6_final.odb (constraints are -# unchanged during finishing), mirroring how synth writes 1_synth.sdc. -$(RESULTS_DIR)/6_final.sdc: $(LOG_DIR)/6_report.log - $(RESULTS_DIR)/6_final.def: $(LOG_DIR)/6_report.log # The final results are called 6_final.*, so it is convenient when scripting @@ -704,10 +678,10 @@ final: finish .PHONY: do-finish do-finish: - $(UNSET_AND_MAKE) do-6_1_fill do-6_1_fill.sdc do-6_report elapsed + $(UNSET_AND_MAKE) do-6_1_fill 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 $(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/cdl.tcl b/flow/scripts/cdl.tcl index f45d941ef4..e5f5ca3f59 100644 --- a/flow/scripts/cdl.tcl +++ b/flow/scripts/cdl.tcl @@ -1,5 +1,5 @@ source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables final -load_design 6_final.odb 6_final.sdc +load_design 6_final.odb write_cdl -masters $::env(CDL_FILE) $::env(RESULTS_DIR)/6_final.cdl diff --git a/flow/scripts/cts.tcl b/flow/scripts/cts.tcl index e90c6f0698..f32b61478d 100644 --- a/flow/scripts/cts.tcl +++ b/flow/scripts/cts.tcl @@ -2,7 +2,7 @@ utl::set_metrics_stage "cts__{}" source $::env(SCRIPTS_DIR)/load.tcl source $::env(SCRIPTS_DIR)/formal_check.tcl erase_non_stage_variables cts -load_design 3_place.odb 3_place.sdc +load_design 3_place.odb source_step_tcl PRE CTS # Clone clock tree inverters next to register loads @@ -12,7 +12,6 @@ repair_clock_inverters proc save_progress { stage } { puts "Run 'make gui_$stage.odb' to load progress snapshot" orfs_write_db $::env(RESULTS_DIR)/$stage.odb - orfs_write_sdc $::env(RESULTS_DIR)/$stage.sdc } # Run CTS @@ -87,4 +86,3 @@ report_metrics 4 "cts final" source_step_tcl POST CTS orfs_write_db $::env(RESULTS_DIR)/4_1_cts.odb -orfs_write_sdc $::env(RESULTS_DIR)/4_cts.sdc diff --git a/flow/scripts/density_fill.tcl b/flow/scripts/density_fill.tcl index 1f93ed4c52..030c2c3825 100644 --- a/flow/scripts/density_fill.tcl +++ b/flow/scripts/density_fill.tcl @@ -1,6 +1,6 @@ source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables final -load_design 5_route.odb 5_route.sdc +load_design 5_route.odb source_step_tcl PRE DENSITY_FILL if { $::env(USE_FILL) } { diff --git a/flow/scripts/detail_place.tcl b/flow/scripts/detail_place.tcl index 20aee94c3a..7927979b4a 100644 --- a/flow/scripts/detail_place.tcl +++ b/flow/scripts/detail_place.tcl @@ -1,7 +1,7 @@ utl::set_metrics_stage "detailedplace__{}" source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables place -load_design 3_4_place_resized.odb 2_floorplan.sdc +load_design 3_4_place_resized.odb source_step_tcl PRE DETAIL_PLACE proc do_dpl { } { @@ -40,4 +40,3 @@ report_metrics 3 "detailed place" true false source_step_tcl POST DETAIL_PLACE orfs_write_db $::env(RESULTS_DIR)/3_5_place_dp.odb -orfs_write_sdc $::env(RESULTS_DIR)/3_place.sdc diff --git a/flow/scripts/detail_route.tcl b/flow/scripts/detail_route.tcl index 538e8476e0..89456b0b99 100644 --- a/flow/scripts/detail_route.tcl +++ b/flow/scripts/detail_route.tcl @@ -1,6 +1,6 @@ utl::set_metrics_stage "detailedroute__{}" source $::env(SCRIPTS_DIR)/load.tcl -load_design 5_1_grt.odb 5_1_grt.sdc +load_design 5_1_grt.odb source_step_tcl PRE DETAIL_ROUTE if { ![grt::have_routes] } { error "Global routing failed, run `make gui_grt` and load $::global_route_congestion_report \ diff --git a/flow/scripts/fillcell.tcl b/flow/scripts/fillcell.tcl index 032c1ab58b..f88417db9a 100644 --- a/flow/scripts/fillcell.tcl +++ b/flow/scripts/fillcell.tcl @@ -1,7 +1,7 @@ source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables route if { [env_var_exists_and_non_empty FILL_CELLS] } { - load_design 5_2_route.odb 5_1_grt.sdc + load_design 5_2_route.odb source_step_tcl PRE FILLCELL set_propagated_clock [all_clocks] diff --git a/flow/scripts/final_connect.tcl b/flow/scripts/final_connect.tcl index 22324613c6..df059d73b5 100644 --- a/flow/scripts/final_connect.tcl +++ b/flow/scripts/final_connect.tcl @@ -1,7 +1,7 @@ utl::set_metrics_stage "finish__{}" source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables final -load_design 6_1_fill.odb 6_1_fill.sdc +load_design 6_1_fill.odb source_step_tcl PRE FINAL_REPORT set_propagated_clock [all_clocks] diff --git a/flow/scripts/final_report.tcl b/flow/scripts/final_report.tcl index 2916f2f473..54a2e3ebda 100644 --- a/flow/scripts/final_report.tcl +++ b/flow/scripts/final_report.tcl @@ -4,5 +4,4 @@ source $::env(SCRIPTS_DIR)/final_connect.tcl # final_outputs.tcl writes the endpoint slack after parasitic extraction orfs_write_db $::env(RESULTS_DIR)/6_final.odb 0 -orfs_write_sdc $::env(RESULTS_DIR)/6_final.sdc source $::env(SCRIPTS_DIR)/final_outputs.tcl diff --git a/flow/scripts/floorplan.tcl b/flow/scripts/floorplan.tcl index 67b5b16564..a17e38602e 100644 --- a/flow/scripts/floorplan.tcl +++ b/flow/scripts/floorplan.tcl @@ -1,7 +1,7 @@ utl::set_metrics_stage "floorplan__{}" source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables floorplan -load_design 1_synth.odb 1_synth.sdc +load_design 1_synth.odb source_step_tcl PRE FLOORPLAN proc report_unused_masters { } { @@ -166,4 +166,3 @@ source_step_tcl POST FLOORPLAN source_env_var_if_exists IO_CONSTRAINTS orfs_write_db $::env(RESULTS_DIR)/2_1_floorplan.odb -orfs_write_sdc $::env(RESULTS_DIR)/2_1_floorplan.sdc diff --git a/flow/scripts/flow.tcl b/flow/scripts/flow.tcl index cd7f0a26bd..c6c93bb8ed 100644 --- a/flow/scripts/flow.tcl +++ b/flow/scripts/flow.tcl @@ -2,12 +2,12 @@ # the final report, in a single OpenROAD process. # # With WRITE_ODB_AND_SDC_EACH_STAGE=0 the per-stage orfs_write_db / -# orfs_write_sdc / orfs_copy_db helpers are no-ops, so this top level is -# the sole writer of .odb/.sdc files. flow_write_db/flow_write_sdc -# produce the same file set as the stage-per-process make flow (the -# extra writes after a stage's own mirror the Makefile do-copy -# recipes), and flow_source enforces that stage scripts write no -# .odb/.sdc files themselves. +# orfs_copy_db helpers are no-ops, so this top level is the sole writer +# of .odb/.sdc files. flow_write_db writes each .odb with its .sdc, +# the same file set as the stage-per-process make flow (the extra +# writes after a stage's own mirror the Makefile do-copy recipes), and +# flow_source enforces that stage scripts write no .odb/.sdc files +# themselves. # Enable keeping variables between stages set ::env(KEEP_VARS) 1 @@ -30,25 +30,19 @@ proc flow_source { script } { proc flow_write_db { name } { set path [file join $::env(RESULTS_DIR) $name] + set sdc [sdc_file_of $path] log_cmd write_db $path - lappend ::flow_expected $path -} - -proc flow_write_sdc { name } { - set path [file join $::env(RESULTS_DIR) $name] - log_cmd write_sdc -no_timestamp $path - lappend ::flow_expected $path + log_cmd write_sdc -no_timestamp $sdc + lappend ::flow_expected $path $sdc } # Synthesis odb (from the yosys netlist) flow_source synth_odb.tcl flow_write_db 1_synth.odb -flow_write_sdc 1_synth.sdc # Floorplan flow_source floorplan.tcl flow_write_db 2_1_floorplan.odb -flow_write_sdc 2_1_floorplan.sdc flow_source macro_place.tcl flow_write_db 2_2_floorplan_macro.odb flow_source tapcell.tcl @@ -56,7 +50,6 @@ flow_write_db 2_3_floorplan_tapcell.odb flow_source pdn.tcl flow_write_db 2_4_floorplan_pdn.odb flow_write_db 2_floorplan.odb -flow_write_sdc 2_floorplan.sdc # Place flow_source global_place_skip_io.tcl @@ -70,31 +63,25 @@ flow_write_db 3_4_place_resized.odb flow_source detail_place.tcl flow_write_db 3_5_place_dp.odb flow_write_db 3_place.odb -flow_write_sdc 3_place.sdc # CTS flow_source cts.tcl flow_write_db 4_1_cts.odb flow_write_db 4_cts.odb -flow_write_sdc 4_cts.sdc # Route flow_source global_route.tcl flow_write_db 5_1_grt.odb -flow_write_sdc 5_1_grt.sdc flow_source detail_route.tcl flow_write_db 5_2_route.odb flow_source fillcell.tcl flow_write_db 5_3_fillcell.odb flow_write_db 5_route.odb -flow_write_sdc 5_route.sdc # Finish. final_report.tcl is split around its 6_final.odb write so # this top level can write at the same point. flow_source density_fill.tcl flow_write_db 6_1_fill.odb -flow_write_sdc 6_1_fill.sdc flow_source final_connect.tcl flow_write_db 6_final.odb -flow_write_sdc 6_final.sdc flow_source final_outputs.tcl diff --git a/flow/scripts/generate_abstract.tcl b/flow/scripts/generate_abstract.tcl index 7b6ec30cbd..31cf237dad 100644 --- a/flow/scripts/generate_abstract.tcl +++ b/flow/scripts/generate_abstract.tcl @@ -7,11 +7,9 @@ set stem [expr { "6_final" }] -set result [find_sdc_file $stem.odb] -set design_stage [lindex $result 0] -set sdc_file [lindex $result 1] +set design_stage [lindex [extract_stage $stem.odb] 0] -log_cmd load_design $stem.odb [file tail $sdc_file] +log_cmd load_design $stem.odb if { $design_stage >= 6 && [file exists $::env(RESULTS_DIR)/$stem.spef] } { log_cmd read_spef $::env(RESULTS_DIR)/$stem.spef diff --git a/flow/scripts/global_place.tcl b/flow/scripts/global_place.tcl index 6a2d583d26..9700890dd6 100644 --- a/flow/scripts/global_place.tcl +++ b/flow/scripts/global_place.tcl @@ -1,7 +1,7 @@ utl::set_metrics_stage "globalplace__{}" source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables place -load_design 3_2_place_iop.odb 2_floorplan.sdc +load_design 3_2_place_iop.odb source_step_tcl PRE GLOBAL_PLACE set_dont_use $::env(DONT_USE_CELLS) diff --git a/flow/scripts/global_place_skip_io.tcl b/flow/scripts/global_place_skip_io.tcl index 96195d486e..aadaa5f014 100644 --- a/flow/scripts/global_place_skip_io.tcl +++ b/flow/scripts/global_place_skip_io.tcl @@ -5,7 +5,7 @@ if { $::env(GPL_PLACE_IOS) } { $::env(RESULTS_DIR)/3_1_place_gp_skip_io.odb return } -load_design 2_floorplan.odb 2_floorplan.sdc +load_design 2_floorplan.odb source_step_tcl PRE GLOBAL_PLACE_SKIP_IO if { [env_var_exists_and_non_empty FLOORPLAN_DEF] } { diff --git a/flow/scripts/global_route.tcl b/flow/scripts/global_route.tcl index fb9d41945f..4b5bdb0034 100644 --- a/flow/scripts/global_route.tcl +++ b/flow/scripts/global_route.tcl @@ -1,7 +1,7 @@ utl::set_metrics_stage "globalroute__{}" source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables grt -load_design 4_cts.odb 4_cts.sdc +load_design 4_cts.odb # This proc is here to allow us to use 'return' to return early from this # file which is sourced @@ -36,9 +36,9 @@ proc global_route_helper { } { if { $result != 0 } { if { !$::env(GENERATE_ARTIFACTS_ON_FAILURE) } { log_cmd write_db $::env(RESULTS_DIR)/5_1_grt-failed.odb + log_cmd write_sdc -no_timestamp $::env(RESULTS_DIR)/5_1_grt-failed.sdc error $errMsg } - orfs_write_sdc $::env(RESULTS_DIR)/5_1_grt.sdc orfs_write_db $::env(RESULTS_DIR)/5_1_grt.odb return 0 } @@ -182,7 +182,6 @@ proc global_route_helper { } { write_guides $::env(RESULTS_DIR)/route.guide source_step_tcl POST GLOBAL_ROUTE orfs_write_db $::env(RESULTS_DIR)/5_1_grt.odb - orfs_write_sdc $::env(RESULTS_DIR)/5_1_grt.sdc } global_route_helper diff --git a/flow/scripts/io_placement.tcl b/flow/scripts/io_placement.tcl index ad4d7809e2..2db2d8addd 100644 --- a/flow/scripts/io_placement.tcl +++ b/flow/scripts/io_placement.tcl @@ -2,7 +2,7 @@ source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables place if { !$::env(GPL_PLACE_IOS) && ![pins_fixed_in_floorplan] } { - load_design 3_1_place_gp_skip_io.odb 2_floorplan.sdc + load_design 3_1_place_gp_skip_io.odb source_step_tcl PRE IO_PLACEMENT log_cmd place_pins \ -hor_layers $::env(IO_PLACER_H) \ diff --git a/flow/scripts/load.tcl b/flow/scripts/load.tcl index 7d70b67769..45f24bdff1 100644 --- a/flow/scripts/load.tcl +++ b/flow/scripts/load.tcl @@ -2,7 +2,7 @@ source $::env(SCRIPTS_DIR)/util.tcl source $::env(SCRIPTS_DIR)/report_metrics.tcl -proc load_design { design_file sdc_file } { +proc load_design { design_file } { # Do not reload if design is already loaded set db [ord::get_db] if { [$db getChip] != "NULL" && [[$db getChip] getBlock] != "NULL" } { @@ -38,8 +38,7 @@ proc load_design { design_file sdc_file } { error "Unrecognized input file $design_file" } - # Read SDC file - log_cmd read_sdc $::env(RESULTS_DIR)/$sdc_file + log_cmd read_sdc $::env(RESULTS_DIR)/[sdc_file_of $design_file] if { [file exists $::env(PLATFORM_DIR)/derate.tcl] } { log_cmd source $::env(PLATFORM_DIR)/derate.tcl diff --git a/flow/scripts/macro_place.tcl b/flow/scripts/macro_place.tcl index 0789129e42..0628d74f36 100644 --- a/flow/scripts/macro_place.tcl +++ b/flow/scripts/macro_place.tcl @@ -1,6 +1,6 @@ source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables floorplan -load_design 2_1_floorplan.odb 2_1_floorplan.sdc +load_design 2_1_floorplan.odb source_step_tcl PRE MACRO_PLACE source $::env(SCRIPTS_DIR)/macro_place_util.tcl diff --git a/flow/scripts/open.tcl b/flow/scripts/open.tcl index c8061687ab..9044ff9af2 100644 --- a/flow/scripts/open.tcl +++ b/flow/scripts/open.tcl @@ -33,14 +33,8 @@ if { [env_var_exists_and_non_empty DEF_FILE] } { } proc read_timing { input_file } { - set result [find_sdc_file $input_file] - set design_stage [lindex $result 0] - set sdc_file [lindex $result 1] - - if { $sdc_file == "" } { - set sdc_file $::env(SDC_FILE) - } - log_cmd read_sdc $sdc_file + set design_stage [lindex [extract_stage $input_file] 0] + log_cmd read_sdc [sdc_file_of $input_file] if { [file exists $::env(PLATFORM_DIR)/derate.tcl] } { source $::env(PLATFORM_DIR)/derate.tcl } diff --git a/flow/scripts/pdn.tcl b/flow/scripts/pdn.tcl index 1ffbadd9ba..ba06b60b89 100644 --- a/flow/scripts/pdn.tcl +++ b/flow/scripts/pdn.tcl @@ -1,6 +1,6 @@ source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables floorplan -load_design 2_3_floorplan_tapcell.odb 2_1_floorplan.sdc +load_design 2_3_floorplan_tapcell.odb source_step_tcl PRE PDN source $::env(PDN_TCL) diff --git a/flow/scripts/resize.tcl b/flow/scripts/resize.tcl index e46ac4b328..53b694403b 100644 --- a/flow/scripts/resize.tcl +++ b/flow/scripts/resize.tcl @@ -1,7 +1,7 @@ utl::set_metrics_stage "placeopt__{}" source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables place -load_design 3_3_place_gp.odb 2_floorplan.sdc +load_design 3_3_place_gp.odb source_step_tcl PRE RESIZE log_cmd estimate_parasitics -placement diff --git a/flow/scripts/synth_metrics.tcl b/flow/scripts/synth_metrics.tcl index d2fe0ab500..59c06f6d59 100644 --- a/flow/scripts/synth_metrics.tcl +++ b/flow/scripts/synth_metrics.tcl @@ -1,5 +1,5 @@ utl::set_metrics_stage "synth__{}" source $::env(SCRIPTS_DIR)/load.tcl -load_design 1_2_yosys.v 1_synth.sdc +load_design 1_2_yosys.v report_metrics 1 "Post synthesis" false false diff --git a/flow/scripts/synth_odb.tcl b/flow/scripts/synth_odb.tcl index 3c2ae23606..0f8585cef3 100644 --- a/flow/scripts/synth_odb.tcl +++ b/flow/scripts/synth_odb.tcl @@ -2,7 +2,7 @@ utl::set_metrics_stage "synth__{}" source $::env(SCRIPTS_DIR)/load.tcl source $::env(SCRIPTS_DIR)/formal_check.tcl erase_non_stage_variables synth -load_design 1_2_yosys.v 1_2_yosys.sdc +load_design 1_2_yosys.v source_step_tcl PRE SYNTH # Eliminate dead logic before writing the synthesis odb so that @@ -29,13 +29,11 @@ report_design_area report_design_area_metrics source_step_tcl POST SYNTH -orfs_write_db $::env(RESULTS_DIR)/1_synth.odb -# Canonicalize 1_synth.sdc. The original SDC_FILE provided by +# Also canonicalizes 1_synth.sdc. The original SDC_FILE provided by # the user could have dependencies, such as sourcing util.tcl, # which are read in here and a canonicalized version is written -# out by OpenSTA that has no dependencies. Sole writer of -# 1_synth.sdc. -orfs_write_sdc $::env(RESULTS_DIR)/1_synth.sdc +# out by OpenSTA that has no dependencies. +orfs_write_db $::env(RESULTS_DIR)/1_synth.odb if { $::env(LEC_CHECK) || $::env(SEC_CHECK) } { write_lec_verilog 1_synth_lec.v } diff --git a/flow/scripts/synth_syn.tcl b/flow/scripts/synth_syn.tcl index 52617bd5ae..16a1445072 100644 --- a/flow/scripts/synth_syn.tcl +++ b/flow/scripts/synth_syn.tcl @@ -70,13 +70,11 @@ log_cmd repair_design -pre_placement report_metrics 1 "synth" false false -orfs_write_db $::env(RESULTS_DIR)/1_synth.odb -# Canonicalize 1_synth.sdc. The original SDC_FILE provided by +# Also canonicalizes 1_synth.sdc. The original SDC_FILE provided by # the user could have dependencies, such as sourcing util.tcl, # which are read in here and a canonicalized version is written -# out by OpenSTA that has no dependencies. Sole writer of -# 1_synth.sdc. -orfs_write_sdc $::env(RESULTS_DIR)/1_synth.sdc +# out by OpenSTA that has no dependencies. +orfs_write_db $::env(RESULTS_DIR)/1_synth.odb # Gate-level netlist for downstream consumers. The Bazel synthesis action # declares this file as an output, so it must be written unconditionally. diff --git a/flow/scripts/tapcell.tcl b/flow/scripts/tapcell.tcl index 94620cbef8..95de249fd2 100644 --- a/flow/scripts/tapcell.tcl +++ b/flow/scripts/tapcell.tcl @@ -1,7 +1,7 @@ source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables floorplan -load_design 2_2_floorplan_macro.odb 2_1_floorplan.sdc +load_design 2_2_floorplan_macro.odb source_step_tcl PRE TAPCELL if { [env_var_exists_and_non_empty TAPCELL_TCL] } { diff --git a/flow/scripts/util.tcl b/flow/scripts/util.tcl index 0310f3ca54..0e92ecc614 100644 --- a/flow/scripts/util.tcl +++ b/flow/scripts/util.tcl @@ -96,31 +96,11 @@ proc extract_stage { input_file } { } } -proc find_sdc_file { input_file } { - # canonicalize input file, sometimes it is called with an input - # file relative to $::env(RESULTS_DIR), other times with - # an absolute path - if { ![file exists $input_file] } { - set input_file [file join $::env(RESULTS_DIR) $input_file] - } - set input_file [file normalize $input_file] - - set stage [extract_stage $input_file] - set design_stage [lindex $stage 0] - set sdc_file "" - - set exact_sdc [string map {.odb .sdc} $input_file] - set sdc_files \ - [glob -nocomplain -directory $::env(RESULTS_DIR) -types f "\[1-9+\]_\[1-9_A-Za-z\]*\.sdc"] - set sdc_files [lsort -decreasing -dictionary $sdc_files] - set sdc_files [lmap file $sdc_files { file normalize $file }] - foreach name $sdc_files { - if { [lindex [lsort -decreasing -dictionary [list $name $exact_sdc]] 0] == $exact_sdc } { - set sdc_file $name - break - } - } - return [list $design_stage $sdc_file] +# The stem ends at the first dot of the file name, so 4_cts.odb, +# 4_cts.odb.def and 4_cts.odb.v all have 4_cts.sdc +proc sdc_file_of { design_file } { + regsub {\.[^/]*$} $design_file .sdc sdc_file + return $sdc_file } proc env_var_equals { env_var value } { @@ -438,6 +418,7 @@ proc orfs_write_db { output_file { endpoint_slack 1 } } { return } log_cmd write_db $output_file + orfs_write_sdc [sdc_file_of $output_file] } proc orfs_write_sdc { output_file } { @@ -448,8 +429,8 @@ proc orfs_write_sdc { output_file } { } # For a stage that leaves the design unchanged, copying the input .odb -# forward is much faster than serializing the in-memory database again -# with write_db. Gated like orfs_write_db: in a single-process flow +# and .sdc forward is much faster than serializing the in-memory database +# again with write_db. Gated like orfs_write_db: in a single-process flow # (WRITE_ODB_AND_SDC_EACH_STAGE=0) the input file may not exist and no # stage file should be produced. # @@ -462,6 +443,7 @@ proc orfs_copy_db { input_file output_file } { return } log_cmd exec cp $input_file $output_file + log_cmd exec cp [sdc_file_of $input_file] [sdc_file_of $output_file] } proc source_step_tcl { hook_type step_name } { diff --git a/flow/util/write_rc.tcl b/flow/util/write_rc.tcl index 62922b2b39..190aee2a39 100644 --- a/flow/util/write_rc.tcl +++ b/flow/util/write_rc.tcl @@ -1,5 +1,5 @@ source $::env(SCRIPTS_DIR)/load.tcl -load_design 6_final.odb 6_final.sdc +load_design 6_final.odb source $::env(UTILS_DIR)/write_rc_helper.tcl