Verilator & Cycle Simulation
RTL Bench doesn't just run one simulator. It intelligently routes your design to the best engine available: Icarus Verilog for rapid, event-driven simulation, or Verilator to compile your HDL into lightning-fast C++ for massive designs.
Event-Driven vs. Cycle-Based
To understand why RTL Bench switches engines, you have to understand the fundamental difference between how they simulate hardware.
| Engine | Type | How it works | Best for |
|---|---|---|---|
| Icarus Verilog | Event-Driven | Maintains an event queue. When a signal changes, it wakes up every gate connected to that signal. Highly accurate for timing, but slow on large designs. | Small designs, testbenches with #delays, and quick iteration. |
| Verilator | Cycle-Based | Compiles Verilog into a C++ program. It evaluates the entire design in chunks (cycles) rather than tracking every individual signal event. | Large designs, RISC-V cores, and simulations running millions of cycles. |
When does RTL Bench switch?
When you click Run Testbench, the backend extracts the gate-level metrics of your synthesized design. It then uses a heuristic to decide which engine will give you the result fastest.
Verilator requires compiling C++ code, which takes 3–5 seconds of overhead. If your design is tiny, Icarus is instant. If your design is huge, Verilator's C++ execution will finish before Icarus even starts.
// Simplified routing logic:
if (design.cells < 30000 && !is_pure_combinational) {
return "icarus"; // Too small to justify C++ compile time
} else if (design.flops > 5000 || design.muls > 20) {
return "verilator"; // Large design, use C++ speed
}
Reading the Engine Badge
Look at the top-right of the Simulation drawer. Next to your PASS/FAIL status, you will see a badge that tells you exactly which engine ran.
-
ICARUS · EVENT— The design was small enough that event-driven simulation was instantaneous. -
VERILATOR · CYCLE— The design was large, so it was compiled to C++ for maximum speed. -
⚠ ICARUS · EVENT— Verilator was attempted, but failed. (See the Fallback section below).
The Graceful Fallback
Verilator is a very strict compiler. It will throw a fatal error if it encounters things like multiple drivers (short circuits) or complex SystemVerilog timing constructs that it cannot synthesize.
If Verilator crashes, RTL Bench does not just throw a red error screen at you. Instead, it catches the C++ compilation error, logs it, and silently falls back to Icarus Verilog so you still get your waveforms.
When this happens, the badge changes to a yellow warning:
⚠ ICARUS · EVENT. Hovering over the badge will show
you exactly why Verilator rejected the design.
#10 or
wait(1ns). RTL Bench automatically rewrites your testbench
to use cycle-accurate @(posedge clk) blocks when routing to
Verilator. If it cannot rewrite the TB, it falls back to Icarus.
Why not just use Verilator for everything?
Because of the compile-time penalty. For a tiny 8-bit adder, Icarus takes 0.1 seconds to simulate. Verilator takes 4 seconds to invoke `g++`, compile the C++, and link the binary.
By keeping small designs on Icarus, RTL Bench guarantees that clicking "Run" feels instant. The switch to Verilator only happens when your design is complex enough that C++ execution time saves you more than the compilation time.
Frequently asked questions
Verilator is a cycle-accurate compiler. Instead of interpreting event queues and signal transitions dynamically like Icarus Verilog or ModelSim, Verilator translates synthesizable Verilog directly into highly optimized multithreaded C++ code, resulting in 10x to 100x speedups.
By default, Verilator simulates 2-state logic (0 and 1) for maximum execution speed, treating X and Z as 0 or 1. However, Verilator provides lint warnings and flags (such as --x-assign) to detect uninitialized registers and potential simulation/synthesis mismatches.
Yes. When waveform generation is enabled, the compiled C++ testbench includes VCD or FST tracing, allowing you to inspect high-speed waveforms directly in the RTL Bench waveform viewer.