I'm very new to FPGA work, and I'm trying to write a testbench for a full adder design that I have. The adder code looks like this:
module full_adder(
input wire A,
input wire B,
input wire INCARRY,
output logic CARRY,
output logic SUM
);
// Full Adder circuit - 3 inputs enter, only 2 outputs leave !
// So.. the carry is set if two or more inputs are set
wire logic ab;
wire logic bc;
wire logic ac;
assign ab = A && B;
assign bc = B && INCARRY;
assign ac = A && INCARRY;
assign CARRY = (ab || ac) || bc;
// And the sum is set if either 1 or all 3 inputs are set
wire logic one_input;
assign one_input = A ^ B;
assign SUM = one_input ^ INCARRY;
endmodule
I am trying to create a testbench for this and so far I have this :
module testbench;
// The inputs and outputs we care about for testing..
logic A;
logic B;
logic INCARRY;
logic SUM;
logic CARRY;
// import the actual logic..
full_adder u_full_adder (.*);
// Stimulus
initial begin
$printtimescale(testbench);
A = '0;
B = '0;
INCARRY = '0;
// And loop through our possible input states..
for (int i = 0; i < 8; i++) begin
$display("Setting inputs to A=%1b, B=%1b, INCARRY=%1b", i[0], i[1], i[2]);
A = i[0];
B = i[1];
INCARRY = i[2];
// and sleep a bit..
#100;
end // end of i loop
$display("PASS: full adder is working");
$stop;
end
// and the checking logic..
always @(A, B, INCARRY, CARRY, SUM) begin
// Check that the carry is set when 2 or more inputs are high
if ((1 < A + B + INCARRY) && CARRY !== 1) begin
$display("FAIL: Not carrying appropriately");
$stop;
end
end // end of always
endmodule
However, running this simulation in Vivado 2022.2, I get a failure stop the first time A and B go high together and the Objects display panel is showing:
NAME | Value |
---|---|
A | 1 |
B | 1 |
INCARRY | 0 |
SUM | 1 |
CARRY | 0 |
Now actually turning this into a bitstream and running it on hardware appears to work just fine (Basys3 board), and adding the internal wires to the display also shows "ab" as 1.
My suspicion is that there is some minute delay between setting the input wire and the output wires changing. To this end I have taken out the $stop and run the whole thing through to see the graph view, even at the most zoomed in I can get to it still appears to all change at once however.
Can anyone give me a hint as although this adder works (or appears to), I'd really like to be able to build reliable test bench code?
I tried running this multiple times and starting at different points in the execution (by tweaking the starting value of i
in the testbench code).
I am expecting the code to run through to the end without finding any problems, but it stops.
Timescale of (testbench) is 1ns/10ps.
Setting inputs to A=0, B=0, INCARRY=0
Setting inputs to A=1, B=0, INCARRY=0
Setting inputs to A=0, B=1, INCARRY=0
Setting inputs to A=1, B=1, INCARRY=0
FAIL: Not carrying appropriately
$stop called at time : 300 ns : File "whatever.sv"
You have a Verilog simulation race condition. You are checking signal values at the same time they are changing.
You can add a small delay after the signals change before you perform the check. For example, since your delay between input changes is 100, use a delay of 1 (#1
):
// and the checking logic..
always @(A, B, INCARRY, CARRY, SUM) begin
#1;
// Check that the carry is set when 2 or more inputs are high
if ((1 < A + B + INCARRY) && CARRY !== 1) begin
$display("FAIL: Not carrying appropriately");
$stop;
end
end // end of always
Output:
Time scale of (testbench) is 1ns / 1ns
Setting inputs to A=0, B=0, INCARRY=0
Setting inputs to A=1, B=0, INCARRY=0
Setting inputs to A=0, B=1, INCARRY=0
Setting inputs to A=1, B=1, INCARRY=0
Setting inputs to A=0, B=0, INCARRY=1
Setting inputs to A=1, B=0, INCARRY=1
Setting inputs to A=0, B=1, INCARRY=1
Setting inputs to A=1, B=1, INCARRY=1
PASS: full adder is working