# Verilog Double Counter Testbench Issues

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


A couple of problems.

You are using nonblcoking assigments in your DUT, but blocking assignments in your testbench. When you do the comparison, the DUT has not updated its values yet.

You wait too many clock cycles after reset.

This works for me

 initial begin
$dumpfile("dump.vcd");$dumpvars;
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");
total_errors = total_errors + 1;
error = 1'bx;
end
else error = 1'b0;
reset = 0;
repeat (100) @(negedge 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
$write("$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);$finish;
end

• Awesome, thanks! It works fine now. I took a look at the things you mentioned, and it definitely makes sense and I'm not sure how I missed it when first writing it. I'll add my new implementation (heavily based on yours) in an edit on my question. If you don't mind me asking though, what's the use for the $dumpfile and$dumpvars exactly? I've never used these functions until now and I was wondering what I can do with the .vcd file it creates Commented Feb 19 at 3:56
• For waveform viewing on edaplayground.com/x/DcLB Commented Feb 19 at 5:19

It looks like you're using bitwise "OR" instead of logical or: