Init commit
This commit is contained in:
commit
082990ceae
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# vsim related
|
||||
work/*
|
||||
*.bak
|
||||
*.wlf
|
||||
*mti
|
||||
|
BIN
Compulsory coursework-2025-20250609/IEEE_754-2019.pdf
Normal file
BIN
Compulsory coursework-2025-20250609/IEEE_754-2019.pdf
Normal file
Binary file not shown.
37
Compulsory coursework-2025-20250609/fp_mult_top.sv
Normal file
37
Compulsory coursework-2025-20250609/fp_mult_top.sv
Normal file
@ -0,0 +1,37 @@
|
||||
//This module is given for the exercises
|
||||
module fp_mult_top (
|
||||
clk, rst, rnd, a, b, z, status
|
||||
);
|
||||
|
||||
input logic [31:0] a, b; // Floating-Point numbers
|
||||
input logic [2:0] rnd; // Rounding signal
|
||||
output logic [31:0] z; // a ± b
|
||||
output logic [7:0] status; // Status Flags
|
||||
input logic clk, rst;
|
||||
|
||||
logic [31:0] a1, b1; // Floating-Point numbers
|
||||
logic [2:0] rnd1; // Rounding signal
|
||||
logic [31:0] z1; // a ± b
|
||||
logic [7:0] status1; // Status Flags
|
||||
|
||||
fp_mult multiplier(a1,b1,rnd1,z1,status1,clk,rst);
|
||||
|
||||
always @(posedge clk)
|
||||
if (!rst)
|
||||
begin
|
||||
a1 <= '0;
|
||||
b1 <= '0;
|
||||
rnd1 <= '0;
|
||||
z <= '0;
|
||||
status <= '0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
a1 <= a;
|
||||
b1 <= b;
|
||||
rnd1 <= rnd;
|
||||
z <= z1;
|
||||
status <= status1;
|
||||
end
|
||||
|
||||
endmodule
|
BIN
Compulsory coursework-2025-20250609/lab_coursework_2025.pdf
Normal file
BIN
Compulsory coursework-2025-20250609/lab_coursework_2025.pdf
Normal file
Binary file not shown.
155
Compulsory coursework-2025-20250609/multiplication.sv
Normal file
155
Compulsory coursework-2025-20250609/multiplication.sv
Normal file
@ -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
|
||||
|
37
fp_mult_top.sv
Normal file
37
fp_mult_top.sv
Normal file
@ -0,0 +1,37 @@
|
||||
//This module is given for the exercises
|
||||
module fp_mult_top (
|
||||
clk, rst, rnd, a, b, z, status
|
||||
);
|
||||
|
||||
input logic [31:0] a, b; // Floating-Point numbers
|
||||
input logic [2:0] rnd; // Rounding signal
|
||||
output logic [31:0] z; // a ± b
|
||||
output logic [7:0] status; // Status Flags
|
||||
input logic clk, rst;
|
||||
|
||||
logic [31:0] a1, b1; // Floating-Point numbers
|
||||
logic [2:0] rnd1; // Rounding signal
|
||||
logic [31:0] z1; // a ± b
|
||||
logic [7:0] status1; // Status Flags
|
||||
|
||||
fp_mult multiplier(a1,b1,rnd1,z1,status1,clk,rst);
|
||||
|
||||
always @(posedge clk)
|
||||
if (!rst)
|
||||
begin
|
||||
a1 <= '0;
|
||||
b1 <= '0;
|
||||
rnd1 <= '0;
|
||||
z <= '0;
|
||||
status <= '0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
a1 <= a;
|
||||
b1 <= b;
|
||||
rnd1 <= rnd;
|
||||
z <= z1;
|
||||
status <= status1;
|
||||
end
|
||||
|
||||
endmodule
|
2374
fpu_mult.mpf
Normal file
2374
fpu_mult.mpf
Normal file
File diff suppressed because it is too large
Load Diff
BIN
lab_coursework_2025.pdf
Executable file
BIN
lab_coursework_2025.pdf
Executable file
Binary file not shown.
71
sim/fp_mult_tb.sv
Normal file
71
sim/fp_mult_tb.sv
Normal file
@ -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
|
||||
|
155
sim/multiplication.sv
Normal file
155
sim/multiplication.sv
Normal file
@ -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
|
||||
|
67
sim/normalize_mult_tb.sv
Normal file
67
sim/normalize_mult_tb.sv
Normal file
@ -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
|
||||
|
67
sim/round_mult_tb.sv
Normal file
67
sim/round_mult_tb.sv
Normal file
@ -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
|
||||
|
87
src/fp_mult.sv
Normal file
87
src/fp_mult.sv
Normal file
@ -0,0 +1,87 @@
|
||||
// fp_mult.sv
|
||||
// Floating-Point Multiplier Core (IEEE-754 single precision)
|
||||
|
||||
module fp_mult (
|
||||
input logic [31:0] a, // input operand A
|
||||
input logic [31:0] b, // input operand B
|
||||
input logic [2:0] rnd, // rounding mode
|
||||
output logic [31:0] z, // result
|
||||
output logic [7:0] status, // status flags (placeholder)
|
||||
input logic clk,
|
||||
input logic rst
|
||||
);
|
||||
|
||||
// === STEP 0: Parse inputs
|
||||
logic sign_a, sign_b;
|
||||
logic [7:0] exp_a, exp_b;
|
||||
logic [23:0] mant_a, mant_b; // includes hidden bit
|
||||
|
||||
always_comb begin
|
||||
sign_a = a[31];
|
||||
sign_b = b[31];
|
||||
exp_a = a[30:23];
|
||||
exp_b = b[30:23];
|
||||
mant_a = (exp_a == 8'd0) ? {1'b0, a[22:0]} : {1'b1, a[22:0]};
|
||||
mant_b = (exp_b == 8'd0) ? {1'b0, b[22:0]} : {1'b1, b[22:0]};
|
||||
// ^ Add hiden leading '1' on normalized numbers
|
||||
// This will lead to always 24-bits mantissa internal representation
|
||||
// for multiplication
|
||||
end
|
||||
|
||||
// === STEP 1: Floating point number sign calculation
|
||||
logic sign_res;
|
||||
assign sign_res = sign_a ^ sign_b;
|
||||
|
||||
// === STEP 2,3. Exponent addition, Exponent subtraction of bias
|
||||
logic [9:0] exp_sum;
|
||||
always_comb begin
|
||||
exp_sum = exp_a + exp_b - 127; // apply bias
|
||||
end
|
||||
|
||||
// === STEP 4: Mantissa multiplication (including leading ones)
|
||||
logic [47:0] mant_prod;
|
||||
always_comb begin
|
||||
mant_prod = mant_a * mant_b;
|
||||
end
|
||||
|
||||
// === STEP 5: Truncation and normalization
|
||||
logic [22:0] mant_norm;
|
||||
logic [9:0] exp_norm;
|
||||
logic guard, sticky;
|
||||
|
||||
normalize_mult norm_inst (
|
||||
.mantissa_in(mant_prod),
|
||||
.exponent_in(exp_sum),
|
||||
.mantissa_out(mant_norm),
|
||||
.exponent_out(exp_norm),
|
||||
.guard_bit(guard),
|
||||
.sticky_bit(sticky)
|
||||
);
|
||||
|
||||
// === STEP 6: Pipeline stage
|
||||
|
||||
// === STEP 7: Rounding
|
||||
logic [22:0] mant_rounded;
|
||||
logic [7:0] exp_rounded;
|
||||
|
||||
round_mult round_inst (
|
||||
.mantissa_in(mant_norm),
|
||||
.exponent_in(exp_norm),
|
||||
.guard_bit(guard),
|
||||
.round_bit(round),
|
||||
.sticky_bit(sticky),
|
||||
.rnd(rnd),
|
||||
.mantissa_out(mant_rounded),
|
||||
.exponent_out(exp_rounded)
|
||||
);
|
||||
|
||||
// === STEP 8: Exception handling
|
||||
|
||||
|
||||
assign z = {sign_res, exp_rounded, mant_rounded};
|
||||
|
||||
// === STEP 6: Status flags (placeholder) ===
|
||||
assign status = 8'b00000000;
|
||||
|
||||
endmodule
|
||||
|
52
src/normalize_mult.sv
Normal file
52
src/normalize_mult.sv
Normal file
@ -0,0 +1,52 @@
|
||||
// normalize_mult.sv
|
||||
// This module normalizes a 48-bit mantissa product and adjusts the exponent accordingly.
|
||||
// It also extracts the guard and sticky bits for IEEE-754 rounding.
|
||||
|
||||
module normalize_mult (
|
||||
input logic [47:0] mantissa_in, // Input mantissa (product of 24-bit x 24-bit)
|
||||
input logic [9:0] exponent_in, // Input exponent (after bias adjustment)
|
||||
output logic [22:0] mantissa_out, // Normalized 23-bit mantissa
|
||||
output logic [9:0] exponent_out, // Adjusted exponent after normalization
|
||||
output logic guard_bit, // Guard bit for rounding
|
||||
output logic sticky_bit // Sticky bit for rounding
|
||||
);
|
||||
|
||||
logic [47:0] mant_shifted;
|
||||
logic [5:0] shift_amount;
|
||||
logic [9:0] exponent_adj;
|
||||
logic sticky;
|
||||
|
||||
always_comb begin
|
||||
// Default assignments
|
||||
shift_amount = 0;
|
||||
mant_shifted = mantissa_in;
|
||||
exponent_adj = exponent_in;
|
||||
|
||||
if (mantissa_in[47] == 1'b1) begin
|
||||
// Overflow: shift right by 1 and increment exponent
|
||||
mant_shifted = mantissa_in >> 1;
|
||||
exponent_adj = exponent_in + 1;
|
||||
sticky = mantissa_in[0];
|
||||
end
|
||||
else begin
|
||||
// Normalize: shift left until MSB '1' is at bit 46
|
||||
for (int i = 0; i <= 46; i++) begin
|
||||
if (mantissa_in[46 - i] == 1'b1) begin
|
||||
shift_amount = i;
|
||||
break;
|
||||
end
|
||||
end
|
||||
mant_shifted = mantissa_in << shift_amount;
|
||||
exponent_adj = exponent_in - shift_amount;
|
||||
sticky = | mant_shifted[22:0]; // Sticky bit = OR of remaining bits
|
||||
end
|
||||
|
||||
// Extract normalized mantissa and rounding bits
|
||||
mantissa_out = mant_shifted[46:24]; // Correct 23-bit mantissa
|
||||
exponent_out = exponent_adj;
|
||||
guard_bit = mant_shifted[23]; // Guard bit
|
||||
sticky_bit = sticky;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
40
src/round_mult.sv
Normal file
40
src/round_mult.sv
Normal file
@ -0,0 +1,40 @@
|
||||
// round_mult.sv
|
||||
// Rounds a normalized mantissa using GRS bits (round to nearest, ties to even)
|
||||
|
||||
module round_mult (
|
||||
input logic [22:0] mantissa_in, // Input mantissa (no implicit bit)
|
||||
input logic [7:0] exponent_in, // Input exponent
|
||||
input logic guard_bit,
|
||||
input logic round_bit,
|
||||
input logic sticky_bit,
|
||||
output logic [22:0] mantissa_out, // Rounded mantissa
|
||||
output logic [7:0] exponent_out // Adjusted exponent (if mantissa overflows)
|
||||
);
|
||||
|
||||
logic round_up;
|
||||
logic [23:0] mantissa_extended;
|
||||
logic [23:0] mantissa_rounded;
|
||||
|
||||
always_comb begin
|
||||
// Concatenate implicit '1' at MSB
|
||||
mantissa_extended = {1'b0, mantissa_in};
|
||||
|
||||
// Round to nearest, ties to even
|
||||
round_up = 0;
|
||||
if (guard_bit && (round_bit || sticky_bit || mantissa_in[0])) begin
|
||||
round_up = 1;
|
||||
end
|
||||
|
||||
mantissa_rounded = mantissa_extended + round_up;
|
||||
|
||||
if (mantissa_rounded[23]) begin
|
||||
// Overflow in rounding ? shift right and increment exponent
|
||||
mantissa_out = mantissa_rounded[23:1];
|
||||
exponent_out = exponent_in + 1;
|
||||
end else begin
|
||||
mantissa_out = mantissa_rounded[22:0];
|
||||
exponent_out = exponent_in;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
x
Reference in New Issue
Block a user