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).
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.
- Success Rate: 100% (18/18 tests functional)
- Perfect Matches: Tests with matching gate counts or identical netlists
- UHDM-Only Success: 2 tests demonstrate superior SystemVerilog support
- Functional: All tests work correctly, validated by gate count comparison
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 - 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 structures with member access via bit slicing
- 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
- Struct member access (e.g.,
bus.field
) - Hierarchical signal references
- Parameter references in expressions
- Control Flow: If-else statements, case statements with parameter values, loops
- Memory: Array inference, memory initialization
- Generate Blocks: For loops, if-else generate, hierarchical instance naming
- Packages: Import statements, package parameters, struct types, functions
- 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)
# Clone with submodules
git clone --recursive https://github.com/username/uhdm2rtlil.git
cd uhdm2rtlil
# Build everything (Surelog, Yosys, UHDM Frontend)
make
# Method 1: Using the test workflow
cd test
bash test_uhdm_workflow.sh simple_counter
# Method 2: Manual workflow
# Step 1: Generate UHDM from SystemVerilog
./build/third_party/Surelog/bin/surelog -parse design.sv
# Step 2: Use Yosys with UHDM frontend (load plugin first)
./out/current/bin/yosys -p "plugin -i uhdm2rtlil.so; read_uhdm slpp_all/surelog.uhdm; synth -top top_module"
Each 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
# Run all tests
cd test
bash run_all_tests.sh
# Run specific test
bash test_uhdm_workflow.sh simple_counter
# Run tests using CMake
cd build
make test
# 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 requiring investigation
# The test framework performs multiple levels of comparison:
# 1. RTLIL comparison - Shows implementation differences
# 2. Gate count comparison - Tests pass if gate counts match
# 3. Netlist comparison - Additional validation of functional equivalence
- simple_counter - 8-bit counter with async reset (tests increment logic, reset handling)
- flipflop - D flip-flop (tests basic sequential logic)
- counter - More complex counter design
- simple_struct - Packed struct handling and member access (tests struct bit slicing)
- simple_assign - Basic continuous assignments
- simple_always_ff - Sequential always_ff blocks with clock and reset
- simple_always_ifelse - Always blocks with if-else conditional logic
- simple_hierarchy - Module instantiation and port connections
- simple_interface - Interface-based connections
- simple_memory - Memory arrays and access patterns
- param_test - Parameter passing and overrides
- generate_test - Generate for loops and if-else generate blocks with proper instance naming
- simple_fsm - Finite state machine with parameterized states (tests parameter references in case statements)
- simple_instance_array - Primitive gate arrays (tests and, or, xor, nand, not gates with array instances)
- simple_package - SystemVerilog packages with parameters, structs, and imports
- struct_array - Arrays of packed structs with complex indexing and member access
- vector_index - Bit-select assignments on vectors (tests
assign wire[bit] = value
syntax) - unique_case - Unique case statements with for loops and break statements
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 comments
How it works:
- Tests listed in
failing_tests.txt
are 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:
# Tests that currently fail:
# (none - all tests pass!)
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_NAME
This 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
│ ├── 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
│ ├── failing_tests.txt # Known failing tests list
│ └── */ # Individual test cases
├── third_party/ # External dependencies
│ ├── Surelog/ # SystemVerilog parser (includes UHDM)
│ └── yosys/ # Synthesis framework
├── .github/workflows/ # CI/CD configuration
├── build/ # Build artifacts
├── CMakeLists.txt # CMake build configuration
└── Makefile # Top-level build orchestration
The UHDM frontend now passes all 18 test cases in the test suite:
- 2 UHDM-only tests - Demonstrate superior SystemVerilog support (simple_instance_array, simple_package)
- 16 Functional tests - Work correctly, validated by matching gate counts
- 0 Failing tests - All tests pass successfully!
- Added automatic expansion of SystemVerilog interfaces to individual signals
- Interface instances are replaced with their constituent nets during RTLIL import
- Interface connections are properly mapped to individual signal connections
- Interface signal wires are converted to proper input/output ports
- Supports parameterized interfaces with different widths
- Added proper handling of parameter references in expressions (e.g., in case statements)
- Parameters are now correctly resolved to their constant values instead of being treated as wire references
- Supports binary constant format "BIN:xx" used by UHDM for proper bit width handling
- simple_interface - Added interface expansion support, converting interface instances to individual signals
- simple_fsm - Fixed parameter reference handling in case statements, ensuring proper constant resolution
- simple_instance_array - Added support for primitive gate arrays (and, or, xor, nand, not gates with array syntax)
- simple_package - Added full package support including imports, parameters, and struct types
- struct_array - Now passes with improved expression handling and struct support
- generate_test - Fixed by adding
proc
beforeopt
in test workflow to handle multiple generated processes correctly
The UHDM frontend now supports Verilog primitive gates and gate arrays:
- Supported gates:
and
,or
,xor
,nand
,nor
,xnor
,not
,buf
- Array instantiation:
and gate_array[3:0] (out, in1, in2);
- Proper bit-slicing for vectored connections
- Maps to Yosys internal gate cells (
$_AND_
,$_OR_
, etc.)
The UHDM frontend now supports SystemVerilog packages:
- Package imports with
import package::*
syntax - Package parameters and constants
- Package struct types with correct width calculation
- Cross-module type references from packages
- Proper wire context resolution during module instantiation
The UHDM frontend now handles elaboration automatically:
- The plugin checks if the UHDM design is already elaborated using
vpi_get(vpiElaborated)
- If not elaborated, it performs elaboration using UHDM's ElaboratorListener
- This removes the need for the
-elabuhdm
flag in Surelog - Elaboration happens transparently when reading UHDM files in Yosys
- Identify UHDM Objects: Determine which UHDM object types represent the feature
- Implement Import: Add handling in appropriate
src/frontends/uhdm/*.cpp
file - 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
# 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
.il
files 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
- Create a feature branch
- Add appropriate test cases
- Ensure all tests pass (or update
failing_tests.txt
if needed) - Submit a pull request
See LICENSE
file for details.