From 1b1b495b094574e33bbbd5f0d85b52a95cc69c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 27 Apr 2026 10:31:36 +0200 Subject: [PATCH 1/4] Add option of synthesis using 'syn' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Povišer --- docs/user/FlowVariables.md | 3 ++ flow/Makefile | 4 ++ flow/scripts/synth_syn.tcl | 76 +++++++++++++++++++++++++++++++++++++ flow/scripts/variables.json | 8 ++++ flow/scripts/variables.yaml | 9 +++++ flow/util/genMetrics.py | 31 +++++++++------ 6 files changed, 119 insertions(+), 12 deletions(-) create mode 100644 flow/scripts/synth_syn.tcl diff --git a/docs/user/FlowVariables.md b/docs/user/FlowVariables.md index 161e77d5a2..0abd1aa460 100644 --- a/docs/user/FlowVariables.md +++ b/docs/user/FlowVariables.md @@ -311,6 +311,7 @@ configuration file. | SYNTH_RETIME_MODULES| *This is an experimental option and may cause adverse effects.* *No effort has been made to check if the retimed RTL is logically equivalent to the non-retimed RTL.* List of modules to apply automatic retiming to. These modules must not get dissolved and as such they should either be the top module or be included in SYNTH_KEEP_MODULES. The main use case is to quickly identify if performance can be improved by manually retiming the input RTL. Retiming will treat module ports like register endpoints/startpoints. The objective function of retiming isn't informed by SDC, even the clock period is ignored. As such, retiming will optimize for best delay at potentially high register number cost. Automatic retiming can produce suboptimal results as its timing model is crude and it doesn't find the optimal distribution of registers on long pipelines. See OR discussion # 8080.| | | SYNTH_SKIP_KEEP| Only meaningful together with SYNTH_CHECKPOINT. When set, signals that the supplied checkpoint is still canonical RTLIL (coarse synth and `keep_hierarchy` have not been run yet), so synth.tcl runs the full coarse+fine synthesis flattened. When unset and SYNTH_CHECKPOINT is used, synth.tcl assumes the checkpoint already has coarse synth + `keep_hierarchy` done and resumes from `coarse:fine`.| 0| | SYNTH_SLANG_ARGS| Additional arguments passed to the slang frontend during synthesis.| | +| SYNTH_USE_SYN| If set to 1, run synthesis using the "syn" tool built into OpenROAD (the synth_syn.tcl flow) instead of the default Yosys-based flow. Defaults to 0 (Yosys flow).| 0| | SYNTH_WRAPPED_ADDERS| Specify the adder modules that can be used for synthesis, separated by commas. The default adder module is determined by the first element of this variable.| | | SYNTH_WRAPPED_MULTIPLIERS| Specify the multiplier modules that can be used for synthesis, separated by commas. The default multiplier module is determined by the first element of this variable.| | | SYNTH_WRAPPED_OPERATORS| Synthesize multiple architectural options for each arithmetic operator in the design. These options are available for switching among in later stages of the flow.| | @@ -349,6 +350,7 @@ configuration file. - [PRE_SYNTH_TCL](#PRE_SYNTH_TCL) - [SDC_FILE](#SDC_FILE) - [SDC_GUT](#SDC_GUT) +- [SKIP_REPORT_METRICS](#SKIP_REPORT_METRICS) - [SLANG_PLUGIN_PATH](#SLANG_PLUGIN_PATH) - [SYNTH_ARGS](#SYNTH_ARGS) - [SYNTH_BLACKBOXES](#SYNTH_BLACKBOXES) @@ -371,6 +373,7 @@ configuration file. - [SYNTH_RETIME_MODULES](#SYNTH_RETIME_MODULES) - [SYNTH_SKIP_KEEP](#SYNTH_SKIP_KEEP) - [SYNTH_SLANG_ARGS](#SYNTH_SLANG_ARGS) +- [SYNTH_USE_SYN](#SYNTH_USE_SYN) - [SYNTH_WRAPPED_ADDERS](#SYNTH_WRAPPED_ADDERS) - [SYNTH_WRAPPED_MULTIPLIERS](#SYNTH_WRAPPED_MULTIPLIERS) - [TIEHI_CELL_AND_PORT](#TIEHI_CELL_AND_PORT) diff --git a/flow/Makefile b/flow/Makefile index 1bb45047a4..a6759a87f9 100644 --- a/flow/Makefile +++ b/flow/Makefile @@ -404,7 +404,11 @@ floorplan_to_place: $(RESULTS_DIR)/1_synth.odb $(RESULTS_DIR)/1_synth.sdc # ============================================================================== +ifeq ($(SYNTH_USE_SYN),1) +$(eval $(call do-step,1_synth,$(VERILOG_FILES) $(SDC_FILE) $(TECH_LEF) $(SC_LEF) $(ADDITIONAL_LEFS) $(LIB_FILES),synth_syn)) +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 diff --git a/flow/scripts/synth_syn.tcl b/flow/scripts/synth_syn.tcl new file mode 100644 index 0000000000..e5706d3faf --- /dev/null +++ b/flow/scripts/synth_syn.tcl @@ -0,0 +1,76 @@ +utl::set_metrics_stage "synth__{}" +source $::env(SCRIPTS_DIR)/load.tcl +erase_non_stage_variables synth + +source_env_var_if_exists PLATFORM_TCL +source $::env(SCRIPTS_DIR)/read_liberty.tcl + +read_lef $::env(TECH_LEF) +read_lef $::env(SC_LEF) +if { [env_var_exists_and_non_empty ADDITIONAL_LEFS] } { + foreach lef $::env(ADDITIONAL_LEFS) { + read_lef $lef + } +} +if { [env_var_exists_and_non_empty DONT_USE_CELLS] } { + set_dont_use $::env(DONT_USE_CELLS) +} + +# Setup verilog include directories +set vIdirsArgs "" +if { [env_var_exists_and_non_empty VERILOG_INCLUDE_DIRS] } { + foreach dir $::env(VERILOG_INCLUDE_DIRS) { + lappend vIdirsArgs "-I$dir" + } + set vIdirsArgs [join $vIdirsArgs] +} + +set elaborate_args [list \ + -D SYNTHESIS --compat=vcs --ignore-assertions --no-implicit-memories --top $::env(DESIGN_NAME) \ + {*}$vIdirsArgs {*}[env_var_or_empty VERILOG_DEFINES]] + +lappend elaborate_args {*}$::env(VERILOG_FILES) + +# Apply top-level parameters +dict for {key value} [env_var_or_empty VERILOG_TOP_PARAMS] { + lappend elaborate_args -G "$key=$value" +} + +# Apply module blackboxing based on module names as they appear +# in the input, that is before any module name mangling done +# by elaboration and synthesis +if { [env_var_exists_and_non_empty SYNTH_BLACKBOXES] } { + foreach m $::env(SYNTH_BLACKBOXES) { + lappend elaborate_args --blackboxed-module "$m" + } +} + +lappend elaborate_args {*}$::env(SYNTH_SLANG_ARGS) + +# If the sources are solely .v files, enable Verilog compatibility +set has_non_v_files false +foreach fn $::env(VERILOG_FILES) { + if { [file extension [string trim $fn]] != ".v" } { + set has_non_v_files true + } +} +if { !$has_non_v_files } { + lappend elaborate_args --std=1364-2005 +} + +sv_elaborate {*}$elaborate_args +syn::stats + +synthesize + +read_sdc $::env(SDC_FILE) +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 +# 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. +orfs_write_sdc $::env(RESULTS_DIR)/1_synth.sdc diff --git a/flow/scripts/variables.json b/flow/scripts/variables.json index 369ed53179..bd34b1bcaf 100644 --- a/flow/scripts/variables.json +++ b/flow/scripts/variables.json @@ -1196,6 +1196,7 @@ "default": 0, "description": "If set to 1, then metrics, report_metrics does nothing. Useful to speed up builds.\n", "stages": [ + "synth", "floorplan", "place", "cts", @@ -1366,6 +1367,13 @@ "synth" ] }, + "SYNTH_USE_SYN": { + "default": 0, + "description": "If set to 1, run synthesis using the \"syn\" tool built into OpenROAD (the synth_syn.tcl flow) instead of the default Yosys-based flow. Defaults to 0 (Yosys flow).\n", + "stages": [ + "synth" + ] + }, "SYNTH_WRAPPED_ADDERS": { "description": "Specify the adder modules that can be used for synthesis, separated by commas. The default adder module is determined by the first element of this variable.\n", "stages": [ diff --git a/flow/scripts/variables.yaml b/flow/scripts/variables.yaml index 6eee57b4c2..bbf1398f4d 100644 --- a/flow/scripts/variables.yaml +++ b/flow/scripts/variables.yaml @@ -115,6 +115,7 @@ SKIP_REPORT_METRICS: If set to 1, then metrics, report_metrics does nothing. Useful to speed up builds. stages: + - synth - floorplan - place - cts @@ -180,6 +181,14 @@ SYNTH_HIERARCHICAL: stages: - synth default: 0 +SYNTH_USE_SYN: + description: > + If set to 1, run synthesis using the "syn" tool built into OpenROAD + (the synth_syn.tcl flow) instead of the default Yosys-based flow. + Defaults to 0 (Yosys flow). + stages: + - synth + default: 0 SYNTH_MEMORY_MAX_BITS: description: > Maximum number of bits for memory synthesis. diff --git a/flow/util/genMetrics.py b/flow/util/genMetrics.py index 6424712e27..95e7c60aeb 100755 --- a/flow/util/genMetrics.py +++ b/flow/util/genMetrics.py @@ -209,6 +209,7 @@ def merge_jsons(root_path, output, files): with open(path, "r") as file: data = json.load(file) output.update(data) + return len(paths) != 0 def extract_metrics( @@ -246,21 +247,26 @@ def extract_metrics( # Synthesis # ========================================================================= + # Try sourcing metrics from OpenROAD's syn flow first, fall back to parsing + # Yosys reports otherwise + found_synthesis_json = merge_jsons(logPath, metrics_dict, "1_*.json") + # The new format (>= 0.57) with -hierarchy is: # cells - extractTagFromFile( - "synth__design__instance__count__stdcell", - metrics_dict, - "^\\s+(\\d+)\\s+[-0-9.]+\\s+\\S+\\s+\\S+\\s+cells$", - rptPath + "/synth_stat.txt", - ) + if not found_synthesis_json: + extractTagFromFile( + "synth__design__instance__count__stdcell", + metrics_dict, + "^\\s+(\\d+)\\s+[-0-9.]+\\s+\\S+\\s+\\S+\\s+cells$", + rptPath + "/synth_stat.txt", + ) - extractTagFromFile( - "synth__design__instance__area__stdcell", - metrics_dict, - "Chip area for (?:top )?module.*: +(\\S+)", - rptPath + "/synth_stat.txt", - ) + extractTagFromFile( + "synth__design__instance__area__stdcell", + metrics_dict, + "Chip area for (?:top )?module.*: +(\\S+)", + rptPath + "/synth_stat.txt", + ) # Netlist hashes: fingerprints of the canonical RTLIL (pre-ABC) and # the final post-synthesis Verilog so the rules-base.json check @@ -271,6 +277,7 @@ def extract_metrics( ) metrics_dict["synth__netlist__hash"] = file_sha1(resultPath + "/1_2_yosys.v") + # Clocks # ========================================================================= clk_list = read_sdc(resultPath + "/2_floorplan.sdc") From ca84ff7382407910674f15d7eda2da6bd1baf973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 1 Jun 2026 15:21:26 +0200 Subject: [PATCH 2/4] Opt in first 8 designs to use 'syn' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Povišer --- flow/designs/asap7/aes/config.mk | 3 +-- flow/designs/asap7/aes_lvt/config.mk | 2 +- flow/designs/asap7/gcd-ccs/rules-base.json | 12 +----------- flow/designs/asap7/gcd/config.mk | 1 + flow/designs/asap7/jpeg/config.mk | 1 + flow/designs/asap7/jpeg_lvt/config.mk | 1 + flow/designs/ihp-sg13g2/aes/config.mk | 2 ++ flow/designs/ihp-sg13g2/gcd/config.mk | 1 + flow/designs/nangate45/dynamic_node/config.mk | 1 + 9 files changed, 10 insertions(+), 14 deletions(-) diff --git a/flow/designs/asap7/aes/config.mk b/flow/designs/asap7/aes/config.mk index 8eb7038a73..c254c713c5 100644 --- a/flow/designs/asap7/aes/config.mk +++ b/flow/designs/asap7/aes/config.mk @@ -6,8 +6,6 @@ export DESIGN_NICKNAME = aes export VERILOG_FILES = $(sort $(wildcard $(DESIGN_HOME)/src/$(DESIGN_NICKNAME)/*.v)) export SDC_FILE = $(DESIGN_HOME)/$(PLATFORM)/$(DESIGN_NICKNAME)/constraint.sdc -export ABC_AREA = 1 - export CORE_UTILIZATION = 70 export CORE_ASPECT_RATIO = 1 export CORE_MARGIN = 2 @@ -27,3 +25,4 @@ else ifeq ($(FLOW_VARIANT),combine) $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)/blackbox/1_synth.v endif +export SYNTH_USE_SYN = 1 diff --git a/flow/designs/asap7/aes_lvt/config.mk b/flow/designs/asap7/aes_lvt/config.mk index 3f210c389b..aa5a147286 100644 --- a/flow/designs/asap7/aes_lvt/config.mk +++ b/flow/designs/asap7/aes_lvt/config.mk @@ -18,4 +18,4 @@ export ASAP7_USE_VT = LVT export RECOVER_POWER = 100 - +export SYNTH_USE_SYN = 1 diff --git a/flow/designs/asap7/gcd-ccs/rules-base.json b/flow/designs/asap7/gcd-ccs/rules-base.json index 519f25d02c..1857680da2 100644 --- a/flow/designs/asap7/gcd-ccs/rules-base.json +++ b/flow/designs/asap7/gcd-ccs/rules-base.json @@ -1,14 +1,4 @@ { - "synth__canonical_netlist__hash": { - "value": "7250dc152c2381ac020b86c78a5191b1c336244b", - "compare": "==", - "level": "warning" - }, - "synth__netlist__hash": { - "value": "a954b979a1a0eff89ed870fa50d202847b6807bf", - "compare": "==", - "level": "warning" - }, "synth__design__instance__area__stdcell": { "value": 43.1, "compare": "<=" @@ -109,4 +99,4 @@ "value": 63, "compare": "<=" } -} \ No newline at end of file +} diff --git a/flow/designs/asap7/gcd/config.mk b/flow/designs/asap7/gcd/config.mk index c98498e7a8..0f8de35b61 100644 --- a/flow/designs/asap7/gcd/config.mk +++ b/flow/designs/asap7/gcd/config.mk @@ -16,3 +16,4 @@ export PLACE_DENSITY = 0.35 # few last gasp iterations export SKIP_LAST_GASP ?= 1 +export SYNTH_USE_SYN = 1 diff --git a/flow/designs/asap7/jpeg/config.mk b/flow/designs/asap7/jpeg/config.mk index 04e7fb1ca9..831e1d4150 100644 --- a/flow/designs/asap7/jpeg/config.mk +++ b/flow/designs/asap7/jpeg/config.mk @@ -15,3 +15,4 @@ export PLACE_DENSITY = 0.75 export TNS_END_PERCENT = 100 +export SYNTH_USE_SYN = 1 diff --git a/flow/designs/asap7/jpeg_lvt/config.mk b/flow/designs/asap7/jpeg_lvt/config.mk index f09ae0d4bb..da51b9caaf 100644 --- a/flow/designs/asap7/jpeg_lvt/config.mk +++ b/flow/designs/asap7/jpeg_lvt/config.mk @@ -18,3 +18,4 @@ export RECOVER_POWER = 100 export ASAP7_USE_VT = LVT +export SYNTH_USE_SYN = 1 diff --git a/flow/designs/ihp-sg13g2/aes/config.mk b/flow/designs/ihp-sg13g2/aes/config.mk index 5acb53d84d..269fa64602 100644 --- a/flow/designs/ihp-sg13g2/aes/config.mk +++ b/flow/designs/ihp-sg13g2/aes/config.mk @@ -14,3 +14,5 @@ export TNS_END_PERCENT = 100 export USE_FILL = 1 export REMOVE_ABC_BUFFERS = 1 + +export SYNTH_USE_SYN = 1 diff --git a/flow/designs/ihp-sg13g2/gcd/config.mk b/flow/designs/ihp-sg13g2/gcd/config.mk index fc554fb8f8..a3d8798bbc 100644 --- a/flow/designs/ihp-sg13g2/gcd/config.mk +++ b/flow/designs/ihp-sg13g2/gcd/config.mk @@ -12,3 +12,4 @@ export TNS_END_PERCENT = 100 export SWAP_ARITH_OPERATORS = 1 export OPENROAD_HIERARCHICAL = 1 +export SYNTH_USE_SYN = 1 diff --git a/flow/designs/nangate45/dynamic_node/config.mk b/flow/designs/nangate45/dynamic_node/config.mk index 3e514eccf8..42a289122e 100644 --- a/flow/designs/nangate45/dynamic_node/config.mk +++ b/flow/designs/nangate45/dynamic_node/config.mk @@ -15,3 +15,4 @@ export TNS_END_PERCENT = 100 export SWAP_ARITH_OPERATORS = 1 export OPENROAD_HIERARCHICAL = 1 +export SYNTH_USE_SYN = 1 From c298a08f538bc4ec400eb01aff9335ee4789cfd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 3 Jun 2026 16:16:36 +0200 Subject: [PATCH 3/4] Streamline metrics emission for synth stage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Povišer --- flow/scripts/synth_odb.tcl | 5 ++++- flow/util/genMetrics.py | 24 +----------------------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/flow/scripts/synth_odb.tcl b/flow/scripts/synth_odb.tcl index d6f53cda3e..63bdc98cda 100644 --- a/flow/scripts/synth_odb.tcl +++ b/flow/scripts/synth_odb.tcl @@ -1,4 +1,4 @@ -utl::set_metrics_stage "floorplan__{}" +utl::set_metrics_stage "synth__{}" source $::env(SCRIPTS_DIR)/load.tcl erase_non_stage_variables synth load_design 1_2_yosys.v 1_2_yosys.sdc @@ -24,6 +24,9 @@ source_step_tcl PRE SYNTH # asap7/jpeg_lvt, asap7/swerv_wrapper, nangate45/ariane133). log_cmd eliminate_dead_logic +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 diff --git a/flow/util/genMetrics.py b/flow/util/genMetrics.py index 95e7c60aeb..fa54254809 100755 --- a/flow/util/genMetrics.py +++ b/flow/util/genMetrics.py @@ -209,7 +209,6 @@ def merge_jsons(root_path, output, files): with open(path, "r") as file: data = json.load(file) output.update(data) - return len(paths) != 0 def extract_metrics( @@ -246,27 +245,7 @@ def extract_metrics( # Synthesis # ========================================================================= - - # Try sourcing metrics from OpenROAD's syn flow first, fall back to parsing - # Yosys reports otherwise - found_synthesis_json = merge_jsons(logPath, metrics_dict, "1_*.json") - - # The new format (>= 0.57) with -hierarchy is: - # cells - if not found_synthesis_json: - extractTagFromFile( - "synth__design__instance__count__stdcell", - metrics_dict, - "^\\s+(\\d+)\\s+[-0-9.]+\\s+\\S+\\s+\\S+\\s+cells$", - rptPath + "/synth_stat.txt", - ) - - extractTagFromFile( - "synth__design__instance__area__stdcell", - metrics_dict, - "Chip area for (?:top )?module.*: +(\\S+)", - rptPath + "/synth_stat.txt", - ) + merge_jsons(logPath, metrics_dict, "1_*.json") # Netlist hashes: fingerprints of the canonical RTLIL (pre-ABC) and # the final post-synthesis Verilog so the rules-base.json check @@ -277,7 +256,6 @@ def extract_metrics( ) metrics_dict["synth__netlist__hash"] = file_sha1(resultPath + "/1_2_yosys.v") - # Clocks # ========================================================================= clk_list = read_sdc(resultPath + "/2_floorplan.sdc") From a3bec389f846e51edb57f2bc56170459dbbae2a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 3 Jun 2026 19:19:41 +0200 Subject: [PATCH 4/4] Relax gcd-ccs metrics for syn switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Povišer --- flow/designs/asap7/gcd-ccs/rules-base.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow/designs/asap7/gcd-ccs/rules-base.json b/flow/designs/asap7/gcd-ccs/rules-base.json index 1857680da2..8dc9005b74 100644 --- a/flow/designs/asap7/gcd-ccs/rules-base.json +++ b/flow/designs/asap7/gcd-ccs/rules-base.json @@ -28,7 +28,7 @@ "compare": "<=" }, "cts__timing__setup__ws": { - "value": -79.2, + "value": -90.0, "compare": ">=" }, "cts__timing__setup__tns": {