4 minutes
My Verilog ModelSim Testbench Templates
Combinational Circuits
A sample testbench for one of my previous projects is here:
`timescale 1 ns/10 ps // time-unit = 1 ns, precision = 10 ps
module GAUSSIAN_CONVOLUTION_TB;
reg [3*3*8-1:0] color_matrix;
wire [7:0] conv_result;
// duration for each period = 20 * timescale = 20 * 1 ns = 20ns
localparam period = 20;
reg return_black;
GAUSSIAN_CONVOLUTION CONV (
.color_matrix(color_matrix),
.conv_result(conv_result),
.return_black(return_black)
);
initial // initial block executes only once
begin
return_black = 0;
// values for a and b
color_matrix = {8'd255, 8'd255, 8'd255, 8'd255, 8'd255, 8'd255, 8'd255, 8'd255, 8'd255};
#period; // wait for period
color_matrix = {8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0};
#period;
color_matrix = {8'd255, 8'd10, 8'd45, 8'd65, 8'd36, 8'd47, 8'd53, 8'd111, 8'd200};
#period;
return_black = 1;
color_matrix = {8'd255, 8'd255, 8'd255, 8'd255, 8'd255, 8'd255, 8'd255, 8'd255, 8'd255};
#period; // wait for period
color_matrix = {8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0};
#period;
color_matrix = {8'd255, 8'd10, 8'd45, 8'd65, 8'd36, 8'd47, 8'd53, 8'd111, 8'd200};
#period;
end
endmodule
A few important lines:
timescale 1 ns/10 ps
localparam period = 20
#period
- See when
reg
andwire
are used
Sequential Circuits
A sample testbench for one of my previous projects is here:
module GAUSSIAN_BLUR_TB;
reg clk;
reg [10:0] x;
reg [10:0] y;
reg [7:0] curr_pixel_data;
wire [7:0] blurred_pixel_data;
integer write_data;
integer i;
// [7:0] 8 bits of data per pixel color
// [0:63] a total of 64 pixels in 64 lines (8 lines of 8 pixels)
reg [7:0] read_data [0:230400];
GAUSSIAN_BLUR #(
.LINE_WIDTH(640),
.PIXEL_DATA_WIDTH(8),
.NUM_ADDR_BITS_X(11),
.NUM_ADDR_BITS_Y(11)
)
GB (
.clk(clk),
.x(x),
.y(y),
.curr_pixel_data(curr_pixel_data),
.blurred_pixel_data(blurred_pixel_data),
.in_valid(1'b1)
);
initial begin
clk = 1'b0;
repeat(230400*2) #10 clk = ~clk; // generate a clock
end
initial begin
x = 1'b0;
y = 1'b0;
i = 0;
$readmemh("test_input_output_files/dimmer_green_channel.txt", read_data);
write_data = $fopen("test_input_output_files/dimmer_green_channel_out.txt");
repeat(230400) @(posedge clk) begin
curr_pixel_data = read_data[i];
$fdisplay(write_data, "%h", blurred_pixel_data);
i = i + 1;
if (x == 639) begin
x = 0;
y = y + 1;
end
else x = x + 1;
end
$fclose(write_data);
end
endmodule
A few lines to note:
$readmemb
used to read a file for binary data$fopen
and$fdisplay
used to write to fileinteger i
used to iterate through data read array- The setting up of the clock signal in the initial block
- The use of
repeat
to count the number of loops to make
Sample of a self-checking + randomising testbench for combinatorial circuit:
The module file:
`timescale 1ns / 1ps
module adder(
input logic [3:0] a, b,
output logic [4:0] sum
);
assign sum = a + b;
endmodule
The testbench file with self checking + randomising:
`timescale 1ns / 1ps
module adder_tb();
logic [3:0] a_in;
logic [3:0] b_in;
logic [4:0] result_out;
logic [4:0] true_result;
adder dut(a_in, b_in, result_out);
localparam period = 10;
initial begin
repeat(10) begin
a_in = $urandom_range(7, 0);
b_in = $urandom_range(7, 0);
true_result = a_in + b_in;
#period;
$display(result_out);
$display(true_result);
if (result_out != true_result) begin
$error("Incorrect Output");
end
end
$display("Test passed");
$finish;
end
endmodule
Sample of a self-checking + randomising testbench for sequential circuit:
The module file:
`timescale 1ns / 1ps
module adder(
input logic clk,
input logic [3:0] a, b,
output logic [4:0] sum
);
always_ff @(posedge clk) begin
sum <= a + b;
end
endmodule
The testbench file with self checking + randomising:
`timescale 1ns / 1ps
module adder_tb();
logic clk;
logic rst;
logic [3:0] a_in;
logic [3:0] b_in;
logic [4:0] result_out;
logic [4:0] true_result;
localparam period = 10;
adder dut(clk, rst, a_in, b_in, result_out);
initial begin
clk = 0;
rst = 1;
repeat(4) #(period/2) clk=~clk;
rst = 0;
forever #(period/2) clk=~clk;
end
initial begin
a_in = 0;
b_in = 0;
//result_out = 0;
true_result = 0;
// wait for rst
@(negedge rst);
repeat (50) @(posedge clk) begin
true_result = a_in + b_in; // do this before reassigning to show correct order
#(1)
a_in = $urandom_range(7, 0);
b_in = $urandom_range(7, 0);
$display("Result out:", result_out);
$display("True Result:", true_result);
$display("\n");
end
end
endmodule
Some examples of randomiser functions in SV:
$urandom( ) and $random( )
eg. variable = $urandom(seed); //seed is an optional argument
$urandom_range()
The $urandom_range() function returns an unsigned integer within a specified range.
variable = $urandom_range( int unsigned maxval, int unsigned minval = 0 );
std::randomise()
Variables can be randomized by using std::randomize method. It can accept the inline constraints using the “with” clause.
std::randomize (variable); std::randomize (variable) with { constraint’s; };
std::randomize (variable-1, variable-2 … variable-n); std::randomize (variable-1, variable-2 … variable-n) with { constraint’s; };
eg std::randomize(data,data_x_4) with { data == addr * 8;
data_x_4 == data * 4;
};