根本原理式:
X = X S ⋅ 2 X E Y = Y S ⋅ 2 Y E X ⋅ Y = ( X S ∗ Y S ) ⋅ 2 X E + Y E X = X_{S} · 2^{X_{E}} \\ Y = Y_{S} · 2^{Y_{E}} \\ X·Y = (X_{S}*Y_{S}) · 2^{X_{E} + Y_{E}} X=XS⋅2XEY=YS⋅2YEX⋅Y=(XS∗YS)⋅2XE+YE
基本流程:
判符号。
算尾数:结果的尾数是输入两数的尾数之积。(未标准化)
算指数:结果的指数是输入两数的指数之和。(未标准化)
标准化和舍位:
① 结果化为二级制(1.xx)的形式,取出尾数。
② 舍去低位,保留高位。
完整代码:
`timescale 100 ns / 10 ps
module floatMult16 (floatA,floatB,product);
input [15:0] floatA, floatB;
output reg [15:0] product;
reg sign;
reg signed [5:0] exponent; //6th bit is the sign
reg [9:0] mantissa;
reg [10:0] fractionA, fractionB; //fraction = {1,mantissa}
reg [21:0] fraction;
always @ (floatA or floatB) begin
if (floatA == 0 || floatB == 0) begin
product = 0;
end else begin
sign = floatA[15] ^ floatB[15];
exponent = floatA[14:10] + floatB[14:10] - 5'd15 + 5'd2;
fractionA = {1'b1,floatA[9:0]};
fractionB = {1'b1,floatB[9:0]};
fraction = fractionA * fractionB;
if (fraction[21] == 1'b1) begin
fraction = fraction << 1;
exponent = exponent - 1;
end else if (fraction[20] == 1'b1) begin
fraction = fraction << 2;
exponent = exponent - 2;
end else if (fraction[19] == 1'b1) begin
fraction = fraction << 3;
exponent = exponent - 3;
end else if (fraction[18] == 1'b1) begin
fraction = fraction << 4;
exponent = exponent - 4;
end else if (fraction[17] == 1'b1) begin
fraction = fraction << 5;
exponent = exponent - 5;
end else if (fraction[16] == 1'b1) begin
fraction = fraction << 6;
exponent = exponent - 6;
end else if (fraction[15] == 1'b1) begin
fraction = fraction << 7;
exponent = exponent - 7;
end else if (fraction[14] == 1'b1) begin
fraction = fraction << 8;
exponent = exponent - 8;
end else if (fraction[13] == 1'b1) begin
fraction = fraction << 9;
exponent = exponent - 9;
end else if (fraction[12] == 1'b0) begin
fraction = fraction << 10;
exponent = exponent - 10;
end
mantissa = fraction[21:12];
if(exponent[5]==1'b1) begin //exponent is negative
product=16'b0000000000000000;
end
else begin
product = {sign,exponent[4:0],mantissa};
end
end
end
endmodule
正正得正,负负得正,正负得负。用异或运算即可。
sign = floatA[15] ^ floatB[15];
floatA与floatB的指数相加,初步得到了乘法结果的指数(尚未标准化)。
exponent = floatA[14:10] + floatB[14:10] - 5'd15 + 5'd2;
floatA与floatB的尾数相乘,初步得到了乘法结果的尾数(尚未标准化)。
//输入的两个浮点数A,B都是标准的。把整数1先借回去,以便参与运算。
fractionA = {1'b1,floatA[9:0]};
fractionB = {1'b1,floatB[9:0]};
//尾数相乘
fraction = fractionA * fractionB;
通过小数点的移动,将运算结果变为二进制(1.xx)的形式。尾数即取小数点后(xx)的部分。同时,在这个过程中"指数"要同步发生变化。
代码的思路是:
从乘法结果尾数的高位开始,寻找到最高位的1。通过左移,将"这一位"变为最高位。
半精度浮点数尾数位只取5位。舍去低位。
标准化:
if (fraction[21] == 1'b1) begin
fraction = fraction << 1;
exponent = exponent - 1;
end else if (fraction[20] == 1'b1) begin
fraction = fraction << 2;
exponent = exponent - 2;
end else if (fraction[19] == 1'b1) begin
fraction = fraction << 3;
exponent = exponent - 3;
end else if (fraction[18] == 1'b1) begin
fraction = fraction << 4;
exponent = exponent - 4;
end else if (fraction[17] == 1'b1) begin
fraction = fraction << 5;
exponent = exponent - 5;
end else if (fraction[16] == 1'b1) begin
fraction = fraction << 6;
exponent = exponent - 6;
end else if (fraction[15] == 1'b1) begin
fraction = fraction << 7;
exponent = exponent - 7;
end else if (fraction[14] == 1'b1) begin
fraction = fraction << 8;
exponent = exponent - 8;
end else if (fraction[13] == 1'b1) begin
fraction = fraction << 9;
exponent = exponent - 9;
end else if (fraction[12] == 1'b0) begin
fraction = fraction << 10;
exponent = exponent - 10;
end
舍位:
mantissa = fraction[21:12];
使用"拼接"语法,最后结果product为16位。
product = {sign,exponent[4:0],mantissa};
input [15:0] floatA, floatB;
output reg [15:0] product;
reg sign;
reg signed [5:0] exponent;
reg [9:0] mantissa;
reg [10:0] fractionA, fractionB;
reg [21:0] fraction;
本模块为纯组合逻辑,非时序。因此只要有数据输入,便触发模块功能,开始运算。
always @ (floatA or floatB) begin
/* -------------------- */
end
if (floatA == 0 || floatB == 0) begin
product = 0;
end
(这一点从上面操作fraction只进行左移也可以看出来。)
if(exponent[5]==1'b1) begin
product=16'b0000000000000000;
end
学习文章:二进制浮点数以及二进制浮点数算术运算
开源项目github-URL:CNN-FPGA