一、FPGA有两种方法表示浮点数
1、自己定义
最高位为符号位 ,中间n位为整数部分 ,最后m位为小数部分
在计算浮点数的运算时候需要转换为定点数

3.14转换为二级制为:11.00100011
自己定义可以表示为:0_00000011_00100011
最高位为符号位 中间8位为整数部分 最后8位是小数部分

2、IEEE 754二进制浮点数算术标准
两种基本的浮点数:单精度(float -32位字长)和双精度(double float -64位字长)。其中单精度格式具有24位有效数字,而双精度格式具有53位有效数字。
两种扩展的浮点数:单精度扩展和双精度扩展。此表准并未规定扩展格式的精度和大小,但它指定了最小精度和大小:单精度扩展需要43位字长以上,双精度亏站需要79位字长以上(64位有效数据)。

浮点数的组成(sign符号、exponent指数、fraction尾数)

FPGA Vivado浮点运算IP核_浮点数


浮点数表示为:V=(-1)^s * M * 2^e

(-1)^s 表示符号位,当s=0,V为正数;当s=1,V为负数

M表示有效数字,1<= M <2;

2^e表示指数位。

左移/右移指数的多少位,在二级制中左移1位表示乘以2,右移1位表示除以2,当移动N位时就是2^N,N可位正也可为负。

二进制浮点数是以符号数值表示法的格式存储–最高有效位被指定为符号位(sign bit);“指数部分”,即次高有效的e个bit,存储指数部分;剩下的f个低有效位的比特,存储有效数的小数部分。

指数偏移(exponent bias)是指浮点数表示法中的指数域的编码值为指数的实际值加上某个固定的值,IEEE 754 规定该固定值位2^(e-1),其中的e为存储指数的比特的长度,单精度为8,双精度为11。所以单精度的固定偏移值是2 ^ (8-1) -1=128-1=127,双精度的固定偏移值是2 ^ (11-1)-1=1024-1=1023;

指数实际的存储:指数的值可能为负数,如果采用补码表示,全体的符号位和E自身的符号位将导致不能简单的进行大小比较。正因为如此,指数部分通常采用一个无符号的正数值存储。单精度的指数部分是-126~+127,加上固定偏移值,指数值的大小是1 ~ 254;浮点数计算时,指数值减去固定偏移值就是实际的指数大小。

采用指数的实际值加上固定的偏移值的办法表示浮点数的指数,好处就是可以用长度为e个比特的无符号整数来表示所有的指数取值,这使得两个浮点数的大小比较更容易。阶码。
eg: 3.14转换为二进制11.00100011…
首先将数据转换为1.x * 2 ^m 的格式即,1.100100011 * 2 ^1格式
8位阶码位大小为127+1
尾数就是小数点后面的所有数据100100011后面补充到23位
所以最终表示为:
0_10000000_100100011000000000000000即十六进制:4048C00(H)

针对阶码E的值,浮点数的值可以分为三种不同的类型:规格化数(正规数)、非规格化数(次正规数)、特殊值。

单精度格式位模式


0<e<255

(-1)^s * 1.f * 2^(e-127(正规数)

e=0,f不等于0

(-1)^s * 0.f * 2^(-126)(次正规数)

e=0 f=0

(-1)^s * 0.0(有符号的零)

s=0 e=255 f=0

+Infinity (正无穷大,特殊值)

s=1 e=255 f=0

-Infinity(负无穷大,特殊值)

e=255 f不等于0

NaN(非数、非确定值、特殊值)

二、IEEE浮点数格式定义了四种不同的舍入方式:
(1)向偶数舍入(默认,不是四舍五入),指向上或向下舍入,尽量使结果的最低有效数字为偶数,也就是向最靠近的数舍入,1.5->2 , 1.4->1, -1.5-> -2,
(2)向零舍入(取整),指的是正负数都向0方向舍入,如1.4->1,-1.5 -> -1
(3)向上舍入(cell),指的每次舍入都进位,如1.4->2
(4)向下舍入(floor),指每次舍入都是向下舍入。

三、FPGA中浮点数运算实现方法
有些FPGA中是不能直接对浮点数进行操作的,只能采用定点数进行数值运算。对于FPGA而言,参与数学运算的数就是16位整型数,FPGA对于小数是无能为力的,一种解决办法就是采用定标。数的定标就是将要运算的浮点数扩大很多倍,然后取整,再用这个数进行运算,运算得到的结果再缩小相应的倍数就可以。

Q表示小数点的位置,Q15就表示小数点在第15位
浮点数x转换为定点数xq: xq = (int)x * 2^Q
定点数xq转换为浮点数x : x = (float) xq * 2^(-Q)

eg: 16进制数2000H,用Q0表示就是8192;用Q15表示就是0.25
Q格式运算中Q值的确定:
(1)定点加减法:需要转换成相同Q格式才能加减
(2)定点乘法:不同Q格式的数据相乘,相当于Q值相加
(3)定点除法:不同Q格式的数据相除,相当于Q值相减
(4)定点左移:相当于Q值增加
(5)定点右移:相当于Q值减少

自己定义的定点数转换为IEEE标准

/******实现将自己定义的浮点数转换为IEEE 754固定的格式*******/
/*------------输入为 31符号位 [30:21]整数位 [20:0]小数位 -------*/
//找到第一个不是0的位数 如果第30位是1 则偏移的阶码位为9  因为整数部分是一共是10位 去掉最高位还余9位
//则最终的8位阶码位为127+9 以此类推
always @ (posedge clk) begin
	if(y_rad_real[30]==1'b1) 
		y_rad_real_float <= {y_rad_real[31],8'd136,y_rad_real[29:7]};
	else if(y_rad_real[29]==1'b1) 
		y_rad_real_float <= {y_rad_real[31],8'd135,y_rad_real[28:6]};
	else if(y_rad_real[28]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd134,y_rad_real[27:5]};
	else if(y_rad_real[27]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd133,y_rad_real[26:4]};
	else if(y_rad_real[26]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd132,y_rad_real[25:3]};
	else if(y_rad_real[25]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'131,y_rad_real[24:2]};
	else if(y_rad_real[24]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd130,y_rad_real[23:1]};
	else if(y_rad_real[23]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd129,y_rad_real[22:0]};
	else if(y_rad_real[22]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd128,y_rad_real[21:0],1'b0};
	else if(y_rad_real[21]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd127,y_rad_real[20:0],2'b0};
	else if(y_rad_real[20]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd126,y_rad_real[19:0],3'b0};
	else if(y_rad_real[19]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd125,y_rad_real[18:0],4'b0};
	else if(y_rad_real[18]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd124,y_rad_real[17:0],5'b0};
	else if(y_rad_real[17]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd123,y_rad_real[16:0],6'b0};
	else if(y_rad_real[16]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd122,y_rad_real[15:0],7'b0};
	else if(y_rad_real[15]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd121,y_rad_real[14:0],8'b0};
	else if(y_rad_real[14]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd120,y_rad_real[13:0],9'b0};
	else if(y_rad_real[13]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd119,y_rad_real[12:0],10'b0};
	else if(y_rad_real[12]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd118,y_rad_real[11:0],11'b0};
	else if(y_rad_real[11]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd117,y_rad_real[10:0],12'b0};
	else if(y_rad_real[10]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd116,y_rad_real[9:0],13'b0};
	else if(y_rad_real[9]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd115,y_rad_real[8:0],14'b0};	
	else if(y_rad_real[8]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd114,y_rad_real[7:0],15'b0};
	else if(y_rad_real[7]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd113,y_rad_real[6:0],16'b0};
	else if(y_rad_real[6]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd112,y_rad_real[5:0],17'b0};
	else if(y_rad_real[5]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd111,y_rad_real[4:0],18'b0};
	else if(y_rad_real[4]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd110,y_rad_real[3:0],19'b0};
	else if(y_rad_real[3]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd109,y_rad_real[2:0],20'b0};
	else if(y_rad_real[2]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd108,y_rad_real[1:0],21'b0};
	else if(y_rad_real[1]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd107,y_rad_real[0],22'b0};
	else if(y_rad_real[0]==1'b1)
		y_rad_real_float <= {y_rad_real[31],8'd106,23'b0};
	else
		y_rad_real_float <= 32'b0;
end

基于FPGA浮点数的定点化
输入的浮点数是f[31:0]表示是一个单精度32浮点数,f[31]是符号位,“0”表示正数,“1”表示负数,f[30:23]这8位是指数位,为了能表示负数,将在实际指数的基础上加上127得到的结果存入到f[30:23],f[22:0]表示小数位(尾数),不过采用了省略整数位(2进制的科学计数位,必定是1),那么这个浮点数要转换成定点数,就需要判断指数位与127的关系,小于127,表示该指数位是正数,那么转换成定点数的话就需要将{8’d1,float_in[22:0]}右移127-float_in[30:23],否则左移float_in[30:23]-127位。

module float2fixed_pipeline
    (
    input [31:0] float_in,
    input enable,
    input clk,
    input rst,
    output reg [31:0] fixed_out,
    output reg valid
    );

     reg [30:0] M_copy;
    reg [4:0] shift_value;
    reg shift_direction;        //0, shift left; 1, shift right
    reg sign;                   //符号位
    reg valid_count;

    
    // Pipeline level 1
    always @ (posedge clk or posedge rst) begin //synchronous enable and asynchronous reset
        if(rst) begin
            shift_value <= 5'd0;
            shift_direction <= 1'b0;
            sign <= 1'b0;
            M_copy <= 31'd0;
        end
        else if(enable) begin
            sign <= float_in[31];
            M_copy <= {8'd1,float_in[22:0]};
            
            if(float_in[30:23] <= 8'd127) begin    //E <= 127,shfit {1'b1,M} right to get I(指数) and F(小数)
                shift_direction <= 1'b1;
                shift_value <= 8'd127 - float_in[30:23];
            end
            else begin                            //E > 127,shfit {1'b1,M} left to get I and F
                shift_direction <= 1'b0;
                shift_value <= float_in[30:23] - 8'd127;//2^7-1
            end         
        end
        else begin        //enable = 0, Maintain the previous value
            shift_value <= shift_value;
            shift_direction <= shift_direction;
            sign <= sign;
            M_copy <= M_copy;
        end
    end
    
    // Output logic
    always @ (posedge clk or posedge rst) begin //synchronous enable and asynchronous reset
        if(rst) begin
            fixed_out <= 32'd0;
        end
        else if(enable) begin 
            if(shift_direction) begin        //E <= 127,shfit {1'b1,M} right to get I and F
                fixed_out <= {sign,M_copy >> shift_value};
            end
            else begin                        //E > 127,shfit {1'b1,M} left to get I and F
                fixed_out <= {sign,M_copy << shift_value};
            end
        end
        else begin        //enable = 0, Maintain the previous value
            fixed_out <= fixed_out;
        end
    end
    

    // The valid output logic
    always @ (posedge clk or posedge rst) begin    //asynchronous reset
        if(rst) begin
            valid <= 1'b0;
            valid_count <= 1'd0;
        end
        else if(enable) begin
            if(valid_count == 1'd1) begin    //Maintain valid as ture unless reset
                valid <= 1'b1;
                valid_count <= valid_count;
            end
            else begin
                valid_count <= 1'b1;
                valid <= 1'b0;
            end
        end
        else begin        //enable = 0, Maintain the previous value
            valid <= valid;
            valid_count <= valid_count;
        end
    end    
    
endmodule