My plan is to design a 32 bit floating point multiplier from scratch. I am still an undergrad with very beginner understanding in computer architecture, Verilog/VHDL and digital circuits/design.
Here's what I have understood so far,
I started to understand how floating point numbers are denoted in IEEE standards (754), then I saw how are floating point numbers multiplied.
Let's keep it simple and ignore that there are several cases required to be understood regarding subnormals, normals, infinities, zeroes, NaN, SNaNs and QNaNs.
Clearly, when multiplying two 32-bit floating numbers, I'll have two exponents, mantissa and significands to worry about.
So, I'm clear about the big picture here, that I'll require modules for normalization, overflow checks, sign checks, truncation checks, lot more and mainly the multiplication itself.
My questions are;
How do I implement that "multiplication itself" module, from what I understood of floating point multiplication is, its effectively just adders placed in parallel to add bitwise XOR's, so how do I implement this in verilog
The actual objective is to achieve a low power design, so clearly my plans are to optimize the adders by replacing with some alternate adder designs, in hopes that I end up reducing power.
Am I roughly on the right track? I can't seem to learn how to make a floating point multiplier anywhere, it'll be great if I'm recommended some good resources to learn the entire thing and make one myself.
EDIT : Here's the verilog I have managed upto,
module sign_unit(input wire sign_a,input wire sign_b,output wire sign_result);
assign sign_result = sign_a^sign_b;
endmodule
module exponent_adder(input wire [7:0] exp_a, input wire [7:0] exp_b, output wire [7:0] exp_result, output wire overflow,output wire underflow);
wire [8:0] exp_sum;
assign exp_sum = exp_a + exp_b - 8'd127;
assign exp_result = exp_sum[7:0];
assign overflow = (exp_sum > 8'd254);
assign underflow = (exp_sum < 8'd1);
endmodule
module mantissa_multiplier(input wire [23:0] mant_a, input wire [23:0] mant_b, output wire [47:0] product);
assign product = mant_a * mant_b;
endmodule
module normalizer(input wire [47:0] in_product, output reg [22:0] norm_mantissa, output reg [7:0] exp_adjust);
integer i;
reg found;
always @(*) begin
exp_adjust = 0;
found = 0;
norm_mantissa = in_product[46:24];
if (in_product[47] == 1'b1) begin
norm_mantissa = in_product[46:24];
exp_adjust = 1;
end else begin
for (i = 46; i >= 24; i = i - 1) begin
if (!found && in_product[i] == 1'b1) begin
norm_mantissa = in_product[i-1 -: 23];
exp_adjust = -(46 - i);
found = 1;
end
end
end
end
endmodule
module rounder(input wire [22:0] in_mantissa, input wire guard, input wire round, input wire sticky, output wire [22:0] out_mantissa, output wire carry);
wire round_up;
assign round_up = guard & (round | sticky | in_mantissa[0]);
assign {carry, out_mantissa} = in_mantissa + round_up;
endmodule
module fp32_multiplier(input wire [31:0] a,input wire [31:0] b,output wire [31:0] result);
wire sign_a = a[31];
wire sign_b = b[31];
wire [7:0] exp_a = a[30:23];
wire [7:0] exp_b = b[30:23];
wire [23:0] mant_a = {1'b1, a[22:0]};
wire [23:0] mant_b = {1'b1, b[22:0]};
wire sign_res;
wire [7:0] exp_res_pre;
wire overflow, underflow;
wire [47:0] raw_product;
wire [22:0] norm_mant;
wire [7:0] exp_adjust;
wire [22:0] rounded_mant;
wire carry;
sign_unit su(sign_a, sign_b, sign_res);
exponent_adder ea(exp_a, exp_b, exp_res_pre, overflow, underflow);
mantissa_multiplier mm(mant_a, mant_b, raw_product);
normalizer norm(raw_product, norm_mant, exp_adjust);
rounder rnd(norm_mant, raw_product[23], raw_product[22], |raw_product[21:0], rounded_mant, carry);
wire [7:0] final_exp = exp_res_pre + exp_adjust + carry;
assign result = {sign_res, final_exp, rounded_mant};
endmodule