一、原理分析
1.IEEE 754标准单精度浮点数
1.1 单精度浮点数的组成与存储
IEEE 754标准的单精度浮点数格式如上,总共32位,由1位符号位,8位阶码,23位尾数组成。其中符号位1表示负数,0表示正数。阶码范围为-126到127,阶码使用移码表示,偏移量为127。尾数使用原码表示,其真实值由1位符号位,1位整数位(默认为1,不在32中存储),23位小数位组成。
以上图value = 0.15625为例。
公式转换如下:
进制转化:
value = 0.15625 = 0.00101(原码)
规格化:
存入尾数:
整数1隐藏,小数01填充0,存入23位二进制中
存入阶码:
-3 = 11111101(补码)= 01111100(移码)
(这里说明一下,在计算机组成原理中,8位补码的范围是-128到127,其移码的偏移量为128,故其移码和补码的区别只有符号位不同)
1.2 范围
最大正数:
0_11111110_11111111111111111111111
最小正数:
0_00000001_00000000000000000000000
最大负数:
1_00000001_00000000000000000000000
最小负数:
1_11111110_11111111111111111111111
1.3 特殊数
无穷大(inf):当阶码 e = 11111111 且尾数全为0时,表示无穷大。
1_11111111_00000000000000000000000(负无穷)
0_11111111_00000000000000000000000(正无穷)
无效数字(NaN): 当阶码 e = 11111111 且尾数不全为0时,表示NaN。
1_11111111_XXXXXXXXXXXXXXXXXXXXXXXXXX
机器零:当阶码 e = 00000000 且尾数全为0时,表示机器零。
1_00000000_00000000000000000000000(负零)
0_00000000_00000000000000000000000(正零)
非规格数: 用于填充零附近的下溢间隙,其与规格数之间过渡很丝滑。
当阶码 e = 00000000 且尾数不全为0时,表示非规格数。该数特点如下:
阶码虽然为00000000,但仍表示指数为-126;
默认整数位为0,而不是规格数的1。
0_00000000_00000000000000000000001
()
2.浮点数加减法
2.1 标准流程
对阶 ——> 尾数相加 ——> 规格化 ——> 舍入 ——> 溢出判断
对阶:两个数相加减,首先比较阶数大小,将阶数小的数通过尾数右移升阶,达到和阶数大的数相同的阶数值。
尾数相加:将对阶后的两数的尾数按照定点加减运算规则相加。(将尾数化成补码相加,使用双符号位)
规格化:尾数的规格化格式为00.1xx或者11.0xx。通过左规和右规实现结果的规格化。同时需要考虑特殊数值-0.5(11.100...0)补码时不是规格化数,-1(11.00...0)补码时是规格化数。左规是尾数左移降阶,右规是尾数右移升阶。
舍入:在对阶时,尾数右移可能造成精度丢失;在规格化时,如果发生右规同样造成精度丢失。这是需要引入舍入规则,降低精度损失。0舍1入法,当被移除的最高数值位为1,在尾数的末位加1;当被移除的最高数值位为0,则舍去。恒置1法,无论移除什么数值,将尾数的末位置1.
溢出判断:当完成规格化后,由于阶码也是用双符号位和补码表示,故,当阶码符号为01时表示上溢出,当阶码符号为10时表示下溢。
2.2 适配IEEE 754标准流程
该流程参考标准流程,结合IEEE 754存储格式,做了一定程度适配。
对阶 + 舍入——> 尾数相加 ——> 规格化 ——> 溢出判断
对阶+舍入:比较对阶,同时根据溢出的数值,按照0舍1入法则,对尾数做处理。
尾数相加:由于尾数使用原码存储,为减少规格化的难度,我采用先比较符号和大小,在进行运算的方法,确保的运算可以直接用原码加减完成而不用担心发生溢出。比如一个正数A和一个负数B相加,先比较A和B的绝对值大小,若,则采用,且C的符号与A的符号相同;若,则采用,且C的符号与A的符号相反。由于A和B相加的结果可能会溢出,所以C的位数更多一位;同时为了减少规格化的硬件复杂度,将两者运算后的结果右移一位后赋值给C。
规格化:因为尾数相加的操作,C的最高两位只可能是00或者01。我们以C的第二高位为尾数的第一个1为规格进行移位,这样只会发生左规操作。故这一步同样不用配合舍入操作。
溢出判断:阶码使用移码表示,在阶码前加一位“0”参与到计算中,若规格化后,阶码高两位为10,表示结果发生上溢,同样考虑阶码为011111111时为无穷大,也可以算作上溢;(若规格化后,阶码高两位为11,表示结果发生下溢)这是书上的说法,但实际上我们发现,其实当阶码的解结果大于9'd382就可以视作下溢了,尽管此时高两位是10(读者可以自己算一下为什么)。当发生上溢时,要给出浮点数溢出中断;若发生下溢,则通过右规操作,将结果转化为非规格数(此时的右规操作不需要引入舍入操作)。
可以证明:发生上溢最大值为阶码11111110和11111110的数相乘,且尾数进位。此时结果为254+254+1-127=382(101111110),满足条件。发生下溢的最小值为0-127+127-23=-23(111101001),满足条件,可化为非规格数。若比该值更小,而比(101111110)要大可直接视作机器0;
3.浮点数乘除法
3.1 标准流程
阶码运算 ——> 尾数运算 ——> 规格化 ——> 舍入 ——> 溢出判断
阶码运算:A*B或者A/B时,阶码使用补码表示,可以直接用A的阶码加上B的阶码或者A的阶码减去B的阶码作为结果。
尾数运算:乘法时:第一步检查两者均不为0时,开始使用定点数乘法完成运算。除法时:第一步检查两者均不零,第二步为了防止溢出,需比较除数和被除数大小,若被除数大于除数,可以将被除数右移一位,开始使用定点数除法完成运算。
规格化:同加减法。
舍入:同加减法。
溢出判断:同加减法。
3.2 适配IEEE 754标准流程
阶码运算 ——> 尾数运算 ——>规格化 ——>舍入——>溢出判断
阶码运算:阶码使用移码运算,乘法时,积的阶码 = A的阶码 + B的阶码 - 127;除法时,商的阶码 = A的阶码 - B的阶码 + 127。
尾数运算:当乘法时,使用*运算符得到A的尾数与B的尾数的乘积,因为在vivado中支持对*乘法器的综合;当除法时,不可以使用/运算符进行,因为/除法器一般不可综合,且就算可综合,综合出的逻辑电路也极度复杂。这里调用vivado的整数除法器ip,将被除数扩展位数并左移24位后放入除法器ip得到结果。主要,为了方便,同样建议被除数在移位前小于除数,这样方便确定从除法器结果中选择位数。
规格化:在加减法规格化模块的基础上扩充了位数,判断如果当前操作是乘法,则规格化应该扫过48位数。
舍入:这里主要是乘法时,得到的结果是48位的,完成规格化需要进行舍入操作,截取高24位作为结果,同时根据0舍1入原则,对低24位舍入。
溢出判断:同加减模块。
二、代码分析
1.状态图和状态分析
本文使用有限状态机实现流程之间的切换,状态转换图如下:
idle:对所有变量进行初始化,并在运算开始前完成对输入浮点数阶码和尾数的存储。
S0:根据A和B阶码相减得到结果符号位的正负,判断A和B阶码的大小,并获得A和B的阶差,并对较小值做右移升阶的操作,同时根据移除的数值,完成舍入操作。
S1:根据A和B符号位和加减操作,分出加和减两大类;减法时,为了不得到负数,比较A和B绝对值大小后,使用大数减小数。三种情况下,可以得到结果的符号位。同时尾数运算结果可能发生溢出,故运算结果统一右移升阶一位。
S2:规格化操作,使用了25位寄存器C_wei_R_high,和24位寄存器C_wei_R_low存储结果。数据格式位高位寄存器,一位固定0,一位整数位,23位小数位;低位寄存器24位小数位。加减除的结果只存储在高位寄存器中,只有乘法的临时结果使用了两个寄存器。规格化的目标就是,将小数位的第一个1,左移降阶到整数位上。
S3:溢出判断。当C阶码的高两位为10,或C阶码为11111111时,或操作为除法且除数为0时,发生上溢,将结果转换为inf,同时拉高错误标志位;当C阶码高两位为11时,将结果转换为机器0。若发现操作为乘除,通过异或判断符号位,有助于区分正无穷和负无穷。拉高ready信号。
S4:乘法时,C的阶码等于A,B阶码相加,并减127。除法时,C的阶码等于A,B阶码相减,并加127。
S5:拉高start_div,启动除法器ip。若start_div已拉高,且操作为除法,取除法器的结果给C的尾数。start_div未拉高,若操作为乘法,使用*操作符得到结果,因为24位定点数相乘,得到48位结果中将有两位整数位,为了符合寄存器的位数安排,可以假设右移了一位,阶码加一而尾数不变;若操作为除法,判断A和B尾数大小,确保A比B小即可。
S6:舍入操作,根据低位寄存器的首位数值,使用0舍1入原则,对高位寄存器舍入。
2.变量表
变量名称 | 位数 | 描述 |
---|---|---|
c_state | 3 | 当前状态 |
n_state | 3 | 下一个状态 |
A_jie_R | 8 | 存储A变量的阶码,移码形式 |
B_jie_R | 8 | 存储B变量的阶码,移码形式 |
A_wei_R | 24 | 存储A的尾数,最高位设置为1,低23位取自输入A,可以理解为1位整数位,23位小数位,无符号位。原码表示 |
B_wei_R | 24 | 存储A的尾数,最高位设置为1,低23位取自输入A |
A_jie_jian_B_jie | 9 | 表示A与B的阶差,最高位可以视作符号位 |
bit_C | 1 | 用于在加减操作时,对阶时舍入的操作是否加1 |
valid_div | 1 | 存储除法器ip的valid信号 |
C_wei_div | 48 | 存储除法器ip的商 |
C_jie_R | 9 | 储存C的阶码, 初始化时最高位设置为0,最终结果取低八位,最高两位可以用于判断溢出 |
C_wei_R_high | 25 | 存储C的尾数,一位固定0,一位整数位,23位小数位 |
C_wei_R_low | 24 | 乘法操作时,用于存储结果尾数的扩展寄存器,24位小数位 |
sign | 1 | 结果的符号位 |
start_div | 1 | 存储除法器ip的start信号 |
div_0 | 24 | 存储除法器IP的余数 |
3.设计文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/08/31 17:20:38
// Design Name:
// Module Name: ALU_float
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//IEEE754标准
//1_数符 8_阶码 23_尾数
//其中阶码使用移码表示,尾数使用原码表示,尾数有隐藏高位
//S:00 加法 11 减法 01 乘法 10 除法
//C:A+B A-B A*B A/B
//ready 结果有效
//start 开始运算
//error 溢出标志
module ALU_float(
input clk,
input rst_n,
input start,
input [1:0] S,
input [31:0] A,
input [31:0] B,
output [31:0] C,
output reg error,
output reg ready
);
parameter idle = 3'd0, //空闲
S0 = 3'd1, //对阶
S1 = 3'd2, //尾数求和
S2 = 3'd3, //规格化
S3 = 3'd4, //溢出判断
S4 = 3'd5, //阶码运算
S5 = 3'd6, //尾数乘除
S6 = 3'd7; //除法时取结果的等待阶段
reg [2:0] c_state,n_state;
reg [7:0] A_jie_R,B_jie_R;
reg [23:0] A_wei_R,B_wei_R;
wire [8:0] A_jie_jian_B_jie;
wire bit_C;
wire valid_div;
wire [47:0] C_wei_div;
reg [8:0] C_jie_R;
reg [24:0] C_wei_R_high;
reg [23:0] C_wei_R_low;
reg sign;
reg start_div;
wire [23:0] div_0;
div_gen_0 diveider (
.s_axis_divisor_tvalid(start_div), // input wire s_axis_divisor_tvalid
.s_axis_divisor_tdata(B_wei_R), // input wire [23 : 0] s_axis_divisor_tdata
.s_axis_dividend_tvalid(start_div), // input wire s_axis_dividend_tvalid
.s_axis_dividend_tdata({A_wei_R,24'd0}), // input wire [47 : 0] s_axis_dividend_tdata
.m_axis_dout_tvalid(valid_div), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata({C_wei_div,div_0}) // output wire [71 : 0] m_axis_dout_tdata
);
always @(posedge clk , negedge rst_n) begin
if (!rst_n) begin
c_state <= idle;
end else begin
c_state <= n_state;
end
end
always @(*) begin
case (c_state)
idle: begin
if(start)
if(^S)
if(A[30:0] && B[30:0]) n_state = S4;
else n_state = S3;
else n_state = S0;
else
n_state = idle;
end
S0:begin
n_state = S1;
end
S1:begin
n_state = S2;
end
S2:begin
if(S == 2'b01)
n_state = S6;
else
n_state = S3;
end
S3:begin
n_state = idle;
end
S4:begin
n_state = S5;
end
S5:begin
if(valid_div)
n_state = S2;
else
n_state = S5;
end
S6:begin
n_state = S3;
end
endcase
end
always @(posedge clk , negedge rst_n) begin
if (!rst_n) begin
A_jie_R <= 0;
B_jie_R <= 0;
C_jie_R <= 0;
A_wei_R <= 0;
B_wei_R <= 0;
C_wei_R_high <= 0;
C_wei_R_low <= 0;
sign <= 0;
error <= 0;
ready <= 0;
start_div <= 0;
end else begin
case (c_state)
idle: begin
B_wei_R <= {1'b1,B[22:0]};
A_wei_R <= {1'b1,A[22:0]};
A_jie_R <= A[30:23];
B_jie_R <= B[30:23];
C_jie_R <= 0;
C_wei_R_high <= 0;
C_wei_R_low <= 0;
sign <= 0;
error <= 0;
ready <= 0;
start_div <= 0;
end
S0:begin
if (A_jie_jian_B_jie[8]) begin
B_jie_R <= B_jie_R;
A_jie_R <= B_jie_R;
B_wei_R <= B_wei_R;
A_wei_R <= (A_wei_R >> (~A_jie_jian_B_jie + 1'b1)) + bit_C;
end else begin
B_jie_R <= A_jie_R;
A_jie_R <= A_jie_R;
A_wei_R <= A_wei_R;
B_wei_R <= (B_wei_R >> A_jie_jian_B_jie) + bit_C;
end
end
S1:begin
if(((A[31]^B[31])&(S == 2'b00)) | (~(A[31]^B[31])&(S == 2'b11)))
if(A_wei_R > B_wei_R) begin
C_wei_R_high <= (A_wei_R - B_wei_R) >> 1 ;
sign <= A[31];
end
else
begin
C_wei_R_high <= (B_wei_R - A_wei_R) >> 1;
sign <= ~A[31];
end
else
begin
sign <= A[31];
C_wei_R_high <= (A_wei_R + B_wei_R) >> 1;
end
C_jie_R <= {1'b0,B_jie_R} + 8'd1;
end
S2:begin
if (C_wei_R_high[23]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low};
C_jie_R <= C_jie_R;
end else if(C_wei_R_high[22]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 1;
C_jie_R <= C_jie_R -9'd1;
end else if(C_wei_R_high[21]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 2;
C_jie_R <= C_jie_R -9'd2;
end else if(C_wei_R_high[20]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 3;
C_jie_R <= C_jie_R -9'd3;
end else if(C_wei_R_high[19]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 4;
C_jie_R <= C_jie_R -9'd4;
end else if(C_wei_R_high[18]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 5;
C_jie_R <= C_jie_R -9'd5;
end else if(C_wei_R_high[17]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 6;
C_jie_R <= C_jie_R -9'd6;
end else if(C_wei_R_high[16]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 7;
C_jie_R <= C_jie_R -9'd7;
end else if(C_wei_R_high[15]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 8;
C_jie_R <= C_jie_R -9'd8;
end else if(C_wei_R_high[14]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 9;
C_jie_R <= C_jie_R -9'd9;
end else if(C_wei_R_high[13]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 10;
C_jie_R <= C_jie_R -9'd10;
end else if(C_wei_R_high[12]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 11;
C_jie_R <= C_jie_R -9'd11;
end else if(C_wei_R_high[11]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 12;
C_jie_R <= C_jie_R -9'd12;
end else if(C_wei_R_high[10]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 13;
C_jie_R <= C_jie_R -9'd13;
end else if(C_wei_R_high[9]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 14;
C_jie_R <= C_jie_R -9'd14;
end else if(C_wei_R_high[8]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 15;
C_jie_R <= C_jie_R -9'd15;
end else if(C_wei_R_high[7]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 16;
C_jie_R <= C_jie_R -9'd16;
end else if(C_wei_R_high[6]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 17;
C_jie_R <= C_jie_R -9'd17;
end else if(C_wei_R_high[5]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 18;
C_jie_R <= C_jie_R -9'd18;
end else if(C_wei_R_high[4]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 19;
C_jie_R <= C_jie_R -9'd19;
end else if(C_wei_R_high[3]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 20;
C_jie_R <= C_jie_R -9'd20;
end else if(C_wei_R_high[2]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 21;
C_jie_R <= C_jie_R -9'd21;
end else if(C_wei_R_high[1]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 22;
C_jie_R <= C_jie_R -9'd22;
end else if(C_wei_R_high[0]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 23;
C_jie_R <= C_jie_R -9'd23;
end else
if(S == 2'b01)begin
if (C_wei_R_low[23]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 24;
C_jie_R <= C_jie_R -9'd24;
end else if(C_wei_R_low[22]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 25;
C_jie_R <= C_jie_R -9'd25;
end else if(C_wei_R_low[21]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 26;
C_jie_R <= C_jie_R -9'd26;
end else if(C_wei_R_low[20]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 27;
C_jie_R <= C_jie_R -9'd27;
end else if(C_wei_R_low[19]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 28;
C_jie_R <= C_jie_R -9'd28;
end else if(C_wei_R_low[18]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 29;
C_jie_R <= C_jie_R -9'd29;
end else if(C_wei_R_low[17]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 30;
C_jie_R <= C_jie_R -9'd30;
end else if(C_wei_R_low[16]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 31;
C_jie_R <= C_jie_R -9'd31;
end else if(C_wei_R_low[15]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 32;
C_jie_R <= C_jie_R -9'd32;
end else if(C_wei_R_low[14]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 33;
C_jie_R <= C_jie_R -9'd33;
end else if(C_wei_R_low[13]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 34;
C_jie_R <= C_jie_R -9'd34;
end else if(C_wei_R_low[12]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 35;
C_jie_R <= C_jie_R -9'd35;
end else if(C_wei_R_low[11]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 36;
C_jie_R <= C_jie_R -9'd36;
end else if(C_wei_R_low[10]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 37;
C_jie_R <= C_jie_R -9'd37;
end else if(C_wei_R_low[9]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 38;
C_jie_R <= C_jie_R -9'd38;
end else if(C_wei_R_low[8]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 39;
C_jie_R <= C_jie_R -9'd39;
end else if(C_wei_R_low[7]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 40;
C_jie_R <= C_jie_R -9'd40;
end else if(C_wei_R_low[6]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 41;
C_jie_R <= C_jie_R -9'd41;
end else if(C_wei_R_low[5]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 42;
C_jie_R <= C_jie_R -9'd42;
end else if(C_wei_R_low[4]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 43;
C_jie_R <= C_jie_R -9'd43;
end else if(C_wei_R_low[3]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 44;
C_jie_R <= C_jie_R -9'd44;
end else if(C_wei_R_low[2]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 45;
C_jie_R <= C_jie_R -9'd45;
end else if(C_wei_R_low[1]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 46;
C_jie_R <= C_jie_R -9'd46;
end else if(C_wei_R_low[0]) begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low} << 47;
C_jie_R <= C_jie_R -9'd47;
end
end
else begin
{C_wei_R_high,C_wei_R_low} <= {C_wei_R_high,C_wei_R_low};
C_jie_R <= C_jie_R;
end
end
S3:begin
ready <= 1;
if(^S)
sign <= A[31] | B[31];
if(C_jie_R[8:7] == 2'b10 || C_jie_R == 9'd255 || (S == 2'b10 && !B[30:0])) begin
error <= 1'd1;
C_jie_R <= 9'd511;
C_wei_R_high <= 0;
end
else if(C_jie_R[8:7] == 2'b11) begin
C_wei_R_high <= 0;
C_jie_R <= 0;
end
end
S4:begin
if(S[1])
C_jie_R <= A_jie_jian_B_jie + 9'd127;
else
C_jie_R <= A_jie_R + B_jie_R - 9'd127;
end
S5:begin
start_div <= 1;
if(start_div)
if(S[1])
C_wei_R_high <= C_wei_div[25:1];
else
C_wei_R_high <= C_wei_R_high;
else
if(S[1]) begin
if(A_wei_R > B_wei_R) begin
A_wei_R <= A_wei_R >> 1;
C_jie_R <= C_jie_R + 9'd1;
end
else begin
A_wei_R <= A_wei_R;
end
end
else begin
{C_wei_R_high,C_wei_R_low} <= A_wei_R * B_wei_R;
C_jie_R <= C_jie_R + 9'd1;
end
end
S6:begin
if(C_wei_R_low[23])
C_wei_R_high <= C_wei_R_high + 25'd1;
else
C_wei_R_high <= C_wei_R_high;
end
endcase
end
end
assign A_jie_jian_B_jie = A_jie_R - B_jie_R;
assign bit_C = A_jie_jian_B_jie ?
((A_jie_jian_B_jie <= 9'd24) || (A_jie_jian_B_jie >= 9'd488) ?
(A_jie_jian_B_jie[8] ?
A_wei_R[~A_jie_jian_B_jie] : B_wei_R[A_jie_jian_B_jie - 8'd1]) : 1'b0) : 1'b0;
assign C = {sign,C_jie_R[7:0],C_wei_R_high[22:0]};
endmodule
4.测试文件
`timescale 1ns / 1ps
module ALU_float_tb (
);
reg rst_n,clk,start;
reg [1:0] S;
reg [31:0] A,B;
wire [31:0] C;
wire error,ready;
ALU_float A1(
.clk(clk),
.rst_n(rst_n),
.start(start),
.S(S),
.A(A),
.B(B),
.C(C),
.error(error),
.ready(ready)
);
always #1 clk = ~clk;
initial begin
clk = 0;
rst_n = 0;
A = 0;
B = 0;
start = 0;
S = 0;
#3
rst_n = 1;
#4
S = 2'b00;
B = 32'b01000111110001101110100101111001;
A = 32'b01001001011000010000011000100101;
#2
start = 1;
#2
start = 0;
#14
S = 2'b11;
#2
start = 1;
#2
start = 0;
#14
S = 2'b01;
#2
start = 1;
#2
start = 0;
#14
S = 2'b10;
#2
start = 1;
#2
start = 0;
#14
$stop;
end
endmodule
三、结果分析
1.matlab结果
2.加法
3.减法
4.乘法
5. 除法
6.当B=0时
7.A,B乘法上溢
8. A,B除法下溢
四、总结
该浮点数单元参考了《计算机组成原理》和网上有关IEEE 754标准的相关资料,设计比较简单,且只能保证综合前仿真正确,时序和面积并未优化,后端肯定无法通过。在算法上,有几个问题需要明确一下:
首先是在加减操作时,有时可能与matlab结果有一点点区别(见结果分析,B= 0时),这是因为在尾数相加后,固定有一步右移升阶一位的操作,可能matlab的并没有这部操作,可能造成一些精度丢失,但几乎不影响结果。
其次,为了硬件简单,并未引入非规格数。如果你有需求,只需要在溢出判断时再添加一种判断,当下溢导致C的阶数大于(512 - 23)时,将C的结果惊醒左移升阶使得C的阶码等于0即可。
最后,如果您对我的文章内容或者代码内容有任何疑问可以在评论区发出来与我讨论,私信也可以。之后也会不定期更新计算机芯片的相关内容,感兴趣可以关注我。