I've been practicing writing some more advanced testbenches for my Verilog circuits. I thought I'd work with something simple: a double counter setup, where c0 is 3-bits long and c1 is 16-bits long. On paper, my circuit should work as follows:
c0: 0, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, ...
c1: 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, ...
I quickly made the circuit and tested it by hand, and it works as expected.
My module:
module double_counter (reset, clk, c0, c1);
input reset, clk;
output reg [2:0] c0;
output reg [15:0] c1;
always @(posedge reset or posedge clk) begin
if (reset) begin
c0 <= 0;
c1 <= 2;
end
else if (c0 == 7) begin
c0 <= 1;
c1 <= c1 + 1;
end
else c0 <= c0 + 1;
end
endmodule
The testbench I wanted to write would check at every positive edge of the clock if the counters were equal to some expected values. However, I'm getting a ton of errors (according to the testbench, not syntax errors) and I am not sure what I am doing wrong. Can anyone please help me understand what's going on?
My (old) attempt at a testbench:
module double_counter_tb;
reg reset, clk;
wire [2:0] c0;
wire [15:0] c1;
reg [2:0] expected_c0;
reg [15:0] expected_c1;
reg error;
integer i;
integer total_errors = 0;
double_counter DUT (reset, clk, c0, c1);
initial begin
clk = 0;
forever begin
#20 clk = ~clk;
end
end
initial begin
error = 1'b0;
reset = 0;
#80;
reset = 1;
#40;
expected_c0 = 0;
expected_c1 = 2;
if (expected_c0 != c0 | expected_c1 != c1) begin
$display("$0t, Error in reset test");
total_errors = total_errors + 1;
error = 1'bx;
end
else error = 1'b0;
#40;
reset = 0;
#80;
repeat (200) @(posedge clk) begin
expected_c0 = expected_c0 + 1;
if (expected_c0 == 7) begin
expected_c0 = 1;
expected_c1 = expected_c1 + 1;
end
if (expected_c0 != c0 | expected_c1 != c1) begin
$display("$0t, Error in test c0=%b, c1=%b", c0, c1);
total_errors = total_errors + 1;
error = 1'bx;
end
else error = 1'b0;
end
$display("Finished with %0d errors", total_errors);
end
endmodule
I'm running a relatively old version of ModelSim (I think it was 5.7 since that's all I had handy) if that is of any help. Thanks in advance!
EDIT: Based on @dave_59's answer, I was able to make considerable improvements to my previous testbench. My final, working testbench, looks like the following:
module double_counter_tb;
reg reset, clk;
wire [2:0] c0;
wire [15:0] c1;
reg [2:0] expected_c0;
reg [15:0] expected_c1;
reg error;
parameter fileout = "double_counter_results.txt";
integer i, f;
integer total_errors = 0;
double_counter DUT (reset, clk, c0, c1);
initial begin
clk = 0;
forever begin
#20 clk = ~clk;
end
end
initial begin
f = $fopen(fileout, "w");
$fwrite(f,"Beginning test...\n\n");
error = 1'b0;
reset = 0;
#80;
reset = 1;
#10;
expected_c0 <= 0;
expected_c1 <= 2;
if (expected_c0 != c0 | expected_c1 != c1) begin
$display("$0t, Error in reset test");
$fwrite(f,"$0t, Error in reset test\n");
total_errors = total_errors + 1;
error = 1'bx;
end
else error = 1'b0;
reset = 0;
repeat (100) @(posedge clk) begin
if (expected_c0 == 7) begin
expected_c0 <= 1;
expected_c1 <= expected_c1 + 1;
end
else expected_c0 <= expected_c0 + 1;
if (expected_c0 != c0 | expected_c1 != c1) begin
$fwrite(f,"Error in test c0=%b c1=%b, expected c0=%b, c1=%b\n", c0, c1, expected_c0, expected_c1);
$display("$0t, Error in test c0=%b, c1=%b ", c0, c1);
$display("$0t, expected c0=%b, c1=%b", expected_c0, expected_c1);
total_errors <= total_errors + 1;
error <= 1'bx;
end
else error <= 1'b0;
end
$display("Finished with %0d errors", total_errors);
$fwrite(f, "Finished with %0d errors", total_errors);
$fclose(f);
$finish;
end
endmodule