Skip to main content

Synthesis

rtl_buddy provides a tool-agnostic synthesis flow that mirrors the simulation workflow. Synthesis runs are described in synth.yaml files; tool-specific defaults and PDK library paths live in root_config.yaml.

Supported backends

rtl_buddy ships two synthesis backends selectable via tool: in synth.yaml:

tool:BackendMulti-clock SDCReports
yosysYosys + ABCWorkaround (min period)Gates, Area, WNS
openroadYosys (stage 1) + OpenROAD STA (stage 2)Native read_sdcGates, Area, WNS, TNS

The OpenROAD backend removes the multi-clock SDC workaround: stage 1 maps RTL to a gate-level netlist with Yosys, stage 2 feeds that netlist into OpenROAD which loads the SDC natively and reports WNS (actual worst slack from report_checks) and TNS (total negative slack).

Installing Yosys

rtl_buddy uses the rtl-buddy fork of Yosys, which tracks upstream with rtl-buddy-specific patches. Build from source:

# Install deps with brew. Adjust to your package manager as needed.
brew install cmake python tcl-tk libffi readline

# Clone, build and install
git clone --recursive https://github.com/rtl-buddy/yosys.git
cd yosys
make config-clang # or `make config-gcc` on Linux
make -j 8 # adjust to no. of CPU cores if needed
make install # installs to /usr/local/bin/yosys

Verify the install:

yosys --version

The yosys binary must be on PATH when rb synth is invoked.

Installing OpenROAD

OpenROAD is required only for the openroad backend. It must be built from source on macOS — no official binaries are published. See the build notes in your project's tools/openroad/SETUP_OSX.md (the starter template uses that filename) for the full procedure. After building, symlink the binary to a directory on PATH:

ln -s /path/to/OpenROAD/build/bin/openroad /usr/local/bin/openroad
openroad -version

The openroad binary must be on PATH when rb synth is invoked with tool: "openroad".

Synthesis config: synth.yaml

A synth.yaml file defines one or more synthesis runs for a block.

rtl-buddy-filetype: synth_config

syntheses:
# Technology-independent run
- name: "sandbox_synth"
desc: "Synthesize sandbox module with Yosys"
model: "test_module"
model_path: "../../design/sandbox/models.yaml"
tool: "yosys"
reglvl: 0

# Technology-mapped run targeting SKY130 (Yosys backend)
- name: "sandbox_sky130"
desc: "Synthesize sandbox module targeting SKY130 HD TT corner"
model: "test_module"
model_path: "../../design/sandbox/models.yaml"
tool: "yosys"
libraries:
- "sky130hd_tt"
constraints: "constraints.sdc"
params:
WIDTH: 8
defines:
TARGET_SYNTH: 1
reglvl: 0
tool_overrides:
yosys:
synth_args: "-flatten"

# Technology-mapped run with OpenROAD backend (native multi-clock SDC, WNS + TNS)
- name: "sandbox_openroad"
desc: "Synthesize sandbox module with OpenROAD timing analysis"
model: "test_module"
model_path: "../../design/sandbox/models.yaml"
tool: "openroad"
libraries:
- "sky130hd_tt"
constraints: "constraints.sdc"
reglvl: 0

Synthesis fields

FieldDescription
nameRun identifier used on the command line and in artefact paths
descHuman-readable description
modelModel name from models.yaml; also used as the synthesis top module
model_pathPath to models.yaml, resolved relative to the synth.yaml directory
toolSynthesis tool name — must match a cfg-synth-tools entry in root_config.yaml
librariesOptional list of library names from cfg-synth-libs; enables technology mapping
constraintsOptional SDC constraints file, resolved relative to synth.yaml
paramsOptional key-value pairs passed as top-level parameter overrides (chparam in Yosys)
definesOptional compile-time Verilog defines passed via -D KEY=VALUE
reglvlRegression level (int or per-tool dict); same semantics as simulation reglvl
tool_overridesOptional per-tool option overrides — keyed by tool name, merges over cfg-synth-tools defaults

SDC constraints

When constraints points to an SDC file, the Yosys backend extracts the create_clock period and passes it to ABC as -D <period_ps> for timing-driven technology mapping. The critical path delay is then used to compute WNS in the results table.

create_clock -period 10.0 [get_ports clk]
set_input_delay 2.0 -clock clk [all_inputs]
set_output_delay 2.0 -clock clk [all_outputs]

Multi-clock designs (Yosys backend): ABC's -D flag takes a single timing window. When multiple create_clock entries are present, rtl_buddy uses the minimum period as a workaround and emits a warning. For correct per-domain timing analysis across multiple clocks, use the openroad backend, which passes the full SDC to read_sdc and handles each clock domain natively.

Regression levels

reglvl works the same way as for simulation tests. Use --reg-level on synth-regression to filter by level.

# Same level for all tools
reglvl: 0

# Tool-specific with fallback
reglvl:
default: 0
dc: 1000

Per-tool overrides

tool_overrides is an escape hatch for tool-specific options that don't have a tool-agnostic equivalent. Keys match the opts fields in cfg-synth-tools:

tool_overrides:
yosys:
synth_args: "-flatten -nordff"
abc_args: "-fast"

Effort levels

A synthesis can select a named effort level that controls how much work the flow does. Efforts are defined once in root_config.yaml under cfg-synth-efforts (see below) and referenced per synthesis:

syntheses:
- name: "sandbox_quick"
desc: "Fast iteration build — Yosys-only, no STA"
model: "test_module"
model_path: "../../design/sandbox/models.yaml"
tool: "openroad"
libraries:
- "sky130hd_tt"
constraints: "constraints.sdc"
effort: "quick" # references a cfg-synth-efforts entry
reglvl: 0

When effort: is omitted, a built-in standard effort with all defaults is used — equivalent to the pre-effort behaviour. The --effort <name> CLI flag overrides the per-synthesis setting at runtime:

rb synth sandbox_openroad --effort quick # force the quick path
rb synth-regression --effort accurate # apply across a whole regression

Precedence for the same knob: per-synthesis tool_overrides > cfg-synth-efforts > cfg-synth-tools.

Root config: root_config.yaml

Synthesis tool configuration

Synthesis tool defaults live under cfg-synth-tools. Multiple tools can be listed; the tool field in synth.yaml selects which entry to use:

cfg-synth-tools:
- name: "yosys"
tool: "yosys" # executable name (must be on PATH)
opts:
synth-args: ""
abc-args: ""

- name: "openroad"
tool: "openroad" # executable name (must be on PATH)
opts:
strategy: "AREA" # AREA (default) | TIMING | TIMING_ANNEAL | TIMING_GENETIC

The strategy option controls optional OpenROAD resynthesis after timing analysis:

strategyEffect
AREA (default)No resynthesis; report area and timing only
TIMING / TIMING_ANNEALRun resynth_annealing after loading the netlist
TIMING_GENETICRun resynth_genetic after loading the netlist

Synthesis effort configuration

cfg-synth-efforts defines named levels that shape both the Yosys stage and the OpenROAD stage. Reference an entry from synth.yaml effort: or rb synth --effort <name>.

cfg-synth-efforts:
- name: "quick"
# Yosys-only fast path; skips OpenROAD entirely.
# Returns gate count + area only. No LEF/STA needed.
yosys:
synth-args: "-flatten"
abc-args: "-fast"
openroad:
run: false

- name: "standard"
# Default behaviour: Yosys + OpenROAD STA with ideal wires (zero RC).
openroad:
run: true

- name: "accurate"
# Apply the Liberty default_wire_load model for RC-aware pre-layout
# timing without needing a tech LEF + floorplan. Swap pre-sta-tcl
# for initialize_floorplan + global_placement + estimate_parasitics
# once a tech LEF is available.
openroad:
run: true
pre-sta-tcl: |
set_wire_load_mode top
set_wire_load_model -name Small

Effort schema:

FieldTypeDescription
namestringUnique effort identifier; referenced from synth.yaml or --effort
yosys.synth-argsstringAppended to the synth -top command in both backends
yosys.abc-argsstringUsed by the unmapped ABC step (Yosys backend without libraries)
openroad.runboolWhen false, a tool: openroad synthesis falls back to the Yosys-only backend (no LEF/STA required) — the recommended quick-look path
openroad.pre-sta-tclstringRaw Tcl snippet injected into synth.tcl between read_sdc and report_checks — use for floorplan/placement/parasitic-estimation before timing analysis

Built-in fallback: when cfg-synth-efforts is not configured (or the synthesis omits effort: and no override is passed), an internal standard effort with all defaults is used. Existing projects therefore need no migration.

Tradeoff: pre-sta-tcl is a raw snippet — powerful, but errors in it surface only at OpenROAD runtime. Test new snippets against a small design before adopting them in a regression.

Example: quick / standard / accurate on SKY130

Running the same DMA design at all three levels (ip_dma, sky130hd_tt, 5-clock SDC):

EffortGatesWNSTNSNotes
quick213+3.314 nsYosys-only with -flatten / -fast; aggressive optimisation; no STA
standard10218−1.172 ns−7835.2 nsOpenROAD STA with ideal wires (zero RC)
accurate10218−1.347 ns−8418.4 nsOpenROAD STA + Liberty wire-load model

The pessimization between standard and accurate (−1.347 vs −1.172 ns WNS) shows the wire-load model adding parasitic RC; the gate count is unchanged because the Yosys stage runs identically.

PDK library configuration

Liberty files for technology mapping are registered under cfg-synth-libs. Paths are resolved relative to root_config.yaml:

cfg-synth-libs:
- name: "sky130hd_tt"
path: "pdk/sky130hd/lib/sky130_fd_sc_hd__tt_025C_1v80.lib"
lef-paths: # required for OpenROAD backend
- "pdk/sky130hd/lef/sky130_fd_sc_hd_merged.lef"

The libraries list in synth.yaml references entries by name.

  • Yosys backend: uses path (liberty) for read_libertydfflibmapabc -libertywrite_verilog. lef-paths is ignored.
  • OpenROAD backend: requires both path (liberty) for timing and lef-paths (LEF) for technology loading. Without lef-paths the run fails immediately with an actionable error.

PDK files are typically large and should be gitignored. Provide a download script:

# pdk/download_pdk.sh
curl -fL <liberty-url> -o pdk/sky130hd/lib/sky130_fd_sc_hd__tt_025C_1v80.lib
curl -fL <lef-url> -o pdk/sky130hd/lef/sky130_fd_sc_hd_merged.lef

Synthesis regression: synth_regression.yaml

synth_regression.yaml lists the synth.yaml files to include in a synthesis regression:

rtl-buddy-filetype: synth_reg_config

synth-configs:
- "synth/sandbox/synth.yaml"
- "synth/dma/synth.yaml"

Paths are resolved relative to synth_regression.yaml.

Running synthesis

Run all syntheses in a config:

rtl-buddy synth -c synth/sandbox/synth.yaml

Run a named synthesis:

rtl-buddy synth sandbox_sky130 -c synth/sandbox/synth.yaml

List syntheses without running:

rtl-buddy synth --list -c synth/sandbox/synth.yaml

Run a synthesis regression:

rtl-buddy synth-regression -c synth_regression.yaml

Run only up to regression level 0:

rtl-buddy synth-regression -c synth_regression.yaml --reg-level 0

Results table

rb synth prints a results table after each run. Columns appear conditionally:

┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Synthesis ┃ Result ┃ Description ┃ Gates ┃ Area ┃ WNS ┃ TNS ┃
┡━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━┩
│ sandbox_synth │ PASS │ Synthesis passed │ 18 │ - │ - │ - │
│ sandbox_sky130 │ PASS │ Synthesis passed │ 18 │ 178.92 µm² │ +8.882 ns │ - │
│ sandbox_openroad │ PASS │ Synthesis passed │ 18 │ 179.00 µm² │ +6.754 ns │ +0.000 ns │
└──────────────────┴────────┴──────────────────┴───────┴────────────┴───────────┴───────────┘
ColumnSourceWhen shown
GatesYosys stat cell countAll lib-mapped flows
AreaYosys stat -liberty / OpenROAD report_design_areaLib-mapped flows
WNSYosys: clock period − critical path delay; OpenROAD: report_checks -path_delay maxLib-mapped flows with SDC
TNSOpenROAD report_tns — sum of all negative endpoint slacksOpenROAD backend with SDC

WNS and TNS are positive when timing is met and negative when violated. TNS = 0 means no violations; a negative TNS indicates the total repair budget needed.

WNS difference between backends: Yosys computes WNS as period − critical_path, which always reports positive slack. OpenROAD's report_checks reports the actual worst slack across all timing paths. The two values are closely aligned for single-clock designs.

Artefacts

Synthesis artefacts land under artefacts/<synth_name>/ relative to the synth.yaml directory.

Yosys backend:

FileContents
synth.fGenerated source filelist (resolved from models.yaml)
synth.ysGenerated Yosys script
synth.logCaptured Yosys stdout and stderr
synth.rtlilOutput netlist, technology-independent flow (RTLIL format)
synth_netlist.vOutput netlist, technology-mapped flow (Verilog)

OpenROAD backend:

FileContents
synth.fGenerated source filelist
synth.ysYosys script (stage 1 — maps RTL to gate-level netlist)
synth_yosys.logYosys stdout and stderr
synth_netlist.vGate-level Verilog produced by Yosys, fed into OpenROAD
synth.tclOpenROAD Tcl script (stage 2 — timing analysis)
synth.logOpenROAD stdout and stderr

Pass/fail detection

Yosys backend: a run passes when the tool exits with code 0 and synth.log contains no lines starting with ERROR:.

OpenROAD backend: both stages must succeed. The Yosys stage applies the same exit-code and ERROR: check; the OpenROAD stage checks exit code and the absence of [ERROR ...] lines in synth.log.

Any other outcome is FAIL with a description in the results table.

Full schema

See YAML Formats: synth.yaml for the complete field reference.