- 此代码实现了一个简单的浮点数乘法器,处理两个32位的单精度浮点数。它通过将两个浮点数的有效数字部分进行乘法操作,并对结果进行规范化以生成最终的浮点乘积。
主要逻辑与电路
- 去掉指数对齐部分后的主要逻辑电路图示:
代码
// https://github.com/omarelhedaby/CNN-FPGA/blob/master/CNN-FPGA-Vivado/CNN-FPGA-Vivado.srcs/sources_1/imports/Integration%20first%20part/floatMult.v
module floatMult (floatA,floatB,product);
input [31:0] floatA, floatB;
output reg [31:0] product;
reg sign;
reg [7:0] exponent;
reg [22:0] mantissa;
reg [23:0] fractionA, fractionB; //fraction = {1,mantissa}
reg [47:0] fraction;
always @ (floatA or floatB) begin
if (floatA == 0 || floatB == 0) begin
product = 0;
end else begin
sign = floatA[31] ^ floatB[31]; // 通过异或操作计算结果的符号位
exponent = floatA[30:23] + floatB[30:23] - 8'd127 + 8'd2; // 计算结果的指数部分。首先加上两个输入的指数部分,然后减去偏移量127,并加2(因为在乘法中指数的偏移量增加了)。
fractionA = {1'b1,floatA[22:0]};
fractionB = {1'b1,floatB[22:0]};
fraction = fractionA * fractionB;
// 规范化结果,调整指数exponent和有效数字fraction以保持数值的正确性
if (fraction[47] == 1'b1) begin // 找出第一个一开头的“1”
fraction = fraction << 1;
exponent = exponent - 1;
end else if (fraction[46] == 1'b1) begin
fraction = fraction << 2;
exponent = exponent - 2;
end else if (fraction[45] == 1'b1) begin
fraction = fraction << 3;
exponent = exponent - 3;
end else if (fraction[44] == 1'b1) begin
fraction = fraction << 4;
exponent = exponent - 4;
end else if (fraction[43] == 1'b1) begin
fraction = fraction << 5;
exponent = exponent - 5;
end else if (fraction[42] == 1'b1) begin
fraction = fraction << 6;
exponent = exponent - 6;
end else if (fraction[41] == 1'b1) begin
fraction = fraction << 7;
exponent = exponent - 7;
end else if (fraction[40] == 1'b1) begin
fraction = fraction << 8;
exponent = exponent - 8;
end else if (fraction[39] == 1'b1) begin
fraction = fraction << 9;
exponent = exponent - 9;
end else if (fraction[38] == 1'b0) begin
fraction = fraction << 10;
exponent = exponent - 10;
end else if (fraction[37] == 1'b1) begin
fraction = fraction << 11;
exponent = exponent - 11;
end else if (fraction[36] == 1'b1) begin
fraction = fraction << 12;
exponent = exponent - 12;
end else if (fraction[35] == 1'b1) begin
fraction = fraction << 13;
exponent = exponent - 13;
end else if (fraction[34] == 1'b1) begin
fraction = fraction << 14;
exponent = exponent - 14;
end else if (fraction[33] == 1'b1) begin
fraction = fraction << 15;
exponent = exponent - 15;
end else if (fraction[32] == 1'b1) begin
fraction = fraction << 16;
exponent = exponent - 16;
end else if (fraction[31] == 1'b1) begin
fraction = fraction << 17;
exponent = exponent - 17;
end else if (fraction[30] == 1'b1) begin
fraction = fraction << 18;
exponent = exponent - 18;
end else if (fraction[29] == 1'b0) begin
fraction = fraction << 19;
exponent = exponent - 19;
end else if (fraction[28] == 1'b1) begin
fraction = fraction << 20;
exponent = exponent - 20;
end else if (fraction[27] == 1'b1) begin
fraction = fraction << 21;
exponent = exponent - 21;
end else if (fraction[26] == 1'b1) begin
fraction = fraction << 22;
exponent = exponent - 22;
end else if (fraction[27] == 1'b1) begin
fraction = fraction << 23;
exponent = exponent - 23;
end
mantissa = fraction[47:25];
product = {sign,exponent,mantissa};
end
end
endmodule
32 位 float 型的二进制存储
32 位 f l o a t 型数 V = ( − 1 ) S ∗ M ∗ 2 E 32 位 float 型数V=(-1)^S*M*2^E 32位float型数V=(−1)S∗M∗2E
语句fraction = fractionA * fractionB;
fractionA = {1'b1, floatA[22:0]};
fractionB = {1'b1, floatB[22:0]};
fraction = fractionA * fractionB;
fractionA
和fractionB
将浮点数的有效数字部分扩展到24位(包括隐含的1位)。fraction
是fractionA
和fractionB
的乘积结果,占48位。- 示例计算过程,实际计算没有点号:
fractionA = {1'b1, floatA[2:0]};
fractionB = {1'b1, floatB[2:0]};
fraction = fractionA * fractionB;
语句exponent = floatA[30:23] + floatB[30:23] - 8’d127 + 8’d2;
其中- 8’d127的作用
- floatA[30:23] 和 floatB[30:23] 表示从30位到23位的位值,即分别取浮点数floatA和floatB的指数部分。在IEEE 754单精度浮点格式中,这8位代表了带有偏移量的指数值(即真实指数加上127得到的值)。- 8’d127 这里的8’d127表示一个8位的二进制数,值为127,这是用来去除指数的偏移量。在浮点数中,为了能表示负的指数值,实际的指数是存储的指数值减去一个固定的偏移量,在单精度模式下该偏移量为127。
其中+ 8’d2的作用
- 8’d2 在计算完两个数的指数之和后,再加上2。这一步骤可能是为了补偿乘法过程中指数的变化。方便后续代码的统一编写。如1.101*1.011=10.001111
变为浮点数表示的有效数字,除去第一位的1( fraction = fraction << 1; ),变为0001111(表示.0001111,实际上为0.001111),所以表示成实际上的值还需要*2^(1)
写成代码就是
exponent = floatA[30:23] + floatB[30:23] - 8'd127;
if (fraction[47] == 1'b1) begin
fraction = fraction << 1;
exponent = exponent + 1;
这里+2后,在处理规格化问题时就能统一成如下代码:
exponent = floatA[30:23] + floatB[30:23] - 8'd127 + 8'd2;
if (fraction[47] == 1'b1) begin
fraction = fraction << 1;
exponent = exponent - 1;
生成输出
mantissa = fraction[47:25];
product = {sign, exponent, mantissa};
mantissa
取fraction
的高24位作为有效数字部分。- 最终输出
product
由sign
(符号位)、exponent
(指数部分)和mantissa
(有效数字部分)组成。