一、IEEE754协议半精度浮点数格式与转换
格式:
二进制半精度浮点数共16位,索引为0-15,其中第15位是符号位,0代表正1代表负,14-10位是阶码,9-0位是尾数位
浮点数十进制转换为二进制
以6.75为例:
1、正数符号位为0
2、将十进制转换为二进制,6.75(D) → 110.11(B)
3、 转换为的规格化数,类似于十进制的科学记数法,110.11(B) → 1.1011 * 10^2
4、计算5位阶码,偏置值(1111)与第二步中n相加,即1111(B)+2(D) = 10001
5、计算尾数,将第二步中的规格化数小数部分提出并作为尾数位,若长度小于10则向后补零,尾数位即为1011000000,注意整数部分的1被隐藏
6、将符号位、阶码、尾数拼到一起即完成十进制到二进制半精度浮点数的转换:0,10001,1011000000
浮点数二进制转十进制
从十进制转二进制原理倒推即可,这里放一个计算说明图,过程不再赘述
二、IEEE754协议半精度浮点数加减法运算原理及代码
以符号位相同为例介绍加减法原理,符号位不同的情况只需要提前判断符号位便可将运算归类为加法或减法,基本流程都是对阶、尾数相加、规格化、舍入、溢出判断
加法
X:15.5(D) → 0,10010,1111000000(B)
Y:2.75(D) → 0,10000,0110000000(B)
1、对阶,比较阶码大小,将小阶码转换为大阶码,因此将Y的阶码转换为X的阶码,阶码加2(D),同时将Y尾数右移两位,注意尾数前隐藏的1,Y尾数(1)0110000000右移两位变为(0)0101100000,隐藏的1变为0,对阶后两者阶码均为10010
2、尾数相加,X尾数没有变化:(1)1111000000,Y的尾数:(0)0101100000
尾数直接相加结果为(10)0100100000
3、需要将尾数相加的结果进行规格化,需要将尾数右移1位同时阶码加1,这样隐藏位从10变为1,规格化结果:阶码10010+1=10011,尾数(1)0010010000
4、舍入,由于尾数右移截断可能产生误差,目前有多种舍入方法来中和误差:
末位恒1:右移后末位置为1;
0舍1入:右移截断的最高位为1则将尾数+1,重新规格化
5、溢出判断:判断阶码是否溢出
6、组合结果0,10011,0010010000
减法
X:8.25(D) → 0,10010,0000100000(B)
Y:-1.25(D) → 1,01111,0100000000(B)
1、8.25阶码大,符号位为0
2、对阶,X阶码大,Y阶码加3(D)同时尾数右移,Y尾数(1)0100000000右移3位变为(0)0010100000,隐藏的1变为0
3、尾数相减X(1)0000100000 - Y(0)0010100000 = (0)1110000000
4、规格化,将尾数左移1位同时阶码减1,将隐藏的0变为1,阶码10001,尾数(1)1100000000
5、判断溢出
6、组合结果0,10001,1100000000
verilog代码
初步采用组合逻辑,无时钟延时,后续可能根据实际需求进行优化或修改为时序逻辑
另外目前还没有添加舍入判断,直接进行右移截断
module float_add16(
input [15:0]a,
input [15:0]b,
output reg [15:0]sum
);
reg sign;//第一位符号位
reg [4:0]exponent_a;
reg [4:0]exponent_b;
reg [10:0]fraction_a;
reg [10:0]fraction_b;//最高位是隐藏的1
reg [4:0]exponent_sum;//可加上第一位判断上溢
reg [11:0]fraction_sum;//保存尾数相加后的进位,以便阶码加减和右规
reg [7:0]exponent_shift;
//用*是所有输入信号敏感
always@(a or b)begin
exponent_a=a[14:10];
exponent_b=b[14:10];
fraction_a={1'b1,a[9:0]};
fraction_b={1'b1,b[9:0]};
if(a[15]==b[15])begin//符号位相同则为加法
sign=a[15];//直接确定符号位
if(exponent_a==exponent_b)begin//阶码相等直接进行尾数相加
fraction_sum = fraction_a + fraction_b;//fraction_sum[11:10]只可能为11或10,尾数要右移一位,阶码加1
exponent_sum = exponent_a + 1'b1;//阶码+1
fraction_sum = fraction_sum >> 1'b1;
end
else if(exponent_a<exponent_b)begin//对阶:a小阶对b大阶
exponent_shift = exponent_b - exponent_a;//确定移多少位
exponent_sum = exponent_b;//阶码
fraction_a = fraction_a >> (exponent_shift);
fraction_sum = fraction_a + fraction_b;
case(fraction_sum[11:10])
2'b11:begin
exponent_sum=exponent_sum + 1'b1;
fraction_sum = fraction_sum >> 1'b1;
end
2'b10:begin
exponent_sum=exponent_sum + 1'b1;
fraction_sum = fraction_sum >> 1'b1;
end
default:begin
exponent_sum = exponent_b;
fraction_sum = fraction_a + fraction_b;
end
endcase
end
else begin//对阶:b小阶对a大阶
exponent_shift = exponent_a - exponent_b;//确定移多少位
exponent_sum = exponent_a;//阶码
fraction_b = fraction_b >> (exponent_shift);
fraction_sum = fraction_a + fraction_b;
case(fraction_sum[11:10])
2'b11:begin
exponent_sum=exponent_sum + 1'b1;
fraction_sum = fraction_sum >> 1'b1;
end
2'b10:begin
exponent_sum=exponent_sum + 1'b1;
fraction_sum = fraction_sum >> 1'b1;
end
2'b01,2'b00:begin
exponent_sum = exponent_a;
fraction_sum = fraction_a + fraction_b;
end
endcase
end
end
else begin//符号不同视为相减,根据阶码大小判断符号位,再进行后续的对阶和尾数相加
if(exponent_a>exponent_b)begin//阶码大则数大,阶码相同则比较尾数大小
sign=a[15];
exponent_shift = exponent_a - exponent_b;
exponent_sum = exponent_a;
fraction_b = fraction_b >> (exponent_shift);//对阶
fraction_sum = fraction_a - fraction_b;//尾数计算
if(fraction_sum[10]==0)begin
if(fraction_sum[9]==1)begin
fraction_sum = fraction_sum << 1;
exponent_sum = exponent_sum - 1;
end
else if(fraction_sum[8]==1)begin
fraction_sum = fraction_sum << 2;
exponent_sum = exponent_sum - 2;
end
else if(fraction_sum[7]==1)begin
fraction_sum = fraction_sum << 3;
exponent_sum = exponent_sum - 3;
end
else if(fraction_sum[6]==1)begin
fraction_sum = fraction_sum << 4;
exponent_sum = exponent_sum - 4;
end
else if(fraction_sum[5]==1)begin
fraction_sum = fraction_sum << 5;
exponent_sum = exponent_sum - 5;
end
else if(fraction_sum[4]==1)begin
fraction_sum = fraction_sum << 6;
exponent_sum = exponent_sum - 6;
end
else if(fraction_sum[3]==1)begin
fraction_sum = fraction_sum << 7;
exponent_sum = exponent_sum - 7;
end
else if(fraction_sum[2]==1)begin
fraction_sum = fraction_sum << 8;
exponent_sum = exponent_sum - 8;
end
else if(fraction_sum[1]==1)begin
fraction_sum = fraction_sum << 9;
exponent_sum = exponent_sum - 9;
end
else if(fraction_sum[0]==1)begin
fraction_sum = fraction_sum << 10;
exponent_sum = exponent_sum - 10;
end
end
end
else if(exponent_a<exponent_b)begin
sign=b[15];
exponent_shift = exponent_b - exponent_a;
exponent_sum = exponent_b;
fraction_a = fraction_a >> (exponent_shift);//对阶
fraction_sum = fraction_b - fraction_a;//尾数计算
if(fraction_sum[10]==0)begin
if(fraction_sum[9]==1)begin
fraction_sum = fraction_sum << 1;
exponent_sum = exponent_sum - 1;
end
else if(fraction_sum[8]==1)begin
fraction_sum = fraction_sum << 2;
exponent_sum = exponent_sum - 2;
end
else if(fraction_sum[7]==1)begin
fraction_sum = fraction_sum << 3;
exponent_sum = exponent_sum - 3;
end
else if(fraction_sum[6]==1)begin
fraction_sum = fraction_sum << 4;
exponent_sum = exponent_sum - 4;
end
else if(fraction_sum[5]==1)begin
fraction_sum = fraction_sum << 5;
exponent_sum = exponent_sum - 5;
end
else if(fraction_sum[4]==1)begin
fraction_sum = fraction_sum << 6;
exponent_sum = exponent_sum - 6;
end
else if(fraction_sum[3]==1)begin
fraction_sum = fraction_sum << 7;
exponent_sum = exponent_sum - 7;
end
else if(fraction_sum[2]==1)begin
fraction_sum = fraction_sum << 8;
exponent_sum = exponent_sum - 8;
end
else if(fraction_sum[1]==1)begin
fraction_sum = fraction_sum << 9;
exponent_sum = exponent_sum - 9;
end
else if(fraction_sum[0]==1)begin
fraction_sum = fraction_sum << 10;
exponent_sum = exponent_sum - 10;
end
end
end
else begin
if(fraction_a>fraction_b)begin
sign=a[15];
exponent_shift = exponent_a - exponent_b;
exponent_sum = exponent_a;
fraction_b = fraction_b >> (exponent_shift);//对阶
fraction_sum = fraction_a - fraction_b;//尾数计算
if(fraction_sum[10]==0)begin
if(fraction_sum[9]==1)begin
fraction_sum = fraction_sum << 1;
exponent_sum = exponent_sum - 1;
end
else if(fraction_sum[8]==1)begin
fraction_sum = fraction_sum << 2;
exponent_sum = exponent_sum - 2;
end
else if(fraction_sum[7]==1)begin
fraction_sum = fraction_sum << 3;
exponent_sum = exponent_sum - 3;
end
else if(fraction_sum[6]==1)begin
fraction_sum = fraction_sum << 4;
exponent_sum = exponent_sum - 4;
end
else if(fraction_sum[5]==1)begin
fraction_sum = fraction_sum << 5;
exponent_sum = exponent_sum - 5;
end
else if(fraction_sum[4]==1)begin
fraction_sum = fraction_sum << 6;
exponent_sum = exponent_sum - 6;
end
else if(fraction_sum[3]==1)begin
fraction_sum = fraction_sum << 7;
exponent_sum = exponent_sum - 7;
end
else if(fraction_sum[2]==1)begin
fraction_sum = fraction_sum << 8;
exponent_sum = exponent_sum - 8;
end
else if(fraction_sum[1]==1)begin
fraction_sum = fraction_sum << 9;
exponent_sum = exponent_sum - 9;
end
else if(fraction_sum[0]==1)begin
fraction_sum = fraction_sum << 10;
exponent_sum = exponent_sum - 10;
end
end
end
else if(fraction_a < fraction_b)begin
sign=b[15];
exponent_shift = exponent_b - exponent_a;
exponent_sum = exponent_b;
fraction_a = fraction_a >> (exponent_shift);//对阶
fraction_sum = fraction_b - fraction_a;//尾数计算
if(fraction_sum[10]==0)begin
if(fraction_sum[9]==1)begin
fraction_sum = fraction_sum << 1;
exponent_sum = exponent_sum - 1;
end
else if(fraction_sum[8]==1)begin
fraction_sum = fraction_sum << 2;
exponent_sum = exponent_sum - 2;
end
else if(fraction_sum[7]==1)begin
fraction_sum = fraction_sum << 3;
exponent_sum = exponent_sum - 3;
end
else if(fraction_sum[6]==1)begin
fraction_sum = fraction_sum << 4;
exponent_sum = exponent_sum - 4;
end
else if(fraction_sum[5]==1)begin
fraction_sum = fraction_sum << 5;
exponent_sum = exponent_sum - 5;
end
else if(fraction_sum[4]==1)begin
fraction_sum = fraction_sum << 6;
exponent_sum = exponent_sum - 6;
end
else if(fraction_sum[3]==1)begin
fraction_sum = fraction_sum << 7;
exponent_sum = exponent_sum - 7;
end
else if(fraction_sum[2]==1)begin
fraction_sum = fraction_sum << 8;
exponent_sum = exponent_sum - 8;
end
else if(fraction_sum[1]==1)begin
fraction_sum = fraction_sum << 9;
exponent_sum = exponent_sum - 9;
end
else if(fraction_sum[0]==1)begin
fraction_sum = fraction_sum << 10;
exponent_sum = exponent_sum - 10;
end
end
end
else begin
sign=a[15];
exponent_shift = exponent_a - exponent_b;
exponent_sum = exponent_a;
fraction_b = fraction_b >> (exponent_shift);//对阶
fraction_sum = fraction_a - fraction_b;//尾数计算
if(fraction_sum[10]==0)begin
if(fraction_sum[9]==1)begin
fraction_sum = fraction_sum << 1;
exponent_sum = exponent_sum - 1;
end
else if(fraction_sum[8]==1)begin
fraction_sum = fraction_sum << 2;
exponent_sum = exponent_sum - 2;
end
else if(fraction_sum[7]==1)begin
fraction_sum = fraction_sum << 3;
exponent_sum = exponent_sum - 3;
end
else if(fraction_sum[6]==1)begin
fraction_sum = fraction_sum << 4;
exponent_sum = exponent_sum - 4;
end
else if(fraction_sum[5]==1)begin
fraction_sum = fraction_sum << 5;
exponent_sum = exponent_sum - 5;
end
else if(fraction_sum[4]==1)begin
fraction_sum = fraction_sum << 6;
exponent_sum = exponent_sum - 6;
end
else if(fraction_sum[3]==1)begin
fraction_sum = fraction_sum << 7;
exponent_sum = exponent_sum - 7;
end
else if(fraction_sum[2]==1)begin
fraction_sum = fraction_sum << 8;
exponent_sum = exponent_sum - 8;
end
else if(fraction_sum[1]==1)begin
fraction_sum = fraction_sum << 9;
exponent_sum = exponent_sum - 9;
end
else if(fraction_sum[0]==1)begin
fraction_sum = fraction_sum << 10;
exponent_sum = exponent_sum - 10;
end
end
end
end
end
sum = {sign,exponent_sum,fraction_sum[9:0]};
end
endmodule
附加时序逻辑代码
//add_en后延迟3个周期出结果
module float32_add_reg(
input clk,
input rst_n,
input [31:0]a,
input [31:0]b,
input add_en,
output [31:0]out
);
reg [7:0]exponent_a;//指数位阶码
reg [7:0]exponent_b;
reg [7:0]exponent_out;
reg sign;
reg [23:0]fraction_a;//尾数位
reg [23:0]fraction_b;
reg [24:0]fraction_out;//尾数位多2位便于右移
reg [7:0]shift_cnt;
reg add_en_d0;
reg add_en_d1;
reg add_en_d2;
reg add_en_d3;
reg [7:0]exponent_out_reg;
reg [24:0]fraction_out_reg;
reg [23:0]fraction_a_reg;
reg [23:0]fraction_b_reg;
reg same;
reg different;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
same<=1'b0;
different<=1'b0;
end
else begin
if(a[31]==1 && b[31]==1)begin
sign<=1'b1;
same<=1'b1;
different<=1'b0;
end
else if(a[31]==0 && b[31]==0)begin
sign<=1'b0;
same<=1'b1;
different<=1'b0;
end
else if(a[31]==1 && b[31]==0 && a[30:0]>b[30:0])begin
sign<=a[31];
different<=1'b1;
same<=1'b0;
end
else if(a[31]==1 && b[31]==0 && a[30:0]<b[30:0])begin
sign<=b[31];
different<=1'b1;
same<=1'b0;
end
else if(a[31]==0 && b[31]==1 && a[30:0]>b[30:0])begin
sign<=a[31];
different<=1'b1;
same<=1'b0;
end
else if(a[31]==0 && b[31]==1 && a[30:0]<b[30:0])begin
sign<=b[31];
different<=1'b1;
same<=1'b0;
end
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
exponent_a<=8'd0;
exponent_b<=8'd0;
fraction_a<=23'd0;
fraction_b<=23'd0;
end
else if(add_en)begin
exponent_a<=a[30:23];
exponent_b<=b[30:23];
fraction_a<={1'b1,a[22:0]};
fraction_b<={1'b1,b[22:0]};
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
add_en_d0<=1'b0;
add_en_d1<=1'b0;
add_en_d2<=1'b0;
add_en_d3<=1'b0;
end
else begin
add_en_d0<=add_en;
add_en_d1<=add_en_d0;
add_en_d2<=add_en_d1;
add_en_d3<=add_en_d2;
end
end
always@(posedge clk or negedge rst_n)begin//对阶
if(!rst_n)begin
exponent_out<=8'd0;
shift_cnt<=8'd0;
end
else if(add_en)begin
if(a[30:23] < b[30:23])begin
shift_cnt<=b[30:23] - a[30:23];
exponent_out<=b[30:23];
end
else if(a[30:23] > b[30:23])begin
shift_cnt<=a[30:23] - b[30:23];
exponent_out<=a[30:23];
end
else begin
shift_cnt<=8'd0;
exponent_out<=a[30:23];
end
end
end
always@(posedge clk)begin//符号位相同或不同都要尾数右移
if(!rst_n)begin
fraction_a_reg<=8'd0;
fraction_b_reg<=8'd0;
end
else if(add_en_d0)begin
if(a[30:23] < b[30:23])begin
fraction_a_reg<=fraction_a >> shift_cnt;
fraction_b_reg<=fraction_b;
end
else if(a[30:23] > b[30:23])begin
fraction_b_reg<=fraction_b >> shift_cnt;
fraction_a_reg<=fraction_a;
end
end
end
always@(posedge clk or negedge rst_n)begin//尾数相加或相减
if(!rst_n)begin
fraction_out<=25'd0;
end
else if(add_en_d1)begin
if(same)begin
fraction_out<=fraction_a_reg+fraction_b_reg;
end
else if(different)begin
if(a[30:23] < b[30:23])begin
fraction_out<=fraction_b_reg-fraction_a_reg;
end
else if(a[30:23] > b[30:23])begin
fraction_out<=fraction_a_reg-fraction_b_reg;
end
end
end
end
always@(posedge clk or negedge rst_n)begin//规格化
if(!rst_n)begin
exponent_out_reg<=1'b0;
fraction_out_reg<=1'b0;
end
else if(add_en_d2)begin
if(fraction_out[24:23] == 2'b11)begin
exponent_out_reg<=exponent_out + 1'b1;
fraction_out_reg <= fraction_out >> 1'b1;
end
else if(fraction_out[24:23] == 2'b10)begin
exponent_out_reg<=exponent_out + 1'b1;
fraction_out_reg <= fraction_out >> 1'b1;
end
else if(fraction_out[24:23] == 2'b01) begin
exponent_out_reg = exponent_out;
fraction_out_reg = fraction_a + fraction_b;
end
else if(fraction_out[22]==1'b1)begin
exponent_out_reg<=exponent_out - 1'b1;
fraction_out_reg <= fraction_out << 1'b1;
end
else if(fraction_out[21]==1'b1)begin
exponent_out_reg<=exponent_out - 2;
fraction_out_reg <= fraction_out << 2;
end
else if(fraction_out[20]==1'b1)begin
exponent_out_reg<=exponent_out - 3;
fraction_out_reg <= fraction_out << 3;
end
else if(fraction_out[19]==1'b1)begin
exponent_out_reg<=exponent_out - 4;
fraction_out_reg <= fraction_out << 4;
end
else if(fraction_out[18]==1'b1)begin
exponent_out_reg<=exponent_out - 5;
fraction_out_reg <= fraction_out << 5;
end
else if(fraction_out[17]==1'b1)begin
exponent_out_reg<=exponent_out - 6;
fraction_out_reg <= fraction_out << 6;
end
else if(fraction_out[16]==1'b1)begin
exponent_out_reg<=exponent_out - 7;
fraction_out_reg <= fraction_out << 7;
end
else if(fraction_out[15]==1'b1)begin
exponent_out_reg<=exponent_out - 8;
fraction_out_reg <= fraction_out << 8;
end
else if(fraction_out[14]==1'b1)begin
exponent_out_reg<=exponent_out - 9;
fraction_out_reg <= fraction_out << 9;
end
else if(fraction_out[13]==1'b1)begin
exponent_out_reg<=exponent_out - 10;
fraction_out_reg <= fraction_out << 10;
end
else if(fraction_out[12]==1'b1)begin
exponent_out_reg<=exponent_out - 11;
fraction_out_reg <= fraction_out << 11;
end
else if(fraction_out[11]==1'b1)begin
exponent_out_reg<=exponent_out - 12;
fraction_out_reg <= fraction_out << 12;
end
else if(fraction_out[10]==1'b1)begin
exponent_out_reg<=exponent_out - 13;
fraction_out_reg <= fraction_out << 13;
end
else if(fraction_out[9]==1'b1)begin
exponent_out_reg<=exponent_out - 14;
fraction_out_reg <= fraction_out << 14;
end
else if(fraction_out[8]==1'b1)begin
exponent_out_reg<=exponent_out - 15;
fraction_out_reg <= fraction_out << 15;
end
else if(fraction_out[7]==1'b1)begin
exponent_out_reg<=exponent_out - 16;
fraction_out_reg <= fraction_out << 16;
end
else if(fraction_out[6]==1'b1)begin
exponent_out_reg<=exponent_out - 17;
fraction_out_reg <= fraction_out << 17;
end
else if(fraction_out[5]==1'b1)begin
exponent_out_reg<=exponent_out - 18;
fraction_out_reg <= fraction_out << 18;
end
else if(fraction_out[4]==1'b1)begin
exponent_out_reg<=exponent_out - 19;
fraction_out_reg <= fraction_out << 19;
end
else if(fraction_out[3]==1'b1)begin
exponent_out_reg<=exponent_out - 20;
fraction_out_reg <= fraction_out << 20;
end
else if(fraction_out[2]==1'b1)begin
exponent_out_reg<=exponent_out - 21;
fraction_out_reg <= fraction_out << 21;
end
else if(fraction_out[1]==1'b1)begin
exponent_out_reg<=exponent_out - 22;
fraction_out_reg <= fraction_out << 22;
end
else if(fraction_out[0]==1'b1)begin
exponent_out_reg<=exponent_out - 23;
fraction_out_reg <= fraction_out << 23;
end
else begin//0情况
exponent_out_reg<=exponent_out;
fraction_out_reg<=fraction_out;
end
end
end
assign out = {sign, exponent_out_reg, fraction_out_reg[22:0]};
endmodule