Init commit

This commit is contained in:
Christos Choutouridis 2025-06-09 22:46:39 +03:00
commit 082990ceae
15 changed files with 3148 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
# vsim related
work/*
*.bak
*.wlf
*mti

Binary file not shown.

View 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

View 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
View 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

File diff suppressed because it is too large Load Diff

BIN
lab_coursework_2025.pdf Executable file

Binary file not shown.

71
sim/fp_mult_tb.sv Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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