Floatint-point 的使用

Floatint-point 的使用

xilinx的常用ip应用系列(零)

ip使用分享(一)

  • 设计平台:Vivado-2017.4(ISE或许也有相对应的)

最近用到了这样一个ip,给功能上是要将浮点数转换成定点数,那顺便我们就可以介绍一下Float-point这个大ip的使用方法.

例化和使用

顶栏 Window->IP Catalog->搜索’float’即得进入页面

官方手册 pg060

在这里插入图片描述

可见,xilinx将几乎所有得浮点数操作都封到这个ip上面了,包括了诸如加减乘除,平方开方等操作.

但需要注意的是,跟ise中的使用不一样,这里的数据输入都是经过axi接口的,所以上图中的S_AXIS_A即为输入数据项.

在这里插入图片描述

点击下一步后,就要选择输入数据类型了,有常见的半精度(Half),单精度(float)和双精度(double),当然还可以自定义整数和小数的位宽.这里以double为例.

在这里插入图片描述

同样,也要选择输出的定点数的范围,为了更好的演示效果,这里取custom,然后取1位符号位,31位整数位和32位的小数位.后面两步是设置延时和接口的,这里就不作介绍了.

简单写个例化代码

module float2point(
    input CLK_50M,aresetn,
    input [63:0] double_data,
    output wire  issigned,
    output wire [30:0] zhengshu,
    output wire [31:0] xiaoshu
    );

wire m_axis_result_tvalid;
float2fix u_float2fix (
  .aclk(CLK_50M),                                  // input wire aclk
  .s_axis_a_tvalid(1'b1),            // input wire s_axis_a_tvalid
  .aresetn(aresetn),                            // input wire aresetn
  .s_axis_a_tdata(double_data),              // input wire [63 : 0] s_axis_a_tdata
  .m_axis_result_tvalid(m_axis_result_tvalid),  // output wire m_axis_result_tvalid
  .m_axis_result_tdata({issigned, zhengshu, xiaoshu})    // output wire [63 : 0] m_axis_result_tdata
);
endmodule

再简单地写个tb(其实也是自动生成的):

module f2p_tb();
localparam PERIOD = 20;
// float2point Inputs     
reg   CLK_50M=0;
reg   [63:0]  double_data=0;
reg   aresetn = 1;
// float2point Outputs
wire  issigned;
wire  [30:0]  zhengshu;
wire  [31:0]  xiaoshu;
float2point  u_float2point (
    .CLK_50M                 ( CLK_50M       ),
    .aresetn(aresetn),
    .double_data             ( double_data   ),
    .issigned                ( issigned      ),
    .zhengshu                ( zhengshu      ),
    .xiaoshu                 ( xiaoshu       )
);

always #(PERIOD/2) CLK_50M = ~CLK_50M;
initial
begin
    #(5*PERIOD) aresetn = 0;
    #(5*PERIOD) aresetn = 1;
    #(10*PERIOD)
    #PERIOD double_data = 64'b0011111111111011001100110011001100110011001100110011001100110011;
    #(10*PERIOD)
    $stop;
end
endmodule

产生测试数据

那么就会有热心网友想问,你上面的测试数据咋生成的呢?

那 就要介绍一个这个 python代码了:

import bitstring
f1 = bitstring.BitArray(float=1.7, length=64)
print(f1.bin)

这里的float是指浮点数,length是32的时候是"float"类型,64的时候是"double"类型

接下来便是 仿真了:

在这里插入图片描述

显然,整数部分已然是出来了,但是小数部分说是有点古怪,不应该是7吗?

但是要仔细想想,在double数据类型里面,小数部分有53位,咋转成定点数就剩下4位(0-9)了呢?

显然,这个值是相对 2的32次方为1的时候考虑的,就是说,如果我们将这个数除以2的32次方,为其真实小数值.

在这里插入图片描述

已然是很接近0.7了.

做点发散思考

那么假设这个值是一个秒数,我们要在硬件计算当前是多上微秒要咋处理呢?

在完全不考虑优化的前提下(设整数为z,小数为x):

u s = ( z + x 2 32 ) ∗ 1000000 us =(z + \frac{x}{2^{32}})* 1000 000 us=(z+232x)1000000
显然,将小数部分拆开:

u s = z ∗ 1000000 + x 2 32 ∗ 1000000 us =z*1000000 + \frac{x}{2^{32}}* 1000000 us=z1000000+232x1000000

此时,显然可以将分母理解为移位,然后将这个移位转到1000000上面,就变成了
u s = z ∗ 1000000 + x 2 26 ∗ 15625 us =z*1000000 + \frac{x}{2^{26}}* 15625 us=z1000000+226x15625

来验证一下:

​ 取小数部分移位26位(即取高6位): 6’b101100(44)

此时 us 为:
u s = 1 ∗ 1000000 + 44 ∗ 15625 = 687500 us =1*1000000 + 44 * 15625 = 687500 us=11000000+4415625=687500

显然是不行的,这个截位带来的误差太大了,即便是取四舍五入,即取45,也是703125

此时, 我们可以转换一下思路,将属于小数的右移转换成整数部分的左移:
u s = ( z < < 32 + x ) ∗ 1000000 2 32 us = \frac{(z<<32 + x)* 1000000}{2^{32}} us=232(z<<32+x)1000000

这个时候来试一下:
u s = ( 1 < < 32 + 3006477101 ) ∗ 1000000 2 32 = 1 , 699 , 999.99855645 us = \frac{(1<<32 + 3006477101)* 1000000}{2^{32}} = 1,699,999.99855645 us=232(1<<32+3006477101)1000000=1,699,999.99855645

当然,由于是整点乘除,结果只能是1699999.

当然了,也是因为这里是整点乘除,所以证明这个小算法还是可以继续修改下去的(对小数部分再作处理),就作为思考题就给大家啦~

还算可以吧~

结语

做点简单的小ip介绍应用系列给大家,但是最近应该还是暂时不会更之前的系列作,敬请等待:)

打赏通道

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页