Applications 1

De la WikiLabs

The Testbench Module

The testbench is a module used only in simulation for testing another module. It encloses the tested module (named DUT - Device Under Test) and generates the signals for the inputs of the DUT. Additionally the testbench may automatically check the correctness of the DUT outputs, and may report or log the values of various DUT signals and the events of the simulation. Simple testbenches generate all signals and do all checks and reports using verilog statements, but more complex testbenches may instantiate helper modules designed for various test functions and operations (signal drivers/generators, output checkers, signal monitors a.s.o.).

Dic lab1 testbench.png

For simple designs with few outputs that are easy to check visually on simulation waveforms, the testbench may be reduced to a DUT and the signals generation part.

For the first laboratory the testbench only generates some signals and does not instantiate any other module.

Exercise 1

One bit signal generation

Already a classical, the first program in any programming language tutorial displays the "Hello World" message. However, your first Vivado module will instead generate a very simple signal, a single binary pulse.

Dic lab1 one pulse.png

The simplest way to generate a signal in a testbench is to use a sequence of assignments that change the signal's value at predetermined steps of the simulation. The sequence of assignments is enclosed in a verilog procedural block of initial type. The initial procedural block starts its execution from the very beginning of simulation (hence its name, initial), and runs all its statements in order until the last one, after which it finishes.

module waveform1; // module declaration. The testbench module is named waveform1 and has no ports (its generated signal is internal).

reg a;            // signal declaration. Signal named a is a variable of type reg. The default size is one bit.

initial begin     // start of an initial procedural block
        a = 0;    // a is set to 0 at the beginning of simulation
    #10 a = 1;    // after 10 simulation steps, a is set to 1
    #10 a = 0;    // after other 10 simulation steps, a is reset to 0. The delays are cumulative, therefore this change occurs after 20 simulation steps from the beginning.
    #20 $stop;    // $stop is a system function to stop the simulation. All system functions are prefixed by the dollar symbol, '''$'''.
end               // ends the procedural block

endmodule         // end of module description

The verilog simulation advances in discrete steps. By default each step is counted as a 1 ns interval. Any verilog statement may be preceded by a delay. The delay tells the simulator how many simulation steps should pass until the statement is executed. The delay is an integer constant value prefixed by the special hash symbol: #delay_value

Exercise 2

Two one-bit signals generation

Dic lab1 two pulse.png


module waveform1;

reg a;            // first signal declaration
reg b;            // second signal declaration

initial begin     // initial procedural block for the generation of a
        a = 0;
    #10 a = 1;
    #10 a = 0;
    #20 $stop;    // Only one call is needed to stop the simulation 
end

initial begin     // initial procedural block for the generation of b
        b = 0;
     #5 b = 1;
    #10 b = 0;
end

endmodule

Each verilog procedural block is treated as a thread by Vivado simulator. All procedural blocks are seen as parallel threads. When one thread finishes its execution, other threads may still have statements to execute. The initial block for generation of b executes its last statement at step 15. However the simulation goes forward (there are still statements in the other initial block to be executed). The stop should be called from the initial procedural block that is last to finish. Alternatively, you may employ a separate initial block to stop the simulation, using a delay whose value covers all steps of the simulation:

initial #40 $stop;

Note: When a procedural block has only one statement you may leave off the begin and end keywords. Otherwise, the begin and end keywords should be employed to enclose the sequence of statements of that procedural block.

Exercise 3

Two one-bit signals generation

Two different (or more) signals may be generated using the same procedural block. You should be careful to sequence and delay the assignments for different signals such that to achieve the desired waveform. Remember that delays are cumulative.

module waveform1;

reg a, b;         // two variables of the same type (and width) may be declared in one declaration statement (not recommended)

initial begin
        a = 0;    // a is set to 0 at the beginning of simulation
        b = 0;    // b is set to 0 at the beginning of simulation
     #5 b = 1;    // after 5 simulation steps, b is set to 1             (at simulation step  5)
     #5 a = 1;    // after other 5 steps, the other variable is set to 1 (at simulation step 10)
                  // more statements to change a and b as desired                                  << COMPLETE THE MISSING CODE
    #20 $stop;
end

endmodule

Exercise 4

Multi-bit signal generation

Sometimes it is more convenient to generate multi-bit signals (such as data of various widths, vectors, bundled signals). Consider a 2 bit data whose value change in time as a sequence of integers.

Dic lab1 multibit.png

Multi-bit signal declaration sets the width of the signal using two indices. The left index is the index of the most significant bit (MSB), the right index is of the least significant bit (LSB)

module waveform1;

reg [1:0] data;   // A 2-bit variable of type reg, named data. MSB index is 1, LSB ndex is 0

initial begin
        data = 0; // data is set to 0 at the beginning of simulation
     #5 data = 1; // after 5 simulation steps, data changes to 1
     #5 data = 3; // after other 5 steps, data changes to 3
                  // more statements to change data value as desired                                  << COMPLETE THE MISSING CODE
    #20 $stop;
end

endmodule

In the above code the data values are given as decimal integers. Verilog integer constants may be written in 4 bases: decimal, hexadecimal, octal and binary. The decimal base is implicit if only a plain number literal is written. To write the value in another base you should prefix the number literal with a base specifier, which is the apostrophe sign folowed by a letter that specifies the base: 'd for decimal, 'b for binary, 'h for hexadecimal.

Generate the same sequence of data values using a binary number format:

initial begin
        data = 2'b00; // data is set to 0 at the beginning of simulation
     #5 data = 2'b01; // after 5 simulation steps, data changes to 1
     #5 data = 2'b11; // after other 5 steps, data changes to 3, which in binary is writen as 11
                      // more statements to change data value as desired                                  << COMPLETE THE MISSING CODE
    #20 $stop;
end

Exercise 5

Signal bundle generation

The 2-bit data signal from Exercise 4 may be seen as a bundle of two one-bit signals. If you look carefully at the waveform of Exercise 2 you may recognize that a and b together may be bundled as a 2-bit number, with a as its most significant bit and b as the last bit:

Dic lab1 multibit ab.png

You may generate separate signals grouping them into a bundle and assigning multi-bit values to this bundle. Two or more signals can be bundled together using the concatenation operator, { }. The bundled signals are listed inside the curly brackets of the concatenation operator, separated by commas. The signals' bits are arranged from left to right, in the order in which the signals are listed.

initial begin
        {a, b} = 2'b00; // a and b are both set to 0 at the beginning of simulation
     #5 {a, b} = 2'b01; // after 5 simulation steps, b changes to 1. a value does not change
                        // more statements to change a and b values as desired                                  << COMPLETE THE MISSING CODE
end