A Yosys frontend that enables SystemVerilog synthesis through UHDM (Universal Hardware Data Model) by converting UHDM representations to Yosys RTLIL (Register Transfer Level Intermediate Language).
Nothing here is counted as "working" on a read-only or vacuous pass. Every synthesized netlist is proven correct by formal equivalence — Yosys
equiv_inductplus a sound SAT-from-reset miter against the Yosys Verilog-frontend golden — and/or by high-activity randomized Verilator co-simulation against the original RTL. A SAT miter also adjudicates every divergence so an inductive-proof gap is never mistaken for a real bug. See Verification Methodology below.
This project bridges the gap between SystemVerilog source code and Yosys synthesis by leveraging two key components:
- Surelog - Parses SystemVerilog and generates UHDM
- UHDM Frontend - Converts UHDM to Yosys RTLIL
This enables full SystemVerilog synthesis capability in Yosys, including advanced features not available in Yosys's built-in Verilog frontend.
Correctness is the project's first-class concern. Every test's SystemVerilog is synthesized and then independently verified by one or more of:
- Formal equivalence (
equiv_induct) — the UHDM-frontend netlist is proven sequentially equivalent to the netlist produced by Yosys's own Verilog frontend (the golden reference), usingequiv_make/equiv_simple/equiv_induct. - Sound SAT-from-reset miter — a bounded model-check from the reset state
(
miter+sat -prove-asserts -seq N -set-init-zero) that is sound: it never false-passes. It is the adjudicator of record — whenequiv_inductcan't close an inductive proof, the miter decides whether the two netlists are truly equivalent (an induction gap, not a bug) or genuinely divergent (a real bug). - High-activity randomized Verilator co-simulation — the UHDM-synthesized gate-level netlist is co-simulated against the original RTL under randomized, high-toggle-activity stimulus (all clocks driven, reset wiggled, activity guards) to catch functional divergences a vacuous stimulus would miss.
A result is only counted as Correct when formal equivalence and/or co-simulation proves it; designs the native Verilog frontend cannot even parse ("SV-only") are verified against the RTL by co-simulation, since there is no golden netlist to compare against. This asymmetric, miter-adjudicated policy is why the tables below report 0 Miter-Formal escapes — no real UHDM≠Verilog difference slips through.
Run via make test-all --all (the internal SystemVerilog suite plus the
upstream Yosys test suite under third_party/yosys/tests/):
- Total Tests: 1397 (852 internal SystemVerilog + 545 upstream Yosys)
- Success Rate: 97% (1352/1397 tests functional), 1 crash, 0 Miter-Formal
escapes (no UHDM≠Verilog diff slips past
equiv_induct) - Passing: 916 tests with formal equivalence verified between the UHDM and Verilog frontends
- UHDM-Only Success: 435 tests verified end-to-end against Verilator (the UHDM frontend handles SystemVerilog the Verilog frontend can't, so formal equivalence isn't possible — see below)
- Equivalence failures: 10 — all caught by
equiv_induct(0 Miter-Formal escapes): internalCastStructArrayandpacked_array_elem_select(both cases where the Verilog-frontend reference is wrong — a SAT miter / slang proves UHDM correct),rp32_r5p_mouse(reset/X-dependent, not cleanly equiv-able); plus 7 from the upstream Yosys suite (arch/nanoxplore/meminit,check_mem/sub_addr,simple/module_scope_case,sva/extnets,svtypes/array_assign,verific/ext_ramnet_err,verilog/mem_bounds). - True failures (no output generated): 12 — all from the upstream Yosys
suite (
arch/fabulous/{arith,custom,ff,io,regfile}_map,functional/picorv32_tb,hana/test_simulation_vlib,opt/opt_rmdff,rpc/design,svinterfaces/{load_and_derive,resolve_types},verific/mixed_flist). Every internal test — including the full Ibex core (ibex_core,ibex_cs_registers,ibex_icache,ibex_top) — now reads and produces output. - Crashes: 1 (
memories/wide_all— upstream Yosys) - Verilator sim-equiv warnings: 117 known-but-untriaged divergences, baselined
in
test/sim_equiv_warn_baseline.txt(a ratchet: the suite fails on any warning NOT in the baseline, and the baseline may only shrink as entries are triaged); plus 72 analyzed known non-bug divergences — of which 58 are sim/synth artefacts where a SAT miter proves UHDM == Verilog, and the rest are uhdm-only don't-care divergences (e.g.rp32_r5p_alu/wbu/mdu, where the Verilog frontend can't synthesize the SV so no miter is possible)
The internal SystemVerilog suite alone is 846 tests, 0 crashes, 0 true failures — every internal design reads and produces output, including the complete Ibex core (all modules +
ibex_top) and the rp32 cores/SoCs. The only internal equivalence failures areCastStructArrayandpacked_array_elem_select(Yosys-Verilog-frontend reference bugs, not UHDM — verified vs slang/iverilog) andrp32_r5p_mouse(reset/X-dependent, not cleanly equiv-able). The figures above are the combined--allrun; all 12 true failures and the single crash come from the imported upstream Yosys suite (feature gaps / non-synthesizable constructs), tracked intest/failing_tests.txtandtest/imported_tests_status.txtand fixed incrementally. No pre-existing internal test regressed.CVA6 latch parity: the full CVA6 core (
cv64a6_imafdc_sv39) now lowers throughread_uhdm; hierarchy; procwith 0 inferred latches — matching theread_slangreference exactly.CVA6 per-module equivalence (
test/cva6_equiv/): every CVA6 module is compiled standalone with its real-hierarchy parameters and mitered against theread_slangreference — 79 of 147 modules formally PROVEN, the rest tracked with expected verdicts incva6_modules.txt(a ratchet: any module regressing from its recorded verdict fails the suite).
Two real-world RISC-V IP families are imported from their upstream RTL (kept
verbatim under test/ibex/ and test/rp32/) and exercised end-to-end through
the UHDM frontend. Run just these with make test-cores (or
bash run_all_tests.sh --cores): 41 tests, 40 functional (97%), 0 crashes.
| IP | What it is | Tests | Result |
|---|---|---|---|
| lowRISC Ibex | 2-stage 32-bit RISC-V core (RV32IMC + PMP, ICache, dummy-instr/lockstep security) | 28 — every RTL module plus the full ibex_top / ibex_top_tracing integration |
28 / 28 pass, 0 crashes |
| rp32 (R5P) | 32-bit RISC-V cores + TCB-interface SoCs (degu, mouse, v-friendly) | 13 — ALU, BRU, CSR, GPR, MDU, WBU, the degu/hamster/mouse cores and their SoC tops |
12 / 13 pass, 0 crashes |
Highlights:
- The entire Ibex hierarchy (all 30 RTL files + prim leaves, top
ibex_top) reads,flattens, and passes Yosyscheckwith 0 logic loops and 0 undriven nets — a campaign that fixed a series of real frontend bugs (comb-only array inference,initial for$meminit, genvar async-reset flops, comb write-then-read threading, struct-field in-flight reads) that took the loop count from 389 → 0. ibex_register_file_fpgais verified by formal equivalence (its power-up$meminitnow matches the Verilog frontend); the other advanced-SV Ibex modules are UHDM-only (the native Verilog frontend cannot parse them) and verified against Verilator co-simulation.- Both interface-based rp32 SoCs (
degu,mouse) boot and run a program end-to-end in a Yosys functional simulation of the UHDM-synthesised netlist. - The single non-pass,
rp32_r5p_mouse, is a knownequiv_inductincompleteness (a reset/X-dependent design where seq-equiv induction can't close), not a UHDM≠Verilog difference — 0 Miter-Formal escapes.
The 4-frontend regression matrix (make test-matrix, run nightly) synthesizes
every test's SystemVerilog through four frontends and ranks them by how much
SV each handles correctly. Every netlist is verified either by formal
equivalence — Yosys equiv_induct plus a sound SAT-from-reset miter, against
the Yosys Verilog-frontend golden — and/or by high-activity randomized
Verilator co-simulation against the original RTL. A result counts as Correct
only when one of those checks proves it equivalent; SV-only means the frontend
synthesized SystemVerilog that the native Verilog frontend cannot even read (no
golden to compare against, so it is verified against the RTL by co-simulation).
Ranked by total tests handled correctly (1237-test matrix):
| Rank | Frontend | Verified correct | SV-only (no golden) | Total correct | Incorrect | Failed to read |
|---|---|---|---|---|---|---|
| 🥇 1 | uhdm (this project) |
814 | 293 | 1107 (89%) | 25 | 37 |
| 🥈 2 | sv2v |
768 | 237 | 1005 (81%) | 0 | 175 |
| 🥉 3 | slang (Yosys sv-elab) |
640 | 243 | 883 (71%) | 0 | 242 |
| 4 | verilog (Yosys native, the golden) |
852 | — | 852 (69%) | 9 | 375 |
On this corpus the UHDM frontend converts the most SystemVerilog — 1107 of 1237 tests verified correct, including 293 designs the native Verilog frontend cannot read at all.
How to read this table honestly:
- It is a self-run benchmark on a largely self-authored corpus. The matrix is mostly this project's own test suite (plus imported Yosys and chipsalliance/UHDM-integration tests), and many tests were added specifically to exercise constructs this frontend targets. The ranking is real but it is not a neutral third-party comparison — a tool graded on the set its authors curated is playing at home. Read "#1 by ~18 points" in that light.
- The benchmark rewards breadth over conservatism.
sv2vandslangreport 0 incorrect results here;uhdm's 25 are a real (tracked) triage backlog intest/failing_tests.txt. The README's ranking metric (total handled) favors reading more SV, but "accepts less yet is never wrong on what it accepts" is a legitimate — sometimes preferable — posture, and it's the onesv2v/slangshow on this corpus. Their higher "Failed to read" counts (175 / 242 vs 37) reflect that trade-off, not a defect. - Coverage ≠ ecosystem fit.
slang/sv-elab is the frontend that has been upstreamed into Yosys itself, ships in the OSS CAD Suite, and is used by OpenROAD — adoption, integration, and maintenance advantages a nightly coverage count does not capture. If your criterion is maximum SV coverage through the Surelog/UHDM path today, this table favorsuhdm; if it is what is maintained and integrated for production, sv-elab has the stronger case. Both can be true.
verilog is the golden reference, so it has no SV-only column and its ceiling is
the SV subset it can parse. Numbers are from one nightly run and drift between runs
(seq-equiv induction is inductively incomplete on some designs) — treat any single
figure as approximate.
Note (2026-06-14): 349 DUTs from chipsalliance/UHDM-integration-tests were imported as
test/<Name>/dut.sv(harnesses excluded). Of the 316 observable ones, 89 pass as-is; the remainder expose feature gaps clustered by area (Parameter, Function, Array, Pattern, Struct, Enum). Seetest/imported_tests_status.txtfor the per-test breakdown.
The detailed per-test coverage that used to follow — the UHDM-only verified test list, Recent Additions, and the Recent Fixes changelog — has moved out of the README to keep this section focused on the leaderboard:
- Changelog / fixes →
docs/recent-improvements.md - Test catalog (incl. the UHDM-only list) →
docs/test-cases.md
SystemVerilog (.sv) → [Surelog] → UHDM (.uhdm) → [UHDM Frontend] → RTLIL → [Yosys] → Netlist
- Industry-grade SystemVerilog parser and elaborator
- Handles full IEEE 1800-2017 SystemVerilog standard
- Outputs Universal Hardware Data Model (UHDM)
- Provides semantic analysis and type checking
- Core Module (
uhdm2rtlil.cpp) - Main frontend entry point, design import, and UHDM elaboration - Module Handler (
module.cpp) - Module definitions, ports, instances, and wire declarations - Process Handler (
process.cpp) - Always blocks, procedural statements, and control flow - Expression Handler (
expression.cpp) - Operations, constants, references, and complex expressions - Functions Handler (
functions.cpp) - Compile-time constant function evaluation - Interpreter (
interpreter.cpp) - Statement interpreter for initial block execution - Memory Handler (
memory.cpp) - Memory inference and array handling - Memory Analysis (
memory_analysis.cpp) - Advanced memory pattern detection and optimization - Clocking Handler (
clocking.cpp) - Clock domain analysis and flip-flop generation - Package Support (
package.cpp) - SystemVerilog package imports, parameters, and type definitions - Primitives Support (
primitives.cpp) - Verilog primitive gates and gate arrays - Reference Module (
ref_module.cpp) - Module instance reference resolution and parameter passing - Interface Support (
interface.cpp) - SystemVerilog interface handling with automatic expansion
- Open-source synthesis framework
- Processes RTLIL for optimization and technology mapping
- Provides extensive backend support for various FPGA and ASIC flows
- Module System: Module definitions, hierarchical instantiation, parameter passing
- Data Types:
- Logic, bit vectors, arrays
- Packed multidimensional arrays with dynamic element access (e.g.,
logic [0:3][7:0], typedef variants) - Packed structures with member access via bit slicing
- Packed unions with member access (all members overlay at bit offset 0, width = widest member)
- Structs containing unions and unions containing structs (nested access)
- Struct arrays with complex indexing
- Package types and imports
- Procedural Blocks:
always_ff- Sequential logic with proper clock/reset inferencealways_comb- Combinational logicalways- Mixed sequential/combinational logic
- Expressions:
- Arithmetic, logical, bitwise, comparison, ternary operators
- Compound assignment operators (
+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=,<<<=,>>>=) - Increment/decrement operators (
x++,--x) as statements and in expressions - Assignment expressions (
x = (y = expr) + 1) with proper side-effect ordering - System function calls ($signed, $unsigned, $floor, $ceil)
- User-defined function calls with good support (simple functions, arithmetic, boolean logic, case statements, nested if-else)
- Struct member access (e.g.,
bus.field) - Hierarchical signal references
- Parameter references with HEX/BIN/DEC formats
- Loop variable substitution in generate blocks
- Control Flow: If-else statements, case statements (including constant evaluation in initial blocks), for loops with compile-time unrolling and variable substitution, repeat loops with compile-time unrolling, while loops in compile-time function evaluation, named and unnamed begin blocks with local variable scoping
- Memory: Array inference, memory initialization, for-loop memory initialization patterns, asymmetric port RAM with different read/write widths
- Shift Registers: Automatic detection and optimization of shift register patterns (e.g.,
M[i+1] <= M[i]) - Generate Blocks:
- For loops with proper scope handling
- If-else generate conditions
- Hierarchical naming (e.g.,
gen_loop[0].signal) - Net and variable imports from generate scopes
- Packages: Import statements, package parameters (including localparam/parameter from enum constants), package-scoped typedefs and enum types, struct types, functions
- Net Types:
wandandwor(wire-AND and wire-OR) with proper multi-driver resolution - Primitives: Gate arrays (and, or, xor, nand, nor, xnor, not, buf)
- Advanced Features:
- Interfaces with automatic expansion to individual signals
- Interface port connections and signal mapping
- Assertions
- GCC/Clang compiler with C++17 support
- CMake 3.16+
- Python 3.6+
- Standard development tools (make, bison, flex)
- Verilator (used by
test/test_sim_equivalence.pyto co-simulate the original SV against the UHDM-derived netlist for tests where the Yosys Verilog frontend can't parse the source — see Verilator-based simulation equivalence below)
On Debian / Ubuntu:
sudo apt-get install -y \
build-essential cmake git python3 python3-pip pkg-config \
libssl-dev zlib1g-dev libtcmalloc-minimal4 uuid-dev tcl-dev \
libffi-dev libreadline-dev bison flex libfl-dev libunwind-dev \
libgoogle-perftools-dev ccache help2mantest/test_sim_equivalence.py needs Verilator 5.x (5.020+) for SVA
parsing. Ubuntu 24.04's stock verilator package is recent enough;
on older distros (22.04 ships 4.038) build from source:
git clone --depth=1 -b v5.048 https://github.com/verilator/verilator.git
cd verilator
autoconf
./configure --prefix=/usr/local
make -j$(nproc)
sudo make install
verilator --version # confirm: "Verilator 5.048 ..."# Clone with submodules
git clone --recursive https://github.com/username/uhdm2rtlil.git
cd uhdm2rtlil
# Configure git hooks (prevents committing files >10MB)
git config core.hooksPath .githooks
# Build everything (Surelog, Yosys, UHDM Frontend)
makeThe plugin (uhdm2rtlil.so) registers two Yosys commands for getting
SystemVerilog into RTLIL:
| Command | Input | Surelog run | Intermediate .uhdm |
|---|---|---|---|
read_sv |
SystemVerilog source(s) + Surelog flags | in-process | no — fully in-memory |
read_uhdm |
a pre-generated .uhdm file |
separate / earlier | yes |
Runs the Surelog compiler in-process and imports the elaborated in-memory
UHDM design straight to RTLIL, without writing or re-reading a .uhdm file.
All arguments are forwarded to Surelog verbatim, exactly as if it were the
surelog executable:
./out/current/bin/yosys -m uhdm2rtlil.so \
-p "read_sv -parse -nobuiltin design.sv; synth -top top_module"
# Multi-file / flags work just like the surelog CLI:
# read_sv -parse -nobuiltin a.sv b.sv +incdir+inc -DWIDTH=8 -top mytopread_sv forces parse + elaborate + in-memory UHDM elaboration on and .uhdm
file writing off. Pass any Surelog flag as usual; -nobuiltin is recommended
to skip Surelog's built-in classes. Plugin-only options (consumed, not passed
to Surelog): -uhdm_debug, -formal, -keep_names.
Useful when the UHDM database was produced by a separate Surelog run (e.g. the
test workflow, or for caching/debugging the .uhdm):
# Step 1: Generate UHDM from SystemVerilog
./build/third_party/Surelog/bin/surelog -parse -d uhdm design.sv
# Step 2: Read the UHDM file with the frontend
./out/current/bin/yosys -m uhdm2rtlil.so \
-p "read_uhdm slpp_all/surelog.uhdm; synth -top top_module"Options: -debug, -formal, -keep_names.
cd test
bash test_uhdm_workflow.sh simple_counterEach test case is a directory containing:
dut.sv- SystemVerilog design under test- Automatically generated comparison files:
*_from_uhdm.il- RTLIL generated via UHDM path*_from_verilog.il- RTLIL generated via Verilog pathrtlil_diff.txt- Detailed RTLIL comparison*_from_uhdm_synth.v- Gate-level netlist via UHDM path*_from_verilog_synth.v- Gate-level netlist via Verilog pathnetlist_diff.txt- Gate-level netlist comparison
# Smoke-test the read_sv command (in-process Surelog compile, no .uhdm file).
# Verifies read_sv == Verilog frontend and that no .uhdm is written. Fast;
# CI runs this first, and `make test` runs it as part of the suite.
make test-read-sv
# Run internal tests only (our test suite; includes test-read-sv)
make test
# Run all tests (internal + Yosys tests)
make test-all
# Run only the core IP tests (rp32 RISC-V SoC + lowRISC Ibex)
make test-cores
# Run Yosys tests only
make test-yosys
# Run specific test from test directory
cd test
bash test_uhdm_workflow.sh simple_counter
# Run tests with options from test directory
cd test
bash run_all_tests.sh # Run internal tests only
bash run_all_tests.sh --all # Run all tests (internal + Yosys)
bash run_all_tests.sh --cores # Run only rp32 + Ibex core IP tests
bash run_all_tests.sh --yosys # Run all Yosys tests
bash run_all_tests.sh --yosys add_sub # Run specific Yosys test pattern
# Test output explanation:
# ✓ PASSED - UHDM and Verilog frontends produce functionally equivalent results
# ⚠ FUNCTIONAL - Works correctly but with RTLIL differences (normal and expected)
# ✗ FAILED - Significant functional differences or equivalence check failure
# The test framework performs multiple levels of comparison:
# 1. RTLIL comparison - Shows implementation differences
# 2. Synthesis and formal equivalence check - Uses Yosys equiv_make/equiv_simple/equiv_induct
# 3. Validates functional equivalence even when gate counts differThe UHDM frontend can run the full Yosys test suite to validate compatibility:
# Run all Yosys tests
make test-yosys
# Run specific Yosys test directory
cd test
./run_all_tests.sh --yosys ../third_party/yosys/tests/arch/common
# Run specific Yosys test
./run_all_tests.sh --yosys ../third_party/yosys/tests/arch/common/add_sub.vUHDM-only tests have no Yosys-Verilog-frontend reference netlist to formally
equivalence-check against, so run_all_tests.sh invokes
test/test_sim_equivalence.py on them as a soft warning.
The script co-simulates two views of the same design under Verilator:
- RTL form — the original
dut.sv, simulated directly by Verilator - Netlist — UHDM frontend output, post-
synth -auto-top
A small SystemVerilog testbench instantiates both side by side
(dut_rtl / dut_netlist), and a C++ driver advances clocks, holds
reset for a few cycles, then drives random inputs for ~50–200 cycles,
comparing every output every cycle. Clocks and resets are extracted
from the netlist via the extract_clocks_resets Yosys plugin
(build/extract_clocks_resets.so).
A mismatch surfaces as a ⚠️ Verilator co-sim WARNING line in the
test summary and does not flip the test to failed. Per-test
output is written to <test_dir>/sim_equiv.log.
You can also run it standalone:
cd test
./test_sim_equivalence.py setundefThe Yosys test runner:
- Automatically finds self-contained Verilog/SystemVerilog tests
- Runs both Verilog and UHDM frontends on each test
- Performs formal equivalence checking when both frontends succeed
- Reports UHDM-only successes (tests that only work with UHDM frontend)
- Creates test results in
test/run/directory structure
The internal suite spans flip-flops & registers, counters, combinational/boolean/ arithmetic logic, multiplexers, multipliers & pipelines, state machines, functions, scope & variable shadowing, arrays & memory, data types & structs, generate & parameterization, module hierarchy & interfaces, and primitives.
See docs/test-cases.md for the full annotated catalog.
The test framework includes automatic handling of known failing tests:
# View known failing tests
cat test/failing_tests.txt
# Format: one test name per line, # for commentsHow it works:
- Tests listed in
failing_tests.txtare expected to fail - The test runner (
run_all_tests.sh) will still run these tests - If all failures are listed in
failing_tests.txt, the test suite passes with exit code 0 - This allows CI to pass while acknowledging known issues
- New unexpected failures will cause the test suite to fail
Current Status: see the authoritative figures under
Verification Methodology → Test Suite Status. In short: the
internal SystemVerilog suite passes with 0 true failures / 0 crashes, and
failing_tests.txt documents the known expected-fail cases from the imported
upstream-Yosys suite (feature gaps, non-DUT techmap files, and equiv_induct
incompleteness that the SAT miter proves equivalent) — it is not empty.
The test workflow runs proc before opt to ensure proper process handling:
hierarchy -check -top $MODULE_NAME
stat
proc # Convert processes to netlists first
opt # Then optimize
stat
write_rtlil ${MODULE_NAME}_from_uhdm.il
synth -top $MODULE_NAMEThis prevents errors when synthesizing designs with generate blocks and multiple processes.
uhdm2rtlil/
├── src/frontends/uhdm/ # UHDM Frontend implementation
│ ├── uhdm2rtlil.cpp # Main frontend, design import, interface expansion
│ ├── module.cpp # Module/port/instance handling
│ ├── process.cpp # Always blocks and statements
│ ├── expression.cpp # Expression evaluation
│ ├── functions.cpp # Compile-time constant function evaluation
│ ├── interpreter.cpp # Statement interpreter for initial blocks
│ ├── memory.cpp # Memory and array support
│ ├── memory_analysis.cpp # Memory pattern detection
│ ├── clocking.cpp # Clock domain analysis
│ ├── package.cpp # Package support
│ ├── primitives.cpp # Primitive gates
│ ├── ref_module.cpp # Module references
│ ├── interface.cpp # Interface declarations and modports
│ └── uhdm2rtlil.h # Header with class definitions
├── test/ # Test framework
│ ├── run_all_tests.sh # Test runner script
│ ├── test_uhdm_workflow.sh # Individual test workflow
│ ├── test_equivalence.sh # Formal equivalence checking script
│ ├── failing_tests.txt # Known failing tests list
│ └── */ # Individual test cases
├── third_party/ # External dependencies
│ ├── Surelog/ # SystemVerilog parser (includes UHDM)
│ └── yosys/ # Synthesis framework (pinned at v0.64)
├── .github/workflows/ # CI/CD configuration
├── build/ # Build artifacts
├── CMakeLists.txt # CMake build configuration
└── Makefile # Top-level build orchestration
The authoritative, up-to-date figures live in one place — Verification Methodology → Test Suite Status and the SystemVerilog Frontend Comparison leaderboard — to avoid the numeric drift that comes from repeating counts in several sections. Any single figure is from one nightly run and is approximate.
The frontend has landed a large number of incremental SystemVerilog features and bug fixes — unpacked-array ports, packed multidimensional arrays, packed unions, struct-field-parameter dimensions, function-local arrays, for-loop unrolling, memory inference, signedness/sign-extension, interfaces, techmap cells, and many more.
The full, annotated changelog lives in
docs/recent-improvements.md.
- Identify UHDM Objects: Determine which UHDM object types represent the feature
- Implement Import: Add handling in appropriate
src/frontends/uhdm/*.cppfile - Map to RTLIL: Convert UHDM objects to equivalent RTLIL constructs
- Add Tests: Create test cases comparing UHDM vs Verilog frontend outputs
- Validate: Ensure generated RTLIL produces correct synthesis results
The project includes Git hooks to maintain code quality:
# Enable Git hooks (one-time setup)
git config core.hooksPath .githooks
# What the hooks do:
# - Prevent commits of files larger than 10MB
# - Prevent commits of test/run/**/*.v files (generated test outputs)# Enable debug output
export YOSYS_ENABLE_UHDM_DEBUG=1
# Run with verbose logging
./out/current/bin/yosys -p "read_uhdm -debug design.uhdm; write_rtlil output.il"- Correctness: Generated RTLIL must be functionally equivalent to Verilog frontend
- Completeness: Support full SystemVerilog feature set over time
- Performance: Efficient UHDM traversal and RTLIL generation
- Maintainability: Clear separation of concerns between different handlers
This project is developed using an innovative AI-assisted approach with Claude (Anthropic's AI assistant). The development workflow leverages Claude's ability to understand and work with multiple file formats simultaneously:
-
UHDM Text Analysis: Claude analyzes the UHDM text output (from
uhdm-dump) to understand the structure and relationships of SystemVerilog constructs as represented in UHDM. -
RTLIL Comparison: The
.ilfiles generated by both the UHDM frontend and Verilog frontend are compared to identify differences and ensure functional equivalence. -
Iterative Development: Claude can:
- Read UHDM dumps to understand what objects need to be handled
- Analyze RTLIL differences to identify missing functionality
- Suggest and implement fixes based on the patterns observed
- Test changes and iterate until the outputs match
# 1. Generate UHDM and dump it for analysis
./build/third_party/Surelog/bin/surelog -parse test.sv
./build/third_party/UHDM/bin/uhdm-dump slpp_all/surelog.uhdm > test.uhdm.txt
# 2. Generate RTLIL from both frontends
yosys -p "read_uhdm slpp_all/surelog.uhdm; write_rtlil test_uhdm.il"
yosys -p "read_verilog test.sv; write_rtlil test_verilog.il"
# 3. Claude analyzes:
# - test.uhdm.txt to understand UHDM structure
# - Differences between test_uhdm.il and test_verilog.il
# - Implements necessary handlers in the frontend code- Rapid Development: Claude can quickly identify patterns and implement handlers
- Comprehensive Understanding: AI can analyze complex relationships across multiple file formats
- Systematic Coverage: Each test case systematically expands SystemVerilog support
- Quality Assurance: Comparing against Yosys's Verilog frontend ensures correctness
This "vibe coding" approach has proven highly effective, enabling the implementation of complex SystemVerilog features like packages, interfaces, and generate blocks in a fraction of the traditional development time.
GitHub Actions automatically:
- Builds all components (Surelog, Yosys, UHDM Frontend)
- Runs comprehensive test suite
- Uploads test results and build artifacts
- Provides clear pass/fail status
See .github/workflows/ci.yml for configuration details.
- Fork the repository
- Clone and set up git hooks:
git clone --recursive https://github.com/yourusername/uhdm2rtlil.git cd uhdm2rtlil git config core.hooksPath .githooks - Create a feature branch
- Add appropriate test cases
- Ensure all tests pass (or update
failing_tests.txtif needed) - Submit a pull request
Note: The repository has git hooks configured to prevent committing files larger than 10MB. This helps keep the repository size manageable. If you need to include large files, consider using Git LFS or adding them to .gitignore.
See LICENSE file for details.