Install RyuSim, compile your first design, and run a native SystemVerilog testbench, a UVM test, or a cocotb testbench.
Install the required build tools for your distribution. The installer will warn if these are missing, but installing them first avoids interruption.
zlib development files (zlib1g-dev / zlib-devel) are required: every simulation RyuSim generates links zlib through the runtime's FST waveform writer. The runtime libz.so.1 most systems already have is not sufficient — linking needs the libz.so symlink that ships in the development package.
The distro clang package is older than the required Clang 18, so install it from apt.llvm.org:
wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- 18 && sudo apt install cmake python3 python3-pip zlib1g-dev
sudo dnf install clang cmake python3 python3-pip zlib-devel
sudo dnf install epel-release && sudo /usr/bin/crb enable && sudo dnf install clang cmake python3 python3-pip zlib-devel
curl -fsSL https://ryusim.com/install.sh | bash
The installer auto-detects your architecture and glibc version. See Downloads for the full list of supported distributions.
Create a simple counter design:
module counter (
input logic clk,
input logic rst,
output logic [7:0] count
);
always_ff @(posedge clk) begin
if (rst)
count <= 8'h0;
else
count <= count + 1;
end
endmodule
Compile it:
ryusim compile counter.sv --top counter
RyuSim v2 delivers full IEEE 1800-2023 testbench-language compliance; gate-level modeling
(cl. 28–33) and the VPI assertion/coverage/data-read APIs (cl. 39–41) ship in v2.x
— see the per-clause compliance matrix. Testbenches
written in SystemVerilog itself are the primary flow: ryusim compile builds a
standalone executable that runs with no Python and no VPI in the loop.
Add a self-checking testbench next to the design, counter_tb.sv. It generates a
clock, releases reset, counts ten rising edges, and checks the result with an immediate
assertion:
`timescale 1ns/1ns
module counter_tb;
logic clk = 1'b0;
logic rst;
logic [7:0] count;
counter dut (.clk(clk), .rst(rst), .count(count));
always #5 clk = ~clk; // 100 MHz free-running clock
initial begin
rst = 1'b1;
@(negedge clk);
rst = 1'b0;
repeat (10) @(posedge clk);
#1; // let the NBA update settle
assert (count == 8'd10)
else $fatal(1, "expected count=10, got %0d", count);
$display("COUNTER_TB_PASS: count=%0d at t=%0t", count, $time);
$finish;
end
endmodule
Compile the design and the testbench together, with the testbench as the top module:
ryusim compile counter.sv counter_tb.sv --top counter_tb
Then run the standalone executable RyuSim built:
./obj_dir/build/counter_tb_sim
Expected output:
RyuSim - Simulation of counter_tb
RyuSim: effective root seed = 14916093976784742661 (source: randomly generated)
COUNTER_TB_PASS: count=10 at t=106
Simulation complete. Time: 106000
The root seed is drawn fresh on every run unless you pin it, so that line will differ. The
binary exits 0 on success; a failing assert reports through
$fatal and exits non-zero, which is what makes these testbenches usable directly
as CI gates.
RyuSim compiles and runs the Accellera UVM library natively, including the UVM DPI helpers.
RyuSim's own verification pins two packages: Accellera UVM 1.2 (the primary
package) and the IEEE 1800.2-2020 reference implementation
(accellera-official/uvm-core,
tag 2020.3.1). The examples below use UVM 1.2; unpack the Accellera distribution and point
UVM_HOME at it:
export UVM_HOME=/path/to/uvm-1.2
Write uvm_hello.sv — a test registered with the
UVM factory and started by run_test():
module uvm_hello;
import uvm_pkg::*;
`include "uvm_macros.svh"
class hello_test extends uvm_test;
`uvm_component_utils(hello_test)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
`uvm_info("HELLO", "Hello, world from UVM on RyuSim", UVM_LOW)
phase.drop_objection(this);
endtask
endclass
initial run_test();
endmodule
Compile it against the package. uvm_pkg.sv and the
stock uvm_dpi.cc are passed as sources, -I adds the package include
directory, and --dpi-define QUESTA selects the UVM HDL backdoor backend that is
written against standard VPI — the one RyuSim implements. The package source itself is
never patched:
ryusim compile uvm_hello.sv \
$UVM_HOME/src/uvm_pkg.sv $UVM_HOME/src/dpi/uvm_dpi.cc \
-I $UVM_HOME/src --dpi-define QUESTA --top uvm_hello
Compiling the whole UVM package is a substantial one-off cost — minutes to tens of
minutes depending on the machine, almost all of it in the C++ build phase. RyuSim runs that
phase at up to 8 parallel jobs by default; -j N sets it explicitly, and lowering
it is the usual fix if the build runs out of memory on the generated class header.
Select the test on the command line with +UVM_TESTNAME, exactly as with any other
simulator — RyuSim's plusarg handling feeds the standard
uvm_cmdline_processor:
./obj_dir/build/uvm_hello_sim +UVM_TESTNAME=hello_test
UVM prints its release-notes banner, runs the full phase ladder, and ends with the report
summary. Abridged ([...] marks omitted lines):
[...]
UVM_INFO @ 0: reporter [RNTST] Running test hello_test...
UVM_INFO uvm_hello.sv(14) @ 0: uvm_test_top [HELLO] Hello, world from UVM on RyuSim
[...]
--- UVM Report Summary ---
** Report counts by severity
UVM_INFO : 4
** Report counts by id
[HELLO] 1
[RNTST] 1
[TEST_DONE] 1
[UVM/RELNOTES] 1
Zero UVM_WARNING, UVM_ERROR and UVM_FATAL counts, and the
binary exits 0.
UVM's DPI-free configuration is also verified — RyuSim's smoke matrix keeps
uvm_pkg compiling and elaborating clean with
-DUVM_NO_DPI -DUVM_REGEX_NO_DPI -DUVM_CMDLINE_NO_DPI defined. That
configuration drops the UVM DPI helpers (regex matching, the HDL backdoor and the
command-line processor), so +UVM_TESTNAME selection is not available in it.
Python testbenches with cocotb remain fully supported over RyuSim's VPI interface, and back-compatibility for existing cocotb testbenches is contractual — v1 testbenches keep working unchanged on v2.
Note: as of the v2.0 release, RyuSim support has not landed in upstream cocotb. Install cocotb from the Seiraiyu fork first:
pip install git+https://github.com/Seiraiyu/cocotb.git@feat/ryusim-simulator-support
The fork adds the RyuSim runner and Makefile.ryusim to cocotb's build
infrastructure. Once upstream cocotb includes RyuSim support, plain pip install
cocotb will be enough — see Downloads.
Create a testbench file test_counter.py:
import cocotb
from cocotb.triggers import RisingEdge, FallingEdge
from cocotb.clock import Clock
@cocotb.test()
async def test_counter_counts(dut):
"""Check that the counter increments on each clock edge."""
cocotb.start_soon(Clock(dut.clk, 10, unit="ns").start())
dut.rst.value = 1
await RisingEdge(dut.clk)
await FallingEdge(dut.clk)
dut.rst.value = 0
for _ in range(10):
await RisingEdge(dut.clk)
await FallingEdge(dut.clk) # let NBA updates settle
assert dut.count.value.to_unsigned() == 10, f"Expected 10, got {dut.count.value.to_unsigned()}"
Create a Makefile in the same directory:
SIM ?= ryusim
TOPLEVEL_LANG := verilog
VERILOG_SOURCES = $(PWD)/counter.sv
TOPLEVEL = counter
COCOTB_TEST_MODULES = test_counter
include $(shell cocotb-config --makefiles)/Makefile.sim
Run the test:
make
cocotb will compile the design with RyuSim, load the VPI testbench, and report results. See the cocotb documentation for triggers, coroutines, bus drivers, and more.