| Verilog Developing test benches for your Verilog models can take much more time and code than the original models. The process of enhancing the model and the test bench can be highly time consuming. While you develop test suites you can add $display and $monitor calls and custom tasks to check for correct responses. In the following examples we are going to develop the self-checking test bench for the 4-bit adder.
module self_test_adder;
reg [3:0] a,b;
reg cin;
wire [3:0] sum;
wire cout;
adder4 dut(cout,sum,a,b,cin);
initial begin
a=0; b=0; cin=0;
#10 if (sum!==0) begin
$display("sum is wrong");
$finish;
end
a=1; b=0; cin=0;
#10 if (sum!==1) begin
$display("sum is wrong");
$finish;
end
a=0; b=0; cin=1;
#10 if (sum!==1) begin
$display("sum is wrong");
$finish;
end
a=0; b=0; cin=0;
#10 if (sum!==0) begin
$display("sum is wrong");
$finish;
end
a=3; b=2; cin=0;
#10 if (sum!==5) begin
$display("sum is wrong");
$finish;
end
a=4; b=2; cin=1;
#10 if (sum!==7) begin
$display("sum is wrong");
$finish;
end
$finish;
end
endmodule
The four bit adder is built from two primitives: sum and carry.
module adder4(r,s,a,b,c);
output r;
output [3:0] s;
input [3:0] a,b;
input c;
wire t0,t1,t2;
sum s0(s[0],a[0],b[0],c);
sum s1(s[1],a[1],b[1],t0);
sum s2(s[2],a[2],b[2],t1);
sum s3(s[3],a[3],b[3],t2);
carry c0(t0,a[0],b[0],c);
carry c1(t1,a[1],b[1],t0);
carry c2(t2,a[2],b[2],t1);
carry c3(r,a[3],b[3],t2);
endmodule
|
primitive carry(r,a,b,c);
output r;
input a,b,c;
table
// a b c : r;
0 0 0 : 0;
0 0 1 : 0;
0 1 0 : 1;
0 1 1 : 1;
1 0 0 : 0;
1 0 1 : 1;
1 1 0 : 1;
1 1 1 : 1;
endtable
endprimitive
|
primitive sum(s,a,b,c);
output s;
input a,b,c;
table
// a b c : s;
0 0 0 : 0;
0 0 1 : 1;
0 1 0 : 1;
0 1 1 : 0;
1 0 0 : 1;
1 0 1 : 0;
1 1 0 : 0;
1 1 1 : 1;
endtable
endprimitive
|

Now we modify the sum primitive in order to induce an error.
primitive sum(s,a,b,c)
output s;
input a,b,c;
table
// a b c : s;
0 0 0 : 0;
0 0 1 : 1;
0 1 0 : 0; // 1 to 0 error
0 1 1 : 0;
1 0 0 : 1;
1 0 1 : 0;
1 1 0 : 1; // 0 to 1 error
1 1 1 : 1;
endtable
endprimitive
The simulation result is as follows:


In the following example the test module generates the required sum values by the use of arithmetical expression.
module self_test_adder_vc;
reg [3:0] a,b;
reg cin;
wire [3:0] sum;
wire cout;
adder4 dut(cout,sum,a,b,cin);
initial begin
a=0; b=0; cin=0;
#10 if (sum!==a+b+cin) begin
$display("sum is wrong");
$finish;
end
a=1; b=0; cin=0;
#10 if (sum!==a+b+cin) begin
$display("sum is wrong");
$finish;
end
a=0; b=0; cin=1;
#10 if (sum!==a+b+cin) begin
$display("sum is wrong");
$finish;
end
a=0; b=0; cin=0;
#10 if (sum!==a+b+cin) begin
$display("sum is wrong");
$finish;
end
a=3; b=2; cin=0;
#10 if (sum!==a+b+cin) begin
$display("sum is wrong");
$finish;
end
a=4; b=2; cin=1;
#10 if (sum!==a+b+cin) begin
$display("sum is wrong");
$finish;
end
$finish;
end
endmodule
The following example siplifies the test bench by using a task to replace the repeated section of code. Because the checking code has been condensed into a task, it is also easy to check cout.
module self_test_adder_task;
reg [3:0] a,b;
reg cin;
wire [3:0] sum;
wire cout;
adder4 dut(cout,sum,a,b,cin);
initial
begin
testadd(0,0,0);
testadd(1,0,0);
testadd(0,0,1);
testadd(3,2,0);
testadd(4,2,1);
testadd(7,7,1);
$finish;
end
task testadd;
input [3:0] ax,bx;
input cx;
begin
a=ax; b=bx; cin=cx;
#10 if ({cout,sum}!==ax+bx+cx)
begin
$display("sum is wrong");
$finish;
end
end
endtask
endmodule



The content of stimuli vector may be placed into a file adder4.vec. The following example shows the adder test bench modified to read the patterns from the file. The test bench applies the patterns using a continuous assignment, a for loop to increment the index variable (i) into the memory, and cheks the result using task. The for is hard coded loop through the first eight locations, so this needs to match the file.
module self_test_adder_task_file;
wire cin;
wire [3:0] a,b,sum;
wire cout;
reg [4+4+1:1] stim[0:7];
integer i;
adder4 dut(cout,sum,a,b,cin);
assign {a,b,cin} = stim[i]; // stimulus from memory
initial
begin
$readmemb("adder4.vec",stim);
for(i=0;i<8;i=i+1)
testadd;
$finish;
end
task testadd;
begin
#10 if ({cout,sum}!==a+b+cin)
begin
$display("sum is wrong");
$finish;
end
end
endtask
endmodule


Test benches for inouts
There are two parts of the test bench for each inout port; there is a wire connected to the port and a register for driving the input. The state of the port is seen on the wire. Values to be driven into the inout port are placed in the register. The register is connected to the port with a continuous assignmant.
When you need to observe the value being driven out from the module under test, the register must either not be driving or be disconnected. The simplest way to make register not to drive is to place a 'bz in it. The continuous assignment that connects the register to the port could also be used to disconnect the register from the port by using the conditional operator (?:).
module ram(data,address,read,write);
parameter AddressSize = 4;
parameter WordSize = 8;
inout [WordSize-1:0] data;
input [AddressSize-1:0] address;
input read,write;
reg [WordSize-1:0] mem [0:1<<AddressSize];
assign data = read ? mem[address] : {WordSize{1'bz}};
always @(write)
mem[address] = data;
always @(read or write)
if (read && write)
$display("Operational error in ram: read and write both active");
endmodule



|
|
|