RTL and gate-level simulation powered by a Rust backend. WASM support enables in-browser testing and debugging.
RHDL's simulation engine is built in Rust for maximum performance. Ruby designs are compiled into an optimized intermediate representation that the Rust backend evaluates cycle-by-cycle. This architecture delivers 10-100x speedups over interpreted simulation while maintaining cycle-accurate behavior.
Components, ports, behavior
Lower to simulation IR
Event-driven evaluation
Run simulations directly from Ruby with full control over clock generation, stimulus, and waveform capture.
require 'rhdl'
counter = Counter.new(width: 8)
# Create a simulation context
sim = RHDL::Sim::Simulator.new(counter)
# Configure waveform dumping
sim.vcd("counter.vcd") do |vcd|
vcd.trace(counter.count, counter.clk)
end
# Apply stimulus and run
sim.run do
counter.rst <= 1
tick
counter.rst <= 0
counter.en <= 1
256.times do |i|
tick
assert_eq counter.count, i & 0xFF
end
end
puts "Simulation passed! #{sim.cycle_count} cycles"
RHDL supports simulation at multiple abstraction levels. RTL simulation runs your design at the register-transfer level for fast functional verification. Gate-level simulation runs the synthesized netlist for timing-accurate validation.
| Feature | RTL Simulation | Gate-Level Simulation |
|---|---|---|
| Abstraction | Behavioral / register-transfer | Primitive gates and flip-flops |
| Speed | Fast — millions of cycles/sec | Slower — evaluates every gate |
| Accuracy | Cycle-accurate, no timing | Gate delays, setup/hold checks |
| Use case | Functional verification, debugging | Post-synthesis validation |
| Waveforms | High-level signals | Gate-level nets, glitches visible |
| Debug | Maps to Ruby source lines | Maps to netlist nodes |
RTL simulation evaluates behavior blocks directly. Fast iteration for design exploration.
# RTL-level simulation (default)
sim = RHDL::Sim::Simulator.new(
design,
level: :rtl
)
sim.run do
# Apply test vectors
design.opcode <= 0xA9 # LDA imm
design.data <= 0x42
tick 3
assert_eq design.acc, 0x42
assert design.zero == 0
end
puts "RTL sim: #{sim.cycles_per_sec} Hz"
# => RTL sim: 2_450_000 Hz
Gate-level simulation evaluates the synthesized netlist. Catches issues that RTL simulation misses.
# Gate-level simulation
netlist = design.synthesize
sim = RHDL::Sim::Simulator.new(
netlist,
level: :gate
)
sim.run do
# Same test vectors
netlist.opcode <= 0xA9
netlist.data <= 0x42
tick 3
assert_eq netlist.acc, 0x42
assert netlist.zero == 0
end
puts "Gate sim: #{sim.cycles_per_sec} Hz"
# => Gate sim: 185_000 Hz
The Rust simulation engine compiles to WebAssembly (WASM), enabling simulations to run entirely in the browser. This opens up possibilities for interactive tutorials, shareable demos, and collaborative debugging without any local toolchain installation.
Native simulation core
Compile to WASM + JS bindings
Run in any modern browser
Compile your design for browser execution. The WASM output includes JavaScript bindings for controlling the simulation from web applications.
# Compile design to WASM for browser simulation
design = Counter.new(width: 8)
design.to_wasm("web/sim.wasm",
expose: [:clk, :rst, :en, :count],
optimize: :size # optimize for download size
)
# Generated JS usage:
# import init, { Simulation } from './sim.js';
# const sim = new Simulation();
# sim.set_input('rst', 1);
# sim.tick();
# sim.set_input('rst', 0);
# sim.set_input('en', 1);
# sim.tick();
# console.log(sim.get_output('count')); // 1