⚡ Digital Design Blog

Part 10 of 10

Verification Basics

Testbenches, simulation, and proving your design works

By Praveen Kumar Vagala

1,008 views

Why Verification?

Verification typically takes 60-70% of project time!

Testbench Structure

┌────────────────────────────────────────────────┐ │ Testbench │ │ │ │ ┌──────────┐ ┌──────────────────┐ │ │ │ Stimulus │───────►│ DUT │ │ │ │Generator │ │ (Design Under │ │ │ └──────────┘ │ Test) │ │ │ └────────┬─────────┘ │ │ │ │ │ ┌──────────┐ │ │ │ │ Monitor/ │◄────────────────┘ │ │ │ Checker │ │ │ └──────────┘ │ │ │ └────────────────────────────────────────────────┘

Simple Testbench

module counter_tb;
    // Testbench signals
    reg        clk;
    reg        rst_n;
    reg        enable;
    wire [3:0] count;
    
    // Instantiate DUT
    counter4 dut (
        .clk    (clk),
        .rst_n  (rst_n),
        .enable (enable),
        .count  (count)
    );
    
    // Clock generation
    initial clk = 0;
    always #5 clk = ~clk;  // 100MHz (10ns period)
    
    // Stimulus
    initial begin
        // Initialize
        rst_n = 0;
        enable = 0;
        
        // Reset
        #20;
        rst_n = 1;
        
        // Enable counting
        #10;
        enable = 1;
        
        // Let it count
        #200;
        
        // Disable
        enable = 0;
        #50;
        
        // End simulation
        $display("Test completed!");
        $finish;
    end
    
    // Monitor
    initial begin
        $monitor("Time=%0t rst_n=%b enable=%b count=%d",
                 $time, rst_n, enable, count);
    end
    
    // Waveform dump (for viewing in waveform viewer)
    initial begin
        $dumpfile("counter.vcd");
        $dumpvars(0, counter_tb);
    end
endmodule

Self-Checking Testbench

module adder_tb;
    reg  [7:0] a, b;
    reg        cin;
    wire [7:0] sum;
    wire       cout;
    
    // Expected values
    reg [8:0] expected;
    integer errors;
    
    // DUT
    adder8 dut (
        .a(a), .b(b), .cin(cin),
        .sum(sum), .cout(cout)
    );
    
    initial begin
        errors = 0;
        
        // Test all combinations (exhaustive for small designs)
        for (a = 0; a < 256; a = a + 1) begin
            for (b = 0; b < 256; b = b + 1) begin
                for (cin = 0; cin < 2; cin = cin + 1) begin
                    #1;  // Wait for combinational logic
                    
                    expected = a + b + cin;
                    
                    if ({cout, sum} !== expected) begin
                        $display("ERROR: a=%d b=%d cin=%d, got %d, expected %d",
                                 a, b, cin, {cout, sum}, expected);
                        errors = errors + 1;
                    end
                end
            end
        end
        
        // Report
        if (errors == 0)
            $display("TEST PASSED!");
        else
            $display("TEST FAILED with %d errors", errors);
            
        $finish;
    end
endmodule

Clock and Reset Generation

// Method 1: Initial + always
initial clk = 0;
always #5 clk = ~clk;

// Method 2: Forever loop
initial begin
    clk = 0;
    forever #5 clk = ~clk;
end

// Method 3: Parameterized
parameter CLK_PERIOD = 10;
initial clk = 0;
always #(CLK_PERIOD/2) clk = ~clk;

// Reset generation
initial begin
    rst_n = 0;
    repeat(5) @(posedge clk);  // Hold reset for 5 clocks
    rst_n = 1;
end

Tasks and Functions

// Task: Can have delays, multiple outputs
task write_data;
    input [7:0] data;
    input [3:0] addr;
    begin
        @(posedge clk);
        wr_en <= 1;
        wr_addr <= addr;
        wr_data <= data;
        @(posedge clk);
        wr_en <= 0;
    end
endtask

// Usage
initial begin
    write_data(8'hAB, 4'h0);
    write_data(8'hCD, 4'h1);
end

// Function: No delays, single output
function [7:0] expected_result;
    input [7:0] a, b;
    begin
        expected_result = a ^ b;  // XOR for example
    end
endfunction

System Tasks

// Display and monitoring
$display("Value = %d", value);        // Print once
$monitor("clk=%b data=%h", clk, data); // Print on change
$strobe("At end of timestep: %d", x);  // Print at end of timestep

// Time
$time      // Current simulation time (integer)
$realtime  // Current simulation time (real)

// File I/O
integer fd;
fd = $fopen("output.txt", "w");
$fdisplay(fd, "Data: %h", data);
$fclose(fd);

// Waveform
$dumpfile("waves.vcd");
$dumpvars(0, testbench);  // Dump all signals

// Control
$finish;   // End simulation
$stop;     // Pause simulation (for debugging)

Assertions (SystemVerilog)

// Immediate assertion
always @(posedge clk) begin
    assert (count < 16) else $error("Count overflow!");
end

// Concurrent assertions
// Check that valid is followed by ready within 5 cycles
property valid_handshake;
    @(posedge clk) valid |-> ##[1:5] ready;
endproperty

assert property (valid_handshake)
    else $error("Handshake timeout!");

// Cover property (for coverage)
cover property (@(posedge clk) state == ERROR);

Code Coverage

Measures how much of your design was exercised:

TypeWhat It Measures
Line CoverageWhich lines executed
Branch CoverageWhich if/else branches taken
Toggle CoverageWhich signals toggled 0→1 and 1→0
FSM CoverageWhich states visited, transitions taken
Condition CoverageBoolean sub-expressions

Random Testing

// Basic random
initial begin
    repeat(1000) begin
        data = $random;           // 32-bit random
        addr = $urandom_range(0, 255);  // Range 0-255
        #10;
        check_result();
    end
end

// Constrained random (SystemVerilog)
class Transaction;
    rand bit [7:0] addr;
    rand bit [31:0] data;
    
    constraint valid_addr { addr < 100; }
    constraint aligned { data[1:0] == 0; }
endclass

Transaction t = new();
t.randomize();

Testbench Checklist

ItemDescription
✓ Clock generationCorrect frequency
✓ Reset sequenceProper initialization
✓ StimulusCover normal and edge cases
✓ Self-checkingCompare with expected values
✓ Error reportingClear pass/fail indication
✓ TimeoutPrevent infinite simulation
✓ Waveform dumpFor debugging

Summary

ConceptKey Point
TestbenchStimulus + DUT + Checker
Self-checkingCompare actual vs expected
TasksReusable stimulus sequences
AssertionsCheck design properties
CoverageMeasure test completeness

🎉 Congratulations!

You've completed the Digital Design Blog Series!

You now have a solid foundation in digital design concepts.

← Back to All Articles