Skip to content

Verification with Verilog

Table of Contents


Why are we doing verification with Verilog?

The RTL is in Verilog. Generally the flow of learning is Digitals -> RTL intro through Verilog -> Verifying the RTL using a TB. So, it is only logical to try to verify using what's already known until we hit a point where what we know is not enough (or probably not efficient at all) anymore!

4-bit Counter DUT Verification

module dut_4_bit_counter(
    input clk,
    input rstn,
    output reg[3:0] c_out
);

always @ (posedge clk) begin
    if(!rstn)
        c_out <= 0; //synchronous active low reset
    else
        c_out <= c_out + 1; //non-blocking
end
Hardware Description Languages (HDLs) operate in concurrancy. Languages like C that operate in procedural manner handle multiple assignments to a variable in a straight forward manner- the variable holds the last assigned value.

In case of Verilog, the value a variable holds at any instant is determined by:
- whether multiple drivers driving this variable. In which case, the final value will depend on the resolution functions.
- how the variable is synced to the clock

wire vs. reg

  • wire and reg are two different data types defined in Verilog.
  • wire represents a connection between two concurrent processes (physically, it'll manifest as a net between two components). It should be continously driven (in verilog, it is done using 'assign' keyword), and it can't store values. It can be driven by multiple drivers simultaneously and the value on the wire at any instant is determined by the underlying resolution function(verilog provide option to decide strength of the driver).
  • reg is a 1-bit 4-state variable. It is generally used to store data.
  • It's not allowed to drive a reg type variable using 'assign' keyword. Instead, reg variables are assigned values using = or <= within procedural blocks (always, initial, task, function).
  • A reg type will synthesize to a register only if it's linked to edge of clock. If it is linked to ALL the input signals and not clock, it'll synthesize to a combinational circuit. However, if all paths are not defined, it can inadvertently infer a latch, which is often undesirable.
    module reg_wire_example(
        input clk,
        input a,
        input b,
        output c,
        output d
    );
        wire temp_wire;
        reg i;
    
        // 1. Continuous assignment to wire 'temp_wire'
        assign temp_wire = a & b;
    
        // 2. Procedural block (sequential logic)
        always @(posedge clk) begin
            i <= a | b;
        end
    
        // 3. Assign 'c' (output) from 'temp_wire' (wire)
        assign c = temp_wire;
    
        // 4. Assign 'd' (output) from 'i' (reg)
        assign d = i;
    
    endmodule
    
    To understand how this code is interpreted at synthesis level (without any optimizations), refer below block diagram: Fig-1

Blocking vs. Non-blocking

Synchronous vs. Asynchronous

Verification Plan (4-bit)

Manual Verification (4-bit)

Test Bench (4-bit)

256-bit Counter DUT Verification

Verification Plan (256-bit)

Manual Verification (256-bit)

Test Bench (256-bit)

Tasks and Functions

System Tasks and Functions