Verilog 实现IEEE 754标准单精度浮点数运算器

一、原理分析

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(原码)

规格化:

        0.00101 = 1.01 \times 2^{-3}

 存入尾数:

        整数1隐藏,小数01填充0,存入23位二进制中

存入阶码: 

        -3 = 11111101(补码)= 01111100(移码)

(这里说明一下,在计算机组成原理中,8位补码的范围是-128到127,其移码的偏移量为128,故其移码和补码的区别只有符号位不同) 

1.2 范围

最大正数:(2-2^{-23}) \times 2^{127} \doteq 3.40282 \times 10^{38}

0_11111110_11111111111111111111111

最小正数:1.0 \times 2^{-126} \doteq 1.17549 \times 10^{-38}

 0_00000001_00000000000000000000000

最大负数: -1.0 \times 2^{-126} \doteq -1.17549 \times 10^{-38}

 1_00000001_00000000000000000000000

最小负数: -(2-2^{-23}) \times 2^{127} \doteq -3.40282 \times 10^{38}

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^{-23} \times 2^{-126} = 2^{-149} \doteq 1.401298 \times 10^{-45}

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的绝对值大小,若\left | A \right | > \left | B \right |,则采用C = \left | A \right | - \left | B \right |,且C的符号与A的符号相同;若\left | A \right | < \left | B \right |,则采用C = \left | B \right | - \left | A \right |,且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即可。

        最后,如果您对我的文章内容或者代码内容有任何疑问可以在评论区发出来与我讨论,私信也可以。之后也会不定期更新计算机芯片的相关内容,感兴趣可以关注我。

IEEE 754浮点数运算Verilog中可以通过使用FPGA开发板来实现FPGA开发板通常具有高性能和低功耗的特点,可以提供良好的硬件支持。 在Verilog中,可以使用IEEE 754浮点数标准定义数据类型,例如单精度浮点数(32位),双精度浮点数(64位)等。可以使用Verilog内置的运算符来进行浮点数的加、减、乘、除等运算,也可以使用Verilog中的模块来实现特定的浮点数运算,如乘法、除法等。 以下是一个使用Verilog实现单精度浮点数加法的例子: ```verilog module float_add(input [31:0] a, input [31:0] b, output [31:0] c); reg [31:0] mantissa_a, mantissa_b; reg [7:0] exp_a, exp_b; reg sign_a, sign_b; reg [31:0] mantissa_c; reg [7:0] exp_c; reg sign_c; assign sign_c = sign_a; assign mantissa_c = mantissa_a + mantissa_b; assign exp_c = exp_a; always @(*) begin sign_a = a[31]; sign_b = b[31]; mantissa_a = {1'b1, a[22:0]}; mantissa_b = {1'b1, b[22:0]}; exp_a = a[30:23] - 127; exp_b = b[30:23] - 127; end always @(*) begin if (mantissa_c[23] == 1) begin mantissa_c = mantissa_c >> 1; exp_c = exp_c + 1; end end always @(*) begin if (exp_a > exp_b) begin mantissa_b = mantissa_b >> (exp_a - exp_b); exp_c = exp_a; end else begin mantissa_a = mantissa_a >> (exp_b - exp_a); exp_c = exp_b; end end always @(*) begin if (sign_a != sign_b) begin if (mantissa_a > mantissa_b) begin mantissa_c = mantissa_a - mantissa_b; sign_c = sign_a; end else begin mantissa_c = mantissa_b - mantissa_a; sign_c = sign_b; end end else begin mantissa_c = mantissa_a + mantissa_b; end end always @(*) begin if (mantissa_c[24] == 1) begin mantissa_c = mantissa_c >> 1; exp_c = exp_c + 1; end end assign c = {sign_c, exp_c + 127, mantissa_c[22:1]}; endmodule ``` 该模块将两个单精度浮点数相加,并输出结果。在该模块中,首先将输入浮点数的符号、尾数和阶码分别提取出来,并进行规格化。然后对阶码和尾数进行调整,使它们的阶码相同,然后进行加法运算。最后再对结果进行规格化,并输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值