diff --git a/docs/contrib/TclContract.md b/docs/contrib/TclContract.md index 9ec7ab1623..067783b3a7 100644 --- a/docs/contrib/TclContract.md +++ b/docs/contrib/TclContract.md @@ -26,8 +26,8 @@ to follow. - **A script never writes its own version of an idiom `util.tcl` already has.** An optional flag is added with `append_env_var`, a command that does - real work runs through `log_cmd`, a result is written with `orfs_write_db` - and `orfs_write_sdc`. An idiom a change needs in two places becomes a proc + real work runs through `log_cmd`, a result is written with `orfs_write_db`, + which writes the `.odb` and its `.sdc`. An idiom a change needs in two places becomes a proc in `util.tcl`. *Breaks:* each copy grows its own small bug, and nobody can grep for the places that do the same thing. diff --git a/flow/Makefile b/flow/Makefile index 2ef5b3b645..79d28aedff 100644 --- a/flow/Makefile +++ b/flow/Makefile @@ -350,8 +350,7 @@ clean_synth: # |_| |_____\___/ \___/|_| \_\_| |_____/_/ \_\_| \_| # .PHONY: floorplan -floorplan: $(RESULTS_DIR)/2_floorplan.odb \ - $(RESULTS_DIR)/2_floorplan.sdc +floorplan: $(RESULTS_DIR)/2_floorplan.odb # ============================================================================== @@ -414,10 +413,11 @@ $(eval $(call OPEN_GUI_SHORTCUT,5_1_grt-failed,5_1_grt-failed.odb)) # $(1) stem, e.g. 2_1_floorplan # $(2) dependencies # $(3) tcl script step -# $(4) extension of result, default .odb +# $(4) extension of result, default .odb; an .odb result comes with +# its .sdc, declared as one grouped target # $(5) folder of target, default $(RESULTS_DIR) define do-step -$(if $(5),$(5),$(RESULTS_DIR))/$(1)$(if $(4),$(4),.odb): $(2) +$(if $(filter-out .odb,$(4)),$(if $(5),$(5),$(RESULTS_DIR))/$(1)$(4):,$(RESULTS_DIR)/$(1).odb $(RESULTS_DIR)/$(1).sdc &:) $(2) $$(UNSET_AND_MAKE) do-$(1) ifeq ($(if $(4),$(4),.odb),.odb) @@ -432,33 +432,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)/$(1).sdc &: $(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).sdc $(RESULTS_DIR)/$(1).sdc + cp $(RESULTS_DIR)/$(2).odb $(RESULTS_DIR)/$(1).odb 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 # ============================================================================== @@ -469,8 +468,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 @@ -484,20 +481,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 #------------------------------------------------------------------------------- @@ -507,17 +502,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_* @@ -529,22 +522,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: @@ -554,11 +546,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: @@ -569,7 +557,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_* @@ -583,8 +571,7 @@ clean_place: # \____| |_| |____/ # .PHONY: cts -cts: $(RESULTS_DIR)/4_cts.odb \ - $(RESULTS_DIR)/4_cts.sdc +cts: $(RESULTS_DIR)/4_cts.odb # ============================================================================== # Run TritonCTS @@ -593,15 +580,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: @@ -609,7 +594,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_* @@ -622,8 +607,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 @@ -642,13 +626,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: @@ -657,7 +639,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_* @@ -686,7 +668,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 @@ -699,25 +680,20 @@ 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 +$(RESULTS_DIR)/6_final.odb $(RESULTS_DIR)/6_final.sdc: $(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. @@ -733,7 +709,7 @@ 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 $(RESULTS_DIR)/6_final.spef 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 7439569d12..fdb9d54ada 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 6a4216f717..643a7b3930 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 4bdc0c10f4..40b96eecb6 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 { !$::env(SKIP_DETAILED_ROUTE) } { 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 3190eeb612..26dea568b0 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 # The global connections, before any step can mark an instance # dont_touch: global_connect skips one (ODB-0383). The rules stay in the @@ -175,4 +175,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..a89766a943 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_sdc -no_timestamp $sdc 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 + 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 733a2df7e1..7fc2fd9726 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 orfs_load_parasitics $stem diff --git a/flow/scripts/global_place.tcl b/flow/scripts/global_place.tcl index 4a125954e2..fce5809f23 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 01ad91ba30..93213b19a5 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 source_step_tcl PRE GLOBAL_ROUTE @@ -30,6 +30,7 @@ proc set_grt_seed { } { proc run_global_route_and_catch_failures { args } { if { [catch { log_cmd global_route {*}$args } errMsg] } { 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 } } @@ -157,4 +158,3 @@ source [file join $::env(SCRIPTS_DIR) "write_ref_sdc.tcl"] 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 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 556cc30ccc..3541d50ef5 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 # A register file in `mode netlist` dissolves onto the parent's rows diff --git a/flow/scripts/open.tcl b/flow/scripts/open.tcl index dc490e790e..e043c46850 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 7a7c32b25f..05bbcb6610 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 fa8a26da3d..1cfd01b08b 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 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 09ab88033a..c8cd77a538 100644 --- a/flow/scripts/util.tcl +++ b/flow/scripts/util.tcl @@ -97,31 +97,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 } { @@ -453,6 +433,7 @@ proc orfs_write_db { output_file { endpoint_slack 1 } } { if { !$::env(WRITE_ODB_AND_SDC_EACH_STAGE) } { return } + orfs_write_sdc [sdc_file_of $output_file] log_cmd write_db $output_file } @@ -464,8 +445,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. # @@ -477,6 +458,7 @@ proc orfs_copy_db { input_file output_file } { if { !$::env(WRITE_ODB_AND_SDC_EACH_STAGE) } { return } + log_cmd exec cp [sdc_file_of $input_file] [sdc_file_of $output_file] log_cmd exec cp $input_file $output_file } 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