From 237bbe348f76618e8f28b644502113e41c7c2c47 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Mon, 16 Dec 2024 12:37:03 +0200 Subject: [PATCH] feat: expand synthesis options, initial state elements in cli (#604) * `Yosys.*Synthesis` * Created new variable `SYNTH_HIERARCHY_MODE`, replacing `SYNTH_NO_FLAT`. There are three options, `flatten`, `deferred_flatten` and `keep`. The first two correspond to `SYNTH_NO_FLAT` being false and true respectively. The third keeps the hierarchy in the final netlist. * Created new variable `SYNTH_TIE_UNDEFINED` to customize whether undefined and undriven values are tied low, high, or left as-is. * Created new variable `SYNTH_WRITE_NOATTR` to allow attributes to be propagated to the final netlist. * Created `Yosys.Resynthesis` * Like `Yosys.Synthesis`, but uses the current input state netlist as an input instead of RTL files ## CLI * Added new option: `-e`/`--initial-state-element-override`: allows an element in the initial state to be overridden straight from the commandline. --- While this is unorthodox, this will be release 2.3.0. The reasoning for this is that these options are critical for an on-going tapeout process. --- Changelog.md | 30 ++++ flake.lock | 23 ++- flake.nix | 2 +- nix/create-shell.nix | 5 +- openlane/__main__.py | 52 ++++-- openlane/flows/cli.py | 12 +- openlane/scripts/openroad/gpl.tcl | 4 + .../scripts/openroad/rsz_timing_postcts.tcl | 38 +++-- .../scripts/openroad/rsz_timing_postgrt.tcl | 36 ++-- openlane/scripts/pyosys/synthesize.py | 161 ++++++++++++++++-- openlane/steps/openroad.py | 17 ++ openlane/steps/pyosys.py | 50 +++++- pyproject.toml | 4 +- 13 files changed, 347 insertions(+), 87 deletions(-) diff --git a/Changelog.md b/Changelog.md index 5e4944483..53e1d64c4 100644 --- a/Changelog.md +++ b/Changelog.md @@ -14,6 +14,36 @@ ## Documentation --> +# 2.3.0 + +## Steps + +* `OpenROAD.GlobalPlacement` + + * Exposed `-routability_check_overflow` argument as new variable + `PL_ROUTABILITY_OVERFLOW_THRESHOLD`. + +* `Yosys.*Synthesis` + + * Created new variable `SYNTH_HIERARCHY_MODE`, replacing `SYNTH_NO_FLAT`. + There are three options, `flatten`, `deferred_flatten` and `keep`. The first + two correspond to `SYNTH_NO_FLAT` being false and true respectively. The + third keeps the hierarchy in the final netlist. + * Created new variable `SYNTH_TIE_UNDEFINED` to customize whether undefined + and undriven values are tied low, high, or left as-is. + * Created new variable `SYNTH_WRITE_NOATTR` to allow attributes to be + propagated to the final netlist. + +* Created `Yosys.Resynthesis` + + * Like `Yosys.Synthesis`, but uses the current input state netlist as an input + instead of RTL files + +## CLI + +* Added new option: `-e`/`--initial-state-element-override`: allows an element + in the initial state to be overridden straight from the commandline. + # 2.2.9 ## Steps diff --git a/flake.lock b/flake.lock index a7eaab0ff..700f92bbb 100644 --- a/flake.lock +++ b/flake.lock @@ -37,17 +37,16 @@ }, "ioplace-parser": { "inputs": { - "nixpkgs": [ - "nix-eda", - "nixpkgs" + "nix-eda": [ + "nix-eda" ] }, "locked": { - "lastModified": 1719837045, - "narHash": "sha256-ya2KEXKAIn8oYUi9G9TaUcQAEfGkbENCgXF/V0d/kws=", + "lastModified": 1730973673, + "narHash": "sha256-F7jux5RLKTFEcXEQ2mRIH83zlSAT+uffYsf/XnKgoiU=", "owner": "efabless", "repo": "ioplace_parser", - "rev": "570fd3e352926f57e6eecbb8bd3892a5dec375b7", + "rev": "e31eb8553caba31c08416d89e31b6aec58002755", "type": "github" }, "original": { @@ -82,11 +81,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1728905391, - "narHash": "sha256-iox9yGNG4MwSKhQuwegLcDW6wVGzfdBPrh8SrhSLA8c=", + "lastModified": 1730973643, + "narHash": "sha256-8ZeUxluUbUD3IF0thq4Alioy3JaEVR0AY5+7PuFypBE=", "owner": "efabless", "repo": "nix-eda", - "rev": "0814aa6c1c7d556aa08212cc875063cff62cb9b0", + "rev": "1f8771758e26ad96da4947ed1b17e3942f978cfa", "type": "github" }, "original": { @@ -129,11 +128,11 @@ ] }, "locked": { - "lastModified": 1724178650, - "narHash": "sha256-p+Li/z3l7ShRSIKUrxVK+7uGhSvqPE7jOW4FA4k3SIw=", + "lastModified": 1728904439, + "narHash": "sha256-e6QXMol9kbrJplYamSDfz+X/BDhgP66rHmjkeIZlaNI=", "owner": "efabless", "repo": "volare", - "rev": "0090420799258d29adca54c8951d38bb8b605aeb", + "rev": "7458169adc63dfac4ecfcb1c967972c6d8cd888f", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 708cd1268..e3210fd60 100644 --- a/flake.nix +++ b/flake.nix @@ -33,7 +33,7 @@ }; inputs.libparse.inputs.nixpkgs.follows = "nix-eda/nixpkgs"; - inputs.ioplace-parser.inputs.nixpkgs.follows = "nix-eda/nixpkgs"; + inputs.ioplace-parser.inputs.nix-eda.follows = "nix-eda"; inputs.volare.inputs.nixpkgs.follows = "nix-eda/nixpkgs"; inputs.devshell.inputs.nixpkgs.follows = "nix-eda/nixpkgs"; diff --git a/nix/create-shell.nix b/nix/create-shell.nix index 57f5fc49e..f3549551f 100644 --- a/nix/create-shell.nix +++ b/nix/create-shell.nix @@ -14,8 +14,9 @@ { extra-packages ? [], extra-python-packages ? [], + extra-env ? [], openlane-plugins ? [], - include-openlane ? true + include-openlane ? true, }: ({ lib, git, @@ -62,7 +63,7 @@ in name = "NIX_PYTHONPATH"; value = "${openlane-env-sitepackages}"; } - ]; + ] ++ extra-env; devshell.interactive.PS1 = { text = ''PS1="${prompt}"''; }; diff --git a/openlane/__main__.py b/openlane/__main__.py index 86780f0e5..a1dcef55b 100644 --- a/openlane/__main__.py +++ b/openlane/__main__.py @@ -23,12 +23,7 @@ from functools import partial from typing import Any, Dict, Sequence, Tuple, Type, Optional, List, Union -from click import ( - Parameter, - Context, - Path, - pass_context, -) +import click from cloup import ( option, option_group, @@ -40,7 +35,7 @@ from .__version__ import __version__ -from .state import State +from .state import State, DesignFormat from .logging import ( debug, err, @@ -56,7 +51,7 @@ def run( - ctx: Context, + ctx: click.Context, flow_name: Optional[str], pdk_root: Optional[str], pdk: str, @@ -73,6 +68,7 @@ def run( config_override_strings: List[str], _force_run_dir: Optional[str], design_dir: Optional[str], + initial_state_element_override: Sequence[str], view_save_path: Optional[str] = None, ef_view_save_path: Optional[str] = None, ): @@ -97,6 +93,27 @@ def run( if flow_description is None: flow_description = "Classic" + if len(initial_state_element_override): + if with_initial_state is None: + with_initial_state = State() + overrides = {} + for element in initial_state_element_override: + element_split = element.split("=", maxsplit=1) + if len(element_split) < 2: + err(f"Invalid initial state element override: '{element}'.") + ctx.exit(1) + df_id, path = element_split + design_format = DesignFormat.by_id(df_id) + if design_format is None: + err(f"Invalid design format ID: '{df_id}'.") + ctx.exit(1) + overrides[design_format] = common.Path(path) + + with_initial_state = with_initial_state.__class__( + with_initial_state, + overrides=overrides, + ) + TargetFlow: Type[Flow] if isinstance(flow_description, str): @@ -170,7 +187,7 @@ def run( flow._save_snapshot_ef(evsp) -def print_version(ctx: Context, param: Parameter, value: bool): +def print_version(ctx: click.Context, param: click.Parameter, value: bool): if not value: return @@ -198,8 +215,8 @@ def print_version(ctx: Context, param: Parameter, value: bool): def print_bare_version( - ctx: Context, - param: Parameter, + ctx: click.Context, + param: click.Parameter, value: bool, ): if not value: @@ -209,7 +226,7 @@ def print_bare_version( def run_included_example( - ctx: Context, + ctx: click.Context, smoke_test: bool, example: Optional[str], **kwargs, @@ -285,8 +302,8 @@ def run_included_example( def cli_in_container( - ctx: Context, - param: Parameter, + ctx: click.Context, + param: click.Parameter, value: bool, ): if not value: @@ -331,14 +348,14 @@ def cli_in_container( o( "--save-views-to", "view_save_path", - type=Path(file_okay=False, dir_okay=True), + type=click.Path(file_okay=False, dir_okay=True), default=None, help="A directory to copy the final views to, where each format is saved under a directory named after the corner ID (much like the 'final' directory after running a flow.)", ), o( "--ef-save-views-to", "ef_view_save_path", - type=Path(file_okay=False, dir_okay=True), + type=click.Path(file_okay=False, dir_okay=True), default=None, help="A directory to copy the final views to in the Efabless format, compatible with Caravel User Project.", ), @@ -401,8 +418,9 @@ def cli_in_container( _enable_debug_flags=True, sequential_flow_reproducible=True, enable_overwrite_flag=True, + enable_initial_state_element=True, ) -@pass_context +@click.pass_context def cli(ctx, /, **kwargs): """ Runs an OpenLane flow via the commandline using a design configuration diff --git a/openlane/flows/cli.py b/openlane/flows/cli.py index 09e1b8d0d..6378c83d2 100644 --- a/openlane/flows/cli.py +++ b/openlane/flows/cli.py @@ -139,6 +139,7 @@ def cloup_flow_opts( volare_pdk_override: Optional[str] = None, _enable_debug_flags: bool = False, enable_overwrite_flag: bool = False, + enable_initial_state_element: bool = False, ) -> Decorator: """ Creates a wrapper that appends a number of OpenLane flow-related flags to a @@ -214,7 +215,7 @@ def decorate(f): ), default=None, callback=initial_state_cb, - help="Use this JSON file as an initial state. If this is not specified, the latest `state_out.json` of the run directory will be used if available.", + help="Use this JSON file as an initial state. If this is not specified, the latest `state_out.json` of the run directory will be used. If none exist, an empty initial state is created.", )(f) f = o( "--design-dir", @@ -381,6 +382,15 @@ def decorate(f): callback=set_worker_count_cb, expose_value=False, )(f) + if enable_initial_state_element: + f = o( + "-e", + "--initial-state-element-override", + type=str, + multiple=True, + default=(), + help="Elements to override in the used initial state in the format DESIGN_FORMAT_ID=PATH", + )(f) if accept_config_files: f = argument( "config_files", diff --git a/openlane/scripts/openroad/gpl.tcl b/openlane/scripts/openroad/gpl.tcl index 1652456d3..ad1015e6a 100755 --- a/openlane/scripts/openroad/gpl.tcl +++ b/openlane/scripts/openroad/gpl.tcl @@ -47,6 +47,9 @@ if { [info exists ::env(PL_ROUTABILITY_DRIVEN)] && $::env(PL_ROUTABILITY_DRIVEN) set_macro_extension $::env(GRT_MACRO_EXTENSION) source $::env(SCRIPTS_DIR)/openroad/common/set_layer_adjustments.tcl lappend arg_list -routability_driven + if { [info exists ::env(PL_ROUTABILITY_OVERFLOW_THRESHOLD)] } { + lappend arg_list -routability_check_overflow $::env(PL_ROUTABILITY_OVERFLOW_THRESHOLD) + } } if { $::env(PL_SKIP_INITIAL_PLACEMENT) } { @@ -72,6 +75,7 @@ lappend arg_list -pad_right $cell_pad_side lappend arg_list -pad_left $cell_pad_side lappend arg_list -init_wirelength_coef $::env(PL_WIRE_LENGTH_COEF) +puts "+ global_placement $arg_list" global_placement {*}$arg_list diff --git a/openlane/scripts/openroad/rsz_timing_postcts.tcl b/openlane/scripts/openroad/rsz_timing_postcts.tcl index 5cc82b427..be22825ea 100644 --- a/openlane/scripts/openroad/rsz_timing_postcts.tcl +++ b/openlane/scripts/openroad/rsz_timing_postcts.tcl @@ -29,26 +29,32 @@ source $::env(SCRIPTS_DIR)/openroad/common/set_rc.tcl estimate_parasitics -placement # Resize -set arg_list [list] -lappend arg_list -verbose -lappend arg_list -setup -lappend arg_list -setup_margin $::env(PL_RESIZER_SETUP_SLACK_MARGIN) -lappend arg_list -max_buffer_percent $::env(PL_RESIZER_SETUP_MAX_BUFFER_PCT) +set setup_args [list] +lappend setup_args -verbose +lappend setup_args -setup +lappend setup_args -setup_margin $::env(PL_RESIZER_SETUP_SLACK_MARGIN) +lappend setup_args -max_buffer_percent $::env(PL_RESIZER_SETUP_MAX_BUFFER_PCT) if { $::env(PL_RESIZER_GATE_CLONING) != 1 } { - lappend arg_list -skip_gate_cloning + lappend setup_args -skip_gate_cloning } -repair_timing {*}$arg_list - -set arg_list [list] -lappend arg_list -verbose -lappend arg_list -hold -lappend arg_list -setup_margin $::env(PL_RESIZER_SETUP_SLACK_MARGIN) -lappend arg_list -hold_margin $::env(PL_RESIZER_HOLD_SLACK_MARGIN) -lappend arg_list -max_buffer_percent $::env(PL_RESIZER_HOLD_MAX_BUFFER_PCT) + +set hold_args [list] +lappend hold_args -verbose +lappend hold_args -hold +lappend hold_args -setup_margin $::env(PL_RESIZER_SETUP_SLACK_MARGIN) +lappend hold_args -hold_margin $::env(PL_RESIZER_HOLD_SLACK_MARGIN) +lappend hold_args -max_buffer_percent $::env(PL_RESIZER_HOLD_MAX_BUFFER_PCT) if { $::env(PL_RESIZER_ALLOW_SETUP_VIOS) == 1 } { - lappend arg_list -allow_setup_violations + lappend hold_args -allow_setup_violations +} + +if { $::env(PL_RESIZER_FIX_HOLD_FIRST) == 1 } { + repair_timing {*}$hold_args + repair_timing {*}$setup_args +} else { + repair_timing {*}$setup_args + repair_timing {*}$hold_args } -repair_timing {*}$arg_list # Legalize source $::env(SCRIPTS_DIR)/openroad/common/dpl.tcl diff --git a/openlane/scripts/openroad/rsz_timing_postgrt.tcl b/openlane/scripts/openroad/rsz_timing_postgrt.tcl index aa85a38a3..2ad629281 100644 --- a/openlane/scripts/openroad/rsz_timing_postgrt.tcl +++ b/openlane/scripts/openroad/rsz_timing_postgrt.tcl @@ -32,26 +32,32 @@ source $::env(SCRIPTS_DIR)/openroad/common/grt.tcl estimate_parasitics -global_routing # Resize -set arg_list [list] -lappend arg_list -verbose -lappend arg_list -setup -lappend arg_list -setup_margin $::env(GRT_RESIZER_SETUP_SLACK_MARGIN) -lappend arg_list -max_buffer_percent $::env(GRT_RESIZER_SETUP_MAX_BUFFER_PCT) +set setup_args [list] +lappend setup_args -verbose +lappend setup_args -setup +lappend setup_args -setup_margin $::env(GRT_RESIZER_SETUP_SLACK_MARGIN) +lappend setup_args -max_buffer_percent $::env(GRT_RESIZER_SETUP_MAX_BUFFER_PCT) if { $::env(GRT_RESIZER_GATE_CLONING) != 1 } { - lappend arg_list -skip_gate_cloning + lappend setup_args -skip_gate_cloning } -repair_timing {*}$arg_list -set arg_list [list] -lappend arg_list -verbose -lappend arg_list -hold -lappend arg_list -setup_margin $::env(GRT_RESIZER_SETUP_SLACK_MARGIN) -lappend arg_list -hold_margin $::env(GRT_RESIZER_HOLD_SLACK_MARGIN) -lappend arg_list -max_buffer_percent $::env(GRT_RESIZER_HOLD_MAX_BUFFER_PCT) +set hold_args [list] +lappend hold_args -verbose +lappend hold_args -hold +lappend hold_args -setup_margin $::env(GRT_RESIZER_SETUP_SLACK_MARGIN) +lappend hold_args -hold_margin $::env(GRT_RESIZER_HOLD_SLACK_MARGIN) +lappend hold_args -max_buffer_percent $::env(GRT_RESIZER_HOLD_MAX_BUFFER_PCT) if { $::env(GRT_RESIZER_ALLOW_SETUP_VIOS) == 1 } { - lappend arg_list -allow_setup_violations + lappend hold_args -allow_setup_violations +} + +if { $::env(GRT_RESIZER_FIX_HOLD_FIRST) == 1 } { + repair_timing {*}$hold_args + repair_timing {*}$setup_args +} else { + repair_timing {*}$setup_args + repair_timing {*}$hold_args } -repair_timing {*}$arg_list # Re-DPL and GRT source $::env(SCRIPTS_DIR)/openroad/common/dpl.tcl diff --git a/openlane/scripts/pyosys/synthesize.py b/openlane/scripts/pyosys/synthesize.py index d0ed67f2d..600dffed1 100644 --- a/openlane/scripts/pyosys/synthesize.py +++ b/openlane/scripts/pyosys/synthesize.py @@ -12,7 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Parts of this file adapted from https://github.com/YosysHQ/yosys/blob/master/techlibs/common/synth.cc +# Parts of this file adapted from: +# +# * https://github.com/YosysHQ/yosys/blob/master/techlibs/common/synth.cc +# * https://github.com/YosysHQ/yosys/blob/master/passes/opt/opt.cc # # Copyright (C) 2012 Claire Xenia Wolf # @@ -57,7 +60,91 @@ def openlane_proc(d: ys.Design, report_dir: str): d.run_pass("opt_expr") # Optimize expressions -def openlane_synth(d, top, flatten, report_dir, *, booth=False, abc_dff=False): +def openlane_opt( + d, + fast=False, + mux_undef=False, + mux_bool=False, + undriven=False, + fine=False, + purge=False, + noclkinv=False, + keepdc=False, + share_all=False, + nodffe=False, + nosdff=False, + sat=False, + opt_share=False, + noff=False, +): + expr_args = [] + merge_args = [] + reduce_args = [] + clean_args = [] + dff_args = [] + if purge: + clean_args.append("-purge") + if mux_undef: + expr_args.append("-mux_undef") + if mux_bool: + expr_args.append("-mux_bool") + if undriven: + expr_args.append("-undriven") + if fine: + expr_args.append("-fine") + reduce_args.append("-fine") + if noclkinv: + expr_args.append("-noclkinv") + if keepdc: + expr_args.append("-keepdc") + dff_args.append("-keepdc") + merge_args.append("-keepdc") + if nodffe: + dff_args.append("-nodffe") + if nosdff: + dff_args.append("-nosdff") + if sat: + dff_args.append("-sat") + if share_all: + merge_args.append("-share_all") + if fast: + while True: + d.run_pass("opt_expr", *expr_args) + d.run_pass("opt_merge", *merge_args) + d.scratchpad_unset("opt.did_something") + if not noff: + d.run_pass("opt_dff", *dff_args) + if not d.scratchpad_get_bool("opt.did_something"): + break + d.run_pass("opt_clean", *clean_args) + ys.log_header(d, "Rerunning OPT passes (Removed registers in this run.)") + d.run_pass("opt_clean", *clean_args) + else: + d.run_pass("opt_expr", *expr_args) + d.run_pass("opt_merge", "-nomux", *merge_args) + while True: + d.scratchpad_unset("opt.did_something") + d.run_pass("opt_muxtree") + d.run_pass("opt_reduce", *reduce_args) + d.run_pass("opt_merge", *merge_args) + if opt_share: + d.run_pass("opt_share") + if not noff: + d.run_pass("opt_dff", *dff_args) + d.run_pass("opt_clean", *clean_args) + d.run_pass("opt_expr", *expr_args) + if not d.scratchpad_get_bool("opt.did_something"): + break + ys.log_header(d, "Rerunning OPT passes. (Maybe there is more to do…)") + + d.optimize() + d.sort() + d.check() + + +def openlane_synth( + d, top, flatten, report_dir, *, booth=False, abc_dff=False, undriven=True +): d.run_pass("hierarchy", "-check", "-top", top, "-nokeep_prints", "-nokeep_asserts") openlane_proc(d, report_dir) @@ -69,9 +156,9 @@ def openlane_synth(d, top, flatten, report_dir, *, booth=False, abc_dff=False): d.run_pass("opt_clean") # Clean up after optimization # Perform various logic optimization passes - d.run_pass("opt", "-nodffe", "-nosdff") # Optimize logic excluding flip-flops + openlane_opt(d, nodffe=True, nosdff=True) d.run_pass("fsm") # Identify and optimize finite state machines - d.run_pass("opt") # Additional logic optimization + openlane_opt(d) d.run_pass("wreduce") # Reduce logic using algebraic rewriting d.run_pass("peepopt") # Perform local peephole optimization d.run_pass("opt_clean") # Clean up after optimization @@ -79,21 +166,38 @@ def openlane_synth(d, top, flatten, report_dir, *, booth=False, abc_dff=False): d.run_pass("booth") d.run_pass("alumacc") # Optimize arithmetic logic unitsb d.run_pass("share") # Share logic across the design - d.run_pass("opt") # More logic optimization + openlane_opt(d) # Memory optimization d.run_pass("memory", "-nomap") # Analyze memories but don't map them yet d.run_pass("opt_clean") # Clean up after memory analysis # Perform more aggressive optimization with faster runtime - d.run_pass("opt", "-fast", "-full") # Fast and comprehensive optimization + openlane_opt( + d, + fast=True, + opt_share=True, # affects opt_share + mux_undef=True, # affects opt_expr + mux_bool=True, # affects opt_expr + undriven=undriven, # affects opt_expr + fine=True, # affects opt_expr, opt_reduce + ) # Technology mapping d.run_pass("memory_map") # Map memories to standard cells - d.run_pass("opt", "-full") # More optimization after memory mapping - d.run_pass("techmap") # Map logic to standard cells from the technology library - d.run_pass("opt", "-fast") # Fast optimization after technology mapping - d.run_pass("opt", "-fast") # More fast optimization + openlane_opt( + d, + opt_share=True, # affects opt_share + mux_undef=True, # affects opt_expr + mux_bool=True, # affects opt_expr + undriven=undriven, # affects opt_expr + fine=True, # affects opt_expr, opt_reduce + ) + d.run_pass("techmap") + + # Couple more fast opt iterations + openlane_opt(d, fast=True) + openlane_opt(d, fast=True) d.run_pass( "abc", "-fast", *(["-dff"] if abc_dff else []) @@ -111,11 +215,13 @@ def openlane_synth(d, top, flatten, report_dir, *, booth=False, abc_dff=False): @click.option("--config-in", type=click.Path(exists=True), required=True) @click.option("--extra-in", type=click.Path(exists=True), required=True) @click.option("--lighter-dff-map", type=click.Path(exists=True), required=False) +@click.argument("inputs", nargs=-1) def synthesize( output, config_in, extra_in, lighter_dff_map, + inputs, ): config = json.load(open(config_in)) extra = json.load(open(extra_in)) @@ -150,7 +256,17 @@ def synthesize( ys.log(f"[INFO] Using SDC file '{sdc_path}' for ABC…") - if verilog_files := config.get("VERILOG_FILES"): + if len(inputs): + d.read_verilog_files( + inputs, + top=config["DESIGN_NAME"], + synth_parameters=[], + includes=includes, + defines=defines, + use_synlig=False, + synlig_defer=False, + ) + elif verilog_files := config.get("VERILOG_FILES"): d.read_verilog_files( verilog_files, top=config["DESIGN_NAME"], @@ -203,10 +319,13 @@ def synthesize( d.tee("stat", "-json", *lib_arguments, o=os.path.join(report_dir, "stat.json")) d.tee("stat", *lib_arguments, o=os.path.join(report_dir, "stat.rpt")) + noattr_flag = [] + if config["SYNTH_WRITE_NOATTR"]: + noattr_flag.append("-noattr") + d.run_pass( "write_verilog", - "-noattr", - "-noexpr", + *noattr_flag, "-nohex", "-nodec", "-defparam", @@ -232,10 +351,11 @@ def synthesize( openlane_synth( d, config["DESIGN_NAME"], - not config["SYNTH_NO_FLAT"], + config["SYNTH_HIERARCHY_MODE"] == "flatten", report_dir, booth=config["SYNTH_MUL_BOOTH"], abc_dff=config["SYNTH_ABC_DFF"], + undriven=config.get("SYNTH_TIE_UNDEFINED") is not None, ) d.run_pass("delete", "t:$print") @@ -305,7 +425,10 @@ def run_strategy(d): *(["-dff"] if config["SYNTH_ABC_DFF"] else []), ) - d.run_pass("setundef", "-zero") + if value := config.get("SYNTH_TIE_UNDEFINED"): + flag = "-zero" if value == "low" else "-one" + d.run_pass("setundef", flag) + d.run_pass( "hilomap", "-hicell", @@ -336,9 +459,13 @@ def run_strategy(d): # sc_mcu7t5v0__and3_1_A3_Z_gf180mcu_fd_sc_mcu7t5v0__buf_1_I_Z d.run_pass("autoname") + noattr_flag = [] + if config["SYNTH_WRITE_NOATTR"]: + noattr_flag.append("-noattr") + d.run_pass( "write_verilog", - "-noattr", + *noattr_flag, "-noexpr", "-nohex", "-nodec", @@ -349,7 +476,7 @@ def run_strategy(d): run_strategy(d) - if config["SYNTH_NO_FLAT"]: + if config["SYNTH_HIERARCHY_MODE"] == "deferred_flatten": # Resynthesize, flattening d_flat = ys.Design() d_flat.add_blackbox_models(blackbox_models, includes=includes, defines=defines) diff --git a/openlane/steps/openroad.py b/openlane/steps/openroad.py index 11cd6efe3..6e687cc2a 100644 --- a/openlane/steps/openroad.py +++ b/openlane/steps/openroad.py @@ -1287,6 +1287,11 @@ class GlobalPlacement(_GlobalPlacement): "Specifies whether the placer should use routability driven placement.", default=True, ), + Variable( + "PL_ROUTABILITY_OVERFLOW_THRESHOLD", + Optional[Decimal], + "Sets overflow threshold for routability mode.", + ), ] @@ -2288,6 +2293,12 @@ class ResizerTimingPostCTS(ResizerStep): "Enables gate cloning when attempting to fix setup violations", default=True, ), + Variable( + "PL_RESIZER_FIX_HOLD_FIRST", + bool, + "Experimental: attempt to fix hold violations before setup violations, which may lead to better timing results.", + default=False, + ), ] def get_script_path(self): @@ -2361,6 +2372,12 @@ class ResizerTimingPostGRT(ResizerStep): "Gates running global routing after resizer steps. May be useful to disable for designs where global routing takes non-trivial time.", default=True, ), + Variable( + "GRT_RESIZER_FIX_HOLD_FIRST", + bool, + "Experimental: attempt to fix hold violations before setup violations, which may lead to better timing results.", + default=False, + ), ] def get_script_path(self): diff --git a/openlane/steps/pyosys.py b/openlane/steps/pyosys.py index 8f76ddc21..353fbab1f 100644 --- a/openlane/steps/pyosys.py +++ b/openlane/steps/pyosys.py @@ -412,10 +412,16 @@ class SynthesisCommon(VerilogStep): default=False, ), Variable( - "SYNTH_NO_FLAT", - bool, - "A flag that disables flattening the hierarchy during synthesis, only flattening it after synthesis, mapping and optimizations.", - default=False, + "SYNTH_HIERARCHY_MODE", + Literal["flatten", "deferred_flatten", "keep"], + "Affects how hierarchy is maintained throughout and after synthesis. 'flatten' flattens it during and after synthesis. 'deferred_flatten' flattens it after synthesis. 'keep' never flattens it.", + default="flatten", + deprecated_names=[ + ( + "SYNTH_NO_FLAT", + lambda x: "deferred_flatten" if x else "flatten", + ) + ], ), Variable( "SYNTH_SHARE_RESOURCES", @@ -453,6 +459,18 @@ class SynthesisCommon(VerilogStep): "Runs the booth pass as part of synthesis: See https://yosyshq.readthedocs.io/projects/yosys/en/latest/cmd/booth.html", default=False, ), + Variable( + "SYNTH_TIE_UNDEFINED", + Optional[Literal["high", "low"]], + "Whether to tie undefined values low or high. Explicitly provide null if you wish to simply leave them undriven.", + default="low", + ), + Variable( + "SYNTH_WRITE_NOATTR", + bool, + "If true, Verilog-2001 attributes are omitted from output netlists. Some utilities do not support attributes.", + default=True, + ), # Variable( # "SYNTH_SDC_FILE", # Optional[Path], @@ -547,6 +565,30 @@ class Synthesis(SynthesisCommon): config_vars = SynthesisCommon.config_vars + verilog_rtl_cfg_vars +@Step.factory.register() +class Resynthesis(SynthesisCommon): + """ + Like ``Synthesis``, but operates on the input netlist instead of RTL files. + Useful to process/elaborate on netlists generated by tools other than Yosys. + + Some metrics will also be extracted and updated, namely: + + * ``design__instance__count`` + * ``design__instance_unmapped__count`` + * ``design__instance__area`` + """ + + id = "Yosys.Resynthesis" + name = "Resynthesis" + + config_vars = SynthesisCommon.config_vars + + inputs = [DesignFormat.NETLIST] + + def get_command(self, state_in): + return super().get_command(state_in) + [state_in[DesignFormat.NETLIST]] + + @Step.factory.register() class VHDLSynthesis(SynthesisCommon): """ diff --git a/pyproject.toml b/pyproject.toml index 4ce86e2be..6eaf08819 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "openlane" -version = "2.2.9" +version = "2.3.0" description = "An infrastructure for implementing chip design flows" authors = ["Efabless Corporation and Contributors "] readme = "Readme.md" @@ -24,7 +24,7 @@ psutil = ">=5.9.0" httpx = ">=0.22.0,<0.28" klayout = ">=0.29.0,<0.30.0" rapidfuzz = ">=3.9.0,<4" -ioplace-parser = "0.3.0" +ioplace-parser = ">=0.3.0,<0.5.0" yamlcore = "^0.0.2"