Here is the design that is supposed to compare two floating point numbers:
// IEEE 764: FP[31] = sign, FP[30:23] = exp, FP[22:0] = mantissa
module compare_fp(input [31:0] floatA,
input [31:0] floatB,
output reg [1:0] compareRes);
// equal: 2, A>B: 1, A<B: 0
assign compareRes[1] = (floatA == floatB); // if they are equal, set the MSB of output to 1
// if A > B set the LSB of output to 1
// 1. A>0, B<0
// 2. sign same, compare exp
// 3. sign and exp same, compare matissa
assign compareRes[0] = ((!floatA[31]) && floatB[31]) ||
(((floatA[31] & floatB[31]) == 1) && (floatA[30:23] < floatB[30:23])) ||
(((floatA[31] | floatB[31]) == 0) && (floatA[30:23] > floatB[30:23])) ||
(((floatA[31] & floatB[31]) == 1) && (floatA[30:23] == floatB[30:23]) && (floatA[22:0] < floatB[22:0])) ||
(((floatA[31] | floatB[31]) == 0) && (floatA[30:23] == floatB[30:23]) && (floatA[22:0] > floatB[22:0]));
endmodule
I wrote a simple testbench following https://verificationguide.com/systemverilog-examples/systemverilog-testbench-example-adder-2/, and I attached it here:
// Code your testbench here
// or browse Examples
class transaction;
randc bit [31:0] floatA;
randc bit [31:0] floatB;
logic [1:0] compareRes;
// constrain the input
//constraint constraint_float {floatA==floatB;}
// actual float
shortreal float_A;
shortreal float_B;
function void display(string name);
$display("---------");
$display("%s",name);
$display("a = %0f, b = %0f, result = %0d", float_A, float_B, compareRes);
$display("a = %0b, b = %0b, result = %0d", floatA, floatB, compareRes);
$display("---------");
endfunction
endclass
class generator;
rand transaction trans;
mailbox gen2drv;
event ended;
int generateCount; // number of cases
function new(mailbox gen2drv);
this.gen2drv = gen2drv;
endfunction
task main();
repeat(generateCount) begin
// create and randomize
trans = new();
if( !trans.randomize()) $fatal("gen: trans randomization failed");
// calculating actual number
trans.float_A = $bitstoshortreal(trans.floatA);
trans.float_B = $bitstoshortreal(trans.floatB);
gen2drv.put(trans);
end
-> ended; //end of generation
endtask
endclass
interface intf;
bit [31:0] floatA;
bit [31:0] floatB;
logic [1:0] compareRes;
endinterface
class driver;
int transaction_count;
mailbox gen2drv;
virtual intf vif;
// constructor
function new(virtual intf vif, mailbox gen2drv);
this.vif = vif;
this.gen2drv = gen2drv;
endfunction
task main;
forever begin
transaction trans;
gen2drv.get(trans);
vif.floatA = trans.floatA;
vif.floatB = trans.floatB;
trans.display("[ Driver ]");
transaction_count++;
end
endtask
endclass
class environment;
generator gen;
driver drv;
mailbox gen2drv;
virtual intf vif;
//constructor
function new(virtual intf vif);
this.vif = vif;
gen2drv = new();
gen = new(gen2drv);
drv = new(vif, gen2drv);
endfunction
task test();
fork
gen.main();
drv.main();
join_any
endtask
task post_test();
wait(gen.ended.triggered);
wait(gen.generateCount == drv.transaction_count);
endtask
task run;
test();
post_test();
$finish;
endtask
endclass
program test(intf intf);
environment env;
initial begin
env = new(intf);
env.gen.generateCount = 3;
env.run();
end
endprogram
module tb;
intf intf1();
test t1(intf1);
compare_fp dut (.floatA(intf1.floatA), .floatB(intf1.floatB), .compareRes(intf1.compareRes));
endmodule
But the output (compareRes
) is always x.
I then wrote a simpler testbench where I manually choose input, and the design works just fine. Below is the simple testbench:
// Code your testbench here
// or browse Examples
interface test;
logic [31:0] floatA;
logic [31:0] floatB;
logic [1:0] compareRes;
endinterface
module tb;
test st();
shortreal float_A;
shortreal float_B;
compare_fp dut(.floatA(st.floatA), .floatB(st.floatB), .compareRes(st.compareRes));
initial begin
#10 st.floatA = 32'b11000000010101001100000001011001;
#10 st.floatB = 32'b01000000010101000111101011100001;
#10 float_A = $bitstoshortreal(st.floatA);
#10 float_B = $bitstoshortreal(st.floatB);
#10 $display("%f %f is %0d", float_A, float_B, st.compareRes);
end
endmodule
So maybe there is something wrong with the value delivery in my testbench? Can anyone give me some suggestion as how to debug the testbench?
In your transaction
display
function, compareRes
is always x because you never assigned a value to it. You declared compareRes
as a logic
type, which defaults to x, but then you never changed its value.
You correctly connected the dut
compareRes
signal to the intf1
interface
in the testbench, but you never made an assignment from the interface
compareRes
to the transaction
compareRes
. This is usually done in a testbench monitor. You should add a monitor to your testbench where you make the assignment. If you are going through all the trouble of creating a class-based testbench, consider adopting the UVM, which is now standard in the industry.
In the driver
, I added the assignment with a delay to try to avoid race conditions:
task main;
forever begin
transaction trans;
gen2drv.get(trans);
vif.floatA = trans.floatA;
vif.floatB = trans.floatB;
#1 trans.compareRes = vif.compareRes;
trans.display("[ Driver ]");
transaction_count++;
end
endtask
When I run the simulation, I see result
= 1 and 0, instead of x. Although this might work for you, this is not the recommended approach.
Also, you should not rely only on $display
output. You should also dump a waveform database and look at signals in a waveform viewer. I did so and was able to confirm the the signals in the dut
had the expected values.
I tried reading the link that you provided to understand why they created a testbench without a monitor, but I found the pop-up ads too distracting.