Verilog Coding Tips and Tricks: How to Write a simple Testbench for your Verilog Design

Thursday, November 12, 2015

How to Write a simple Testbench for your Verilog Design

Once you complete writing the Verilog code for your digital design the next step would be to test it. First we have to test whether the code is working correctly in functional level or simulation level. A program written for testing the main design is called Testbench

In this post I want to show you, how to write a very simple testbench. Lets consider two types of designs. One without any clock(purely combinational) and one with clock(contains synchronous elements).

Without Clock:

The module takes two inputs A and B and returns the XOR of A and B as output on port C.

//XOR module
module test(A,B,C);

    input [7:0] A,B;
    output [7:0] C;
    
    assign C = A ^ B;
    
endmodule

The testbench code for the above module is given below. I have commented it well enough to show you the important sections.

//testbench module.
//Its a testbench, so we dont have any inputs or outputs for this module.
module tb;

    // Declare the Inputs as Reg's
    reg [7:0] A;
    reg [7:0] B;

    // Declare the Outputs as wire's
    wire [7:0] C;

    // Instantiate the design you want to test.
    //Read this for instantiation methods
    test uut (
        .A(A), 
        .B(B), 
        .C(C)
    );

//We will apply the inputs here.
    initial begin
        // Apply the first set of Inputs
        A = 100;
        B = 40;
        #100; //wait for some time before we apply the next input.
        //Apply the 2nd set of inputs and so on...
      A = 10;
        B = 30;
        #100; //wait for some time before we apply the next input.  
        A = 255;
        B = 0;
        #100;
    end
//end the simulation inputs here.   

//In case your simulator doesnt have a simulation waveform then display the inputs and outputs
//using display system command.
//whenever there is a change in A or B execute the always block.
always@(A,B)
    $display("A = %b,B = %b,C = A xor B = %b",A,B,C);
    
endmodule


The following lines will be printed after the codes were simulated:

A = 01100100,B = 00101000,C = A xor B = xxxxxxxx
A = 00001010,B = 00011110,C = A xor B = 01001100
A = 11111111,B = 00000000,C = A xor B = 00010100

I used Xilinx ISE 13.1 for simulation and I got the following waveform. For bigger designs with tons of variables and internal signals, I prefer using simulation waveform to debug the design.


With Clock:

For simplicity I will just add a clock to the above module. The XOR operation will take place at every positive edge of the clock. 

//XOR module with clock
module test(CLK,A,B,C);

    input CLK;
    input [7:0] A,B;
    output [7:0] C;
    reg [7:0] C;
    
    always@ (posedge CLK)
        C = A ^ B;
    
endmodule


The testbench for this type is almost the same as the old one. Just that, we have to add a clock here. Also we have generate a clock which keeps alternating between 0 and 1 till the end of simulation.


//testbench module.
//Its a testbench, so we dont have any inputs or outputs for this module.
module tb;

    // Declare the Inputs as Reg's
    reg [7:0] A;
    reg [7:0] B;
    reg CLK;

    // Declare the Outputs as wire's
    wire [7:0] C;

    // Instantiate the design you want to test.
    //Read this for instantiation methods
    test uut (
        .CLK(CLK),
        .A(A), 
        .B(B), 
        .C(C)
    );

//Generate the clock here:
    initial CLK = 0;  //initialize the clock value to zero
     //toggle the clock value every 10 ns. 
     //So the clock has a clock period of 20 ns.
    always #10 CLK = ~CLK; 

//We will apply the inputs here.
    initial begin
        // Apply the first set of Inputs
        A = 100;
        B = 40;
        #100; //wait for some time before we apply the next input.
        //Apply the 2nd set of inputs and so on...
      A = 10;
        B = 30;
        #100; //wait for some time before we apply the next input.  
        A = 255;
        B = 0;
        #100;
    end
//end the simulation inputs here.   

//In case your simulator doesnt have a simulation waveform then display the inputs and outputs
//using display system command.
//whenever there is a change in A or B execute the always block.
always@(A,B)
    $display("A = %b,B = %b,C = A xor B = %b",A,B,C);
    
endmodule


The display system function outputs the same results as in the last case. The simulation waveform obtained in Xilinx ISE 13.1 is pasted below:


Note how the output port C is only updated at the positive edge of the clock and not right after the change of inputs.

Notes:-

As with everything else, you can get creative with testbench designs too. For complex designs you might have to read the inputs from the files and write the outputs to the files. Here I just wanted to show you something very basic. I will cover many more aspects of testbench design in coming posts.

No comments:

Post a Comment