RTL Bench PRO

How Verilog simulation works

Unlike standard software executed step-by-step on a CPU, hardware logic evaluates concurrently across clock cycles. This guide breaks down discrete event queues, testbench writing, VCD waveform internals, and how browser-based execution runs in the cloud.

1. The event-driven simulation queue

Verilog simulators like Icarus Verilog use a discrete event scheduler. Time advances only when an active event occurs (a clock edge rises, a wire toggles state), rather than calculating every picosecond continuously.

💡 The Stratified Event Queue: Events within the same timestamp are partitioned into distinct regions to prevent race conditions:
  • Active Region: Evaluates continuous assignments (assign), blocking statements (=), and $display routines.
  • Inactive Region: Evaluates statements delayed by zero time units (#0). Avoid using #0 in synthesizable RTL.
  • NBA (Non-Blocking Assignment) Region: Evaluates registers assigned with <=. This ensures all flip-flops sample their inputs simultaneously on a clock edge before updating their output registers.
  • Postponed Region: Samples variables for trace generation ($dumpvars) and concurrent assertions without logging intermediate glitches.

2. Anatomy of a Verilog testbench

A testbench is a verification harness that contains no input or output ports. It instantiates your module (the DUT, Device Under Test), generates clocks and resets, applies input stimuli, and records the output response.

DUT Port Type Testbench Declaration Reason
input reg (or logic) The testbench actively updates values inside procedural blocks (initial / always).
output wire The output is driven by the DUT and read passively by the testbench.

Shift register & testbench example

Here is an 8-bit serial-in, parallel-out (SIPO) shift register alongside a self-contained verification testbench:

// Synthesizable Design Under Test (DUT)
module shift_reg_8bit (
  input  wire       clk,
  input  wire       rst_n,
  input  wire       shift_en,
  input  wire       din,
  output reg  [7:0] dout
);
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      dout <= 8'h00;
    end else if (shift_en) begin
      dout <= {dout[6:0], din};
    end
  end
endmodule
// Simulation Testbench
`timescale 1ns/1ps

module tb_shift_reg;
  reg        clk;
  reg        rst_n;
  reg        shift_en;
  reg        din;
  wire [7:0] dout;

  shift_reg_8bit dut (
    .clk(clk), .rst_n(rst_n),
    .shift_en(shift_en), .din(din), .dout(dout)
  );

  // 100 MHz clock (10ns period)
  always #5 clk = ~clk;

  initial begin
    $dumpfile("waveform.vcd");
    $dumpvars(0, tb_shift_reg);

    clk = 0; rst_n = 0; shift_en = 0; din = 0;
    #12 rst_n = 1; // release async reset

    @(negedge clk); shift_en = 1; din = 1;
    @(negedge clk); din = 0;
    @(negedge clk); din = 1;
    @(negedge clk); din = 1;

    @(negedge clk); shift_en = 0; din = 0;
    #20;
    $finish;
  end
endmodule

3. How waveforms are captured: The VCD format

When running tools like Icarus Verilog (iverilog + vvp), transition data is recorded in Value Change Dump (VCD) format, defined by IEEE 1364:

  • Header Section: Declares the simulation timescale ($timescale 1ns$end), module scopes, and variable mapping tokens.
  • Change Section: VCD records only value changes. If a bus remains at 0xAA for 500 clock cycles, no entries are recorded until the next transition.
â„šī¸ The Four-Valued Logic System: Digital simulators track four discrete states: 0 (Low/GND), 1 (High/Vdd), X (Unknown / uninitialized register), and Z (High Impedance / floating net).

4. Common simulation pitfalls

  1. Missing $finish: If your testbench omits $finish;, the clock will toggle indefinitely until backend servers enforce an execution timeout.
  2. Stimulus race conditions: Changing input variables directly on @(posedge clk) can lead to non-deterministic sampling across different simulators. Always apply stimulus on @(negedge clk) or introduce a slight propagation offset (e.g. #1 din = 1;).
  3. Inferred latches: Combinational blocks with incomplete conditional assignments (e.g., an if without an else branch) tell the synthesizer to preserve stale values, creating asynchronous latches.

Frequently asked questions

How does the online Verilog simulator work?

RTL Bench compiles HDL source code using Icarus Verilog (iverilog -g2012) in isolated cloud containers. The output executable (vvp) generates a Value Change Dump (VCD) file, which is streamed back to your browser and visualized interactively without installing local software.

Can I simulate modules without writing a custom testbench?

Yes. If no module containing $dumpfile or $dumpvars is detected, RTL Bench automatically analyzes the top-level module ports, synthesizes a dynamic testbench, drives clock and reset sequences, and supplies randomized input stimulus.

Are multi-file designs and memory files supported?

Yes. You can upload multiple .v and .sv files, header files (.vh, .svh), and memory initialization files referenced through $readmemh or $readmemb.

Next

Try it in the workbench →