Init commit
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
// sim/fp_mult_tb.sv
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module fp_mult_tb;
|
||||
|
||||
logic [31:0] a, b, z;
|
||||
logic [2:0] rnd;
|
||||
logic [7:0] status;
|
||||
logic clk = 0, rst = 0;
|
||||
|
||||
// DUT
|
||||
fp_mult dut (
|
||||
.a(a),
|
||||
.b(b),
|
||||
.rnd(rnd),
|
||||
.z(z),
|
||||
.status(status),
|
||||
.clk(clk),
|
||||
.rst(rst)
|
||||
);
|
||||
|
||||
// Clock generation
|
||||
always #5 clk = ~clk;
|
||||
|
||||
typedef struct {
|
||||
logic [31:0] a;
|
||||
logic [31:0] b;
|
||||
logic [31:0] expected;
|
||||
string desc;
|
||||
} test_vector_t;
|
||||
|
||||
test_vector_t tests [11];
|
||||
|
||||
initial begin
|
||||
$display("Starting fp_mult test...\n");
|
||||
|
||||
// Normal multiplication cases
|
||||
tests[0] = '{32'h3f800000, 32'h40000000, 32'h40400000, "1.0 * 2.0 = 2.0"};
|
||||
tests[1] = '{32'h40400000, 32'h40400000, 32'h40c00000, "3.0 * 3.0 = 9.0"};
|
||||
tests[2] = '{32'hbf800000, 32'h40000000, 32'hc0400000, "-1.0 * 2.0 = -2.0"};
|
||||
tests[3] = '{32'h3f000000, 32'h3f000000, 32'h3e800000, "0.5 * 0.5 = 0.25"};
|
||||
tests[4] = '{32'h3f800000, 32'h00000000, 32'h00000000, "1.0 * 0.0 = 0.0"};
|
||||
|
||||
// Corner cases (some may fail if not handled yet)
|
||||
tests[5] = '{32'h7f800000, 32'h3f800000, 32'h7f800000, "inf * 1.0 = inf"};
|
||||
tests[6] = '{32'hff800000, 32'h3f800000, 32'hff800000, "-inf * 1.0 = -inf"};
|
||||
tests[7] = '{32'h7fc00000, 32'h3f800000, 32'h7fc00000, "NaN * 1.0 = NaN"};
|
||||
tests[8] = '{32'h00800000, 32'h00800000, 32'h00000000, "denorm * denorm = underflow"};
|
||||
tests[9] = '{32'h7f7fffff, 32'h7f7fffff, 32'h7f800000, "max * max = inf (overflow)"};
|
||||
tests[10] = '{32'h00000000, 32'hff800000, 32'hffc00000, "0.0 * -inf = NaN"};
|
||||
|
||||
rnd = 3'b000; // default round to nearest
|
||||
rst = 1; #10;
|
||||
rst = 0; #10;
|
||||
|
||||
for (int i = 0; i < 11; i++) begin
|
||||
a = tests[i].a;
|
||||
b = tests[i].b;
|
||||
#20;
|
||||
$display("[%0d] %s", i+1, tests[i].desc);
|
||||
$display(" A=%h B=%h => Z=%h (expected %h) %s\n",
|
||||
a, b, z, tests[i].expected,
|
||||
(z === tests[i].expected) ? "PASS" : "FAIL");
|
||||
end
|
||||
|
||||
$display("\nFinished fp_mult test.");
|
||||
$stop;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
//////
|
||||
// Please consider this function a black box. DO NOT try to copy any part of this function in your code.
|
||||
//////
|
||||
|
||||
function [31:0] multiplication (string round, logic [31:0] a, logic [31:0] b);
|
||||
bit [31:0] result;
|
||||
// Convert every denormal in zero
|
||||
if(a[30:23] == '0) a[22:0] = '0;
|
||||
if(b[30:23] == '0) b[22:0] = '0;
|
||||
if(a[30:23] == '1) a[22:0] = '0;
|
||||
if(b[30:23] == '1) b[22:0] = '0;
|
||||
|
||||
// If (a is inf or NaN) or (b is inf or NaN) => Result Inf
|
||||
if((a[30:23] == '1 && b[30:23] == '0) || (a[30:23] == '0 && b[30:23] == '1)) result = {1'b0, {8{1'b1}}, {23{1'b0}}};
|
||||
else begin
|
||||
result = $shortrealtobits($bitstoshortreal(a) * $bitstoshortreal(b));
|
||||
case (round)
|
||||
//IEEE_NEAR ROUNDING
|
||||
"IEEE_near": begin
|
||||
if(result[30:23] == '1) result[22:0] = '0;
|
||||
if(result[30:23] == '0) result[22:0] = '0;
|
||||
end
|
||||
//IEEE_ZERO ROUNDING
|
||||
"IEEE_zero": begin
|
||||
//Round towards zero instead if rounded up and positive
|
||||
if($bitstoshortreal(result) > ($bitstoshortreal(a) * $bitstoshortreal(b)))
|
||||
begin
|
||||
if($bitstoshortreal(result) > 0)
|
||||
begin
|
||||
result = result - 1;
|
||||
end
|
||||
end
|
||||
//Round towards zero instead if rounded down and negative
|
||||
if($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b)))
|
||||
begin
|
||||
if($bitstoshortreal(result) < 0)
|
||||
begin
|
||||
result = result - 1;
|
||||
end
|
||||
end
|
||||
if(result[30:23] == '0) result[22:0] = '0;
|
||||
end
|
||||
//AWAY_ZERO ROUNDING
|
||||
"away_zero": begin
|
||||
//Check if the result is denormal and round to minNormal
|
||||
if((result[30:23] == '0 && result[22:0] != '0) || (a[30:23] != '0 && b[30:23] != '0 && result[30:23] == '0 && result[22:0] == '0)) begin
|
||||
result = {result[31], {7{1'b0}}, 1'b1, {23{1'b0}}};
|
||||
end
|
||||
else begin
|
||||
//Round away from zero instead if rounded up and negative
|
||||
if($bitstoshortreal(result) > ($bitstoshortreal(a) * $bitstoshortreal(b)))
|
||||
begin
|
||||
if($bitstoshortreal(result) < 0)
|
||||
begin
|
||||
result = result + 1;
|
||||
end
|
||||
end
|
||||
//Round away from zero instead if rounded down and positive
|
||||
if($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b)))
|
||||
begin
|
||||
if($bitstoshortreal(result) > 0)
|
||||
begin
|
||||
result = result + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
if(result[30:23] == '1) result[22:0] = '0;
|
||||
end
|
||||
//IEEE_PINF ROUNDING
|
||||
"IEEE_pinf": begin
|
||||
//Check if the result is denormal and round to minNormal, but only for positives
|
||||
if((result[31] == 0 && result[30:23] == '0 && result[22:0] != '0) || (result[31] == 0 && a[30:23] != '0 && b[30:23] != '0 && result[30:23] == '0 && result[22:0] == '0)) begin
|
||||
result = {{8{1'b0}}, 1'b1, {23{1'b0}}};
|
||||
end
|
||||
else begin
|
||||
//Round towards positive infinity instead if rounded down and positive
|
||||
if($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b)))
|
||||
begin
|
||||
if($bitstoshortreal(result) > 0)
|
||||
begin
|
||||
result = result + 1;
|
||||
end
|
||||
end
|
||||
//Round towards positive infinity instead if rounded down and negative
|
||||
if($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b)))
|
||||
begin
|
||||
if($bitstoshortreal(result) < 0)
|
||||
begin
|
||||
result = result - 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
if(result[30:23] == '0) result[22:0] = '0;
|
||||
end
|
||||
//IEEE_NINF ROUNDING
|
||||
"IEEE_ninf": begin
|
||||
//Check if the result is denormal and round to minNormal, but only for negatives
|
||||
if((result[31] == 1 && result[30:23] == '0 && result[22:0] != '0) || (result[31] == 1 && a[30:23] != '0 && b[30:23] != '0 && result[30:23] == '0 && result[22:0] == '0)) begin
|
||||
result = {1'b1, {7{1'b0}}, 1'b1, {23{1'b0}}};
|
||||
end
|
||||
else begin
|
||||
//Round towards negative infinity instead if rounded up and positive
|
||||
if($bitstoshortreal(result) > ($bitstoshortreal(a) * $bitstoshortreal(b)))
|
||||
begin
|
||||
if($bitstoshortreal(result) > 0)
|
||||
begin
|
||||
result = result - 1;
|
||||
end
|
||||
end
|
||||
//Round towards negative infinity instead if rounded up and negative
|
||||
if($bitstoshortreal(result) > ($bitstoshortreal(a) * $bitstoshortreal(b)))
|
||||
begin
|
||||
if($bitstoshortreal(result) < 0)
|
||||
begin
|
||||
result = result + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
if(result[30:23] == '0) result[22:0] = '0;
|
||||
end
|
||||
//NEAR_UP ROUNDING
|
||||
"near_up": begin
|
||||
//Round towards positive infinity if rounded down, negative and in the middle
|
||||
if(($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b))))
|
||||
begin
|
||||
if(($bitstoshortreal(result) - ($bitstoshortreal(a) * $bitstoshortreal(b))) == (($bitstoshortreal(a) * $bitstoshortreal(b)) - $bitstoshortreal(result-1)))
|
||||
begin
|
||||
if($bitstoshortreal(result) < 0)
|
||||
begin
|
||||
result = result - 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
//Round towards positive infinity if rounded down, positive and in the middle
|
||||
if(($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b))))
|
||||
begin
|
||||
if(($bitstoshortreal(result+1) - ($bitstoshortreal(a) * $bitstoshortreal(b))) == (($bitstoshortreal(a) * $bitstoshortreal(b)) - $bitstoshortreal(result)))
|
||||
begin
|
||||
if($bitstoshortreal(result) > 0)
|
||||
begin
|
||||
result = result + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if(result[30:23] == '1) result[22:0] = '0;
|
||||
if(result[30:23] == '0) result[22:0] = '0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module normalize_mult_tb;
|
||||
|
||||
logic [47:0] mantissa_in;
|
||||
logic [9:0] exponent_in;
|
||||
logic [22:0] mantissa_out;
|
||||
logic [9:0] exponent_out;
|
||||
logic guard_bit, sticky_bit;
|
||||
|
||||
normalize_mult dut (
|
||||
.mantissa_in(mantissa_in),
|
||||
.exponent_in(exponent_in),
|
||||
.mantissa_out(mantissa_out),
|
||||
.exponent_out(exponent_out),
|
||||
.guard_bit(guard_bit),
|
||||
.sticky_bit(sticky_bit)
|
||||
);
|
||||
|
||||
initial begin
|
||||
|
||||
integer i;
|
||||
logic [47:0] mantissa_inputs [13];
|
||||
logic [9:0] exponent_inputs [13];
|
||||
logic [22:0] exp_mantissas [13];
|
||||
logic [9:0] exp_exponents [13];
|
||||
string exp_grs [13];
|
||||
|
||||
$display("Starting normalize_mult test...\n");
|
||||
|
||||
mantissa_inputs[0] = 48'h800000000000; exponent_inputs[0] = 130; exp_mantissas[0] = 23'h400000; exp_exponents[0] = 131; exp_grs[0] = "0,0";
|
||||
mantissa_inputs[1] = 48'h400000000000; exponent_inputs[1] = 130; exp_mantissas[1] = 23'h400000; exp_exponents[1] = 130; exp_grs[1] = "0,0";
|
||||
mantissa_inputs[2] = 48'h200000000000; exponent_inputs[2] = 130; exp_mantissas[2] = 23'h400000; exp_exponents[2] = 129; exp_grs[2] = "0,0";
|
||||
mantissa_inputs[3] = 48'h000040000000; exponent_inputs[3] = 130; exp_mantissas[3] = 23'h400000; exp_exponents[3] = 114; exp_grs[3] = "0,0";
|
||||
mantissa_inputs[4] = 48'h000000000F00; exponent_inputs[4] = 130; exp_mantissas[4] = 23'h780000; exp_exponents[4] = 95; exp_grs[4] = "0,0";
|
||||
mantissa_inputs[5] = 48'h000000000000; exponent_inputs[5] = 130; exp_mantissas[5] = 23'h000000; exp_exponents[5] = 130; exp_grs[5] = "0,0";
|
||||
mantissa_inputs[6] = 48'h400000000080; exponent_inputs[6] = 130; exp_mantissas[6] = 23'h400000; exp_exponents[6] = 130; exp_grs[6] = "0,1";
|
||||
mantissa_inputs[7] = 48'h4000000000C0; exponent_inputs[7] = 130; exp_mantissas[7] = 23'h400000; exp_exponents[7] = 130; exp_grs[7] = "0,1";
|
||||
mantissa_inputs[8] = 48'h400000000089; exponent_inputs[8] = 130; exp_mantissas[8] = 23'h400000; exp_exponents[8] = 130; exp_grs[8] = "0,1";
|
||||
mantissa_inputs[9] = 48'h4000000000FF; exponent_inputs[9] = 130; exp_mantissas[9] = 23'h400000; exp_exponents[9] = 130; exp_grs[9] = "0,1";
|
||||
mantissa_inputs[10]= 48'h400000800000; exponent_inputs[10]= 130; exp_mantissas[10]=23'h400000; exp_exponents[10]=130; exp_grs[10]= "1,0";
|
||||
mantissa_inputs[11]= 48'h400000C00000; exponent_inputs[11]= 130; exp_mantissas[11]=23'h400000; exp_exponents[11]=130; exp_grs[11]= "1,1";
|
||||
mantissa_inputs[12]= 48'h800000000001; exponent_inputs[12]= 130; exp_mantissas[12]=23'h400000; exp_exponents[12]=131; exp_grs[12]= "0,1";
|
||||
|
||||
for (i = 0; i < 13; i++) begin
|
||||
mantissa_in = mantissa_inputs[i];
|
||||
exponent_in = exponent_inputs[i];
|
||||
|
||||
#10;
|
||||
$display("[%0d] IN=%h | EXPECTED: OUT=%h EXP=%0d (G,S)=(%s) | OUT=%h EXP=%0d (G,S)=(%b,%b)",
|
||||
i+1,
|
||||
mantissa_in,
|
||||
exp_mantissas[i],
|
||||
exp_exponents[i],
|
||||
exp_grs[i],
|
||||
mantissa_out,
|
||||
exponent_out,
|
||||
guard_bit, sticky_bit
|
||||
);
|
||||
end
|
||||
|
||||
$display("\nFinished normalize_mult test.");
|
||||
$stop;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module round_mult_tb;
|
||||
|
||||
logic [22:0] mantissa_in;
|
||||
logic [7:0] exponent_in;
|
||||
logic guard_bit, round_bit, sticky_bit;
|
||||
logic [22:0] mantissa_out;
|
||||
logic [7:0] exponent_out;
|
||||
|
||||
round_mult dut (
|
||||
.mantissa_in(mantissa_in),
|
||||
.exponent_in(exponent_in),
|
||||
.guard_bit(guard_bit),
|
||||
.round_bit(round_bit),
|
||||
.sticky_bit(sticky_bit),
|
||||
.mantissa_out(mantissa_out),
|
||||
.exponent_out(exponent_out)
|
||||
);
|
||||
|
||||
initial begin
|
||||
integer i;
|
||||
|
||||
logic [22:0] mant_in [10];
|
||||
logic [7:0] exp_in [10];
|
||||
logic g_bit [10];
|
||||
logic r_bit [10];
|
||||
logic s_bit [10];
|
||||
logic [22:0] expected_m [10];
|
||||
logic [7:0] expected_e [10];
|
||||
string notes [10];
|
||||
|
||||
$display("Starting round_mult test...\n");
|
||||
|
||||
mant_in[0] = 23'h400000; exp_in[0] = 8'd100; g_bit[0] = 1; r_bit[0] = 0; s_bit[0] = 0; expected_m[0] = 23'h400000; expected_e[0] = 8'd100; notes[0] = "Tie: do not round (even)";
|
||||
mant_in[1] = 23'h400001; exp_in[1] = 8'd100; g_bit[1] = 1; r_bit[1] = 0; s_bit[1] = 0; expected_m[1] = 23'h400002; expected_e[1] = 8'd100; notes[1] = "Round up (tie ? odd LSB)";
|
||||
mant_in[2] = 23'h400000; exp_in[2] = 8'd100; g_bit[2] = 1; r_bit[2] = 1; s_bit[2] = 0; expected_m[2] = 23'h400001; expected_e[2] = 8'd100; notes[2] = "Round up (guard + round)";
|
||||
mant_in[3] = 23'h400000; exp_in[3] = 8'd100; g_bit[3] = 1; r_bit[3] = 0; s_bit[3] = 1; expected_m[3] = 23'h400001; expected_e[3] = 8'd100; notes[3] = "Round up (guard + sticky)";
|
||||
mant_in[4] = 23'h7FFFFF; exp_in[4] = 8'd100; g_bit[4] = 1; r_bit[4] = 1; s_bit[4] = 1; expected_m[4] = 23'h400000; expected_e[4] = 8'd101; notes[4] = "Overflow during rounding";
|
||||
mant_in[5] = 23'h123456; exp_in[5] = 8'd90; g_bit[5] = 0; r_bit[5] = 0; s_bit[5] = 0; expected_m[5] = 23'h123456; expected_e[5] = 8'd90; notes[5] = "No rounding";
|
||||
mant_in[6] = 23'h123456; exp_in[6] = 8'd90; g_bit[6] = 1; r_bit[6] = 0; s_bit[6] = 0; expected_m[6] = 23'h123456; expected_e[6] = 8'd90; notes[6] = "Guard only, no round";
|
||||
mant_in[7] = 23'h123456; exp_in[7] = 8'd90; g_bit[7] = 1; r_bit[7] = 1; s_bit[7] = 0; expected_m[7] = 23'h123457; expected_e[7] = 8'd90; notes[7] = "Guard + Round";
|
||||
mant_in[8] = 23'h123456; exp_in[8] = 8'd90; g_bit[8] = 1; r_bit[8] = 0; s_bit[8] = 1; expected_m[8] = 23'h123457; expected_e[8] = 8'd90; notes[8] = "Guard + Sticky";
|
||||
mant_in[9] = 23'h123456; exp_in[9] = 8'd90; g_bit[9] = 1; r_bit[9] = 1; s_bit[9] = 1; expected_m[9] = 23'h123457; expected_e[9] = 8'd90; notes[9] = "Guard + Round + Sticky";
|
||||
|
||||
for (i = 0; i < 10; i++) begin
|
||||
mantissa_in = mant_in[i];
|
||||
exponent_in = exp_in[i];
|
||||
guard_bit = g_bit[i];
|
||||
round_bit = r_bit[i];
|
||||
sticky_bit = s_bit[i];
|
||||
|
||||
#10;
|
||||
$display("[%0d] %s\n IN: mant=%h, exp=%0d, GRS=%b%b%b\n OUT: mant=%h, exp=%0d (expected: mant=%h, exp=%0d)\n",
|
||||
i+1, notes[i],
|
||||
mantissa_in, exponent_in, guard_bit, round_bit, sticky_bit,
|
||||
mantissa_out, exponent_out,
|
||||
expected_m[i], expected_e[i]
|
||||
);
|
||||
end
|
||||
|
||||
$display("Finished round_mult test.");
|
||||
$stop;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user