当前位置:   article > 正文

基于IEEE754标准的浮点数加法运算_fpga使用ieee754浮点数

fpga使用ieee754浮点数

基于IEEE754标准的浮点数加法运算


背景:
前文有提到过,心血来潮想学习浮点数乘法,基于IEEE754标准完成一个浮点数乘法运算的代码实现。随后,发现乘加器的运用比较广泛,且目前已完成了单精度浮点乘法运算的实现,所以,为嘛不去实现单精度浮点加法的运算呢?
于是,决定对相关知识点进行整合,进行一个完整的浮点数加法实现。


说明1:如果文章有误,欢迎大家指出、讨论,笔者也会积极改正,希望大家一起进步!
说明2:为了书写方便,本文中的一些符号相关的写法,可能是基于verilog语言的写法。另有一些流程,为了更直观的的表达,用的是verilog伪代码的方式进行展示。若给大家的阅读带来不便,还请多多包涵。



前言

  • 插句题外话:
  • 借用一句台词“木叶飞舞之处,火之意志生生不息”,致那位好友。
  • 属于我们的大航海时代已经开启了,人生是旷野,有缘再见,祝好运!
  • 2024年07月23日,记于 伟大航路 上

一、单精度浮点数

  • 关于浮点数,已经在上一篇文章中详细介绍过了,本文就不赘述了。
  • 有需要的朋友,可以点击此处链接浮点数及其乘法运算(基于IEEE754标准),前往查阅。
  • 注1:单精度浮点数(Single Floating Point,binary 32 format)、双精度浮点数(Double Floating Point,binary 64 format),虽然两者在阶码位、尾数位的位宽上有区别,但在乘法、加法的计算原理上基本一致,可以做到类推。
  • 注2:浮点数,不管是单精度,还是双精度,由科学计算法变化而来,不能直接乘加,注意格式。

二、浮点数加法

1.思路

假设需要对两个浮点乘数A[31:0]和B[31:0]进行加法运算,得到C,则具体流程如下:
C = A + B
= { A_sign, A_exponent, A_fraction} + { B_sign, B_exponent, B_fraction};
其中:

  • 假设A_exponent > B_exponent
  • 开始比较A_exponent、B_exponent的大小,
  • 调整A_fraction与B_fraction的小数位来使A_exponent、B_exponent的大小一致。
  • 一般是,阶码小的向价码大的对齐。
  • 调整完毕后,即可进行加减运算,并对所得结果进行正规化、位数舍入,即可得到所求结果。
    则有:
    1 exp_diff = A_exponent - B_exponent > 0;
    2 将{1‘b1,B_fraction}向左移 exp_diff 位,得到b_f_align;
    注意:这里进行移位、加运算时,必须要把尾数位的隐藏位1加进去,该1表示小数的整数部分。
    注意:CSDN上的很多帖子上,都在写用双符号法判断溢出的操作,但他们在所给的计算样例中舍弃掉隐藏位1,不小心就被绕进去了。
    注意:如,本来要计算浮点数 1.m1 + 1.m2 的,对方展示的样例可能就是计算 0.m1+0.m2 的,然后用起了双符号法。
    3 根据符号A_sign与B_sign,进行A_fraction与b_f_align的运算。
// 注:Verilog伪代码
if( A_sign== B_sign) begin
	sum_m  = c_m_align + d_m_align;
	sum_s = A_sign;
end else if (A_fraction>= b_f_align) begin
	sum_m  = A_fraction- b_f_align;
	sum_s = A_sign;
end else if (A_fraction< b_f_align) begin
	sum_m  = b_f_align- A_fraction;
	sum_s = B_sign;
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

4 计算结果正则化,然后进行舍入计算。并在此过程中,要进行溢出判断。

注:
a 赛灵思他们家好像用的都是就近舍入( Round to nearest (even) );
b 还有一些帖子上用的是 末位恒置1法 、0舍1入法,感觉精度不一定有 就近舍入 的高。

2.加法算法

// 注:Verilog伪代码,不是规范的代码书写,只是为了方便 阅读 与 区分。

if( A和B为 zero或denormal ) begin
	则返回zero;
end else if( A或B为 nan) begin
	返回qnan;
end else if( A或B为 infinity ) begin
	if( A与B为 infinity ) begin
		if( A或B为 符号不相同 )  返回qnan;
		else 返回infinity;
	end else 	
		返回infinity;
end else if(  A为 zero )begin
	返回B;
end else if(  B为 zero )begin
	返回A;
else
	正常的浮点数计算,按照 1.思路 中的操作来就行了。
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

上述过程中,还需要对INVALID、UNDERFLOW、OVERFLOW进行判断。
这个根据定义来就行了,比较简单,就不赘述了。

3.代码示例

	fp_add_data #(
		.addr_width( addr_WIDTH )
	)fp_add_data_inst(	//   数据读取模块,对存在本地的浮点数据进行读取
		.Clk(Clk),
		.rst_N(rst_N),
		.Done(Done),
		.C_H(c_h[31:0]),
		.D_H(d_h[31:0]),
		.C_D(c_d[31:0])
	);
	//   A和B的数据,传递给浮点加法器
	fp_add fp_add_inst(	
		.C(c_h[31:0]),
		.D(d_h[31:0]),
		.FPA_OUT(fpa_out[31:0]) //   通过浮点乘法器算出来的A*B结果
	);
assign PassStatus = ( fpa_out==c_d )? 1 : 0 ; //   将事先预算出的加法结果与浮点加法模块算出的结果进行对比
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

4. RTL仿真图(vivado)

波形图:
1 整体角度
在这里插入图片描述
2 局部放大
在这里插入图片描述
从RTL仿真结果来看,PassStatus的一直为1,这意味浮点数加法器的功能应该是通过了的。

其他:
关于运行速度,是在一款国产FPGA软件工具上测的。
预期300Mhz,最快可以跑到320Mhz;预期400Mhz,最快可以跑到400.2Mhz;
感觉改进一下代码,可能跑得更快。

5. 补充:双符号法

在这里插入图片描述
嗯,百度百科的词条是这么解释双符号法的,笔者认为这个可以从计算机原理的角度来解释二进制数据的加减、溢位过程。
但从Verilog实现的角度来看,还是直接进行符号判断、然后原码加减来的简单暴力点;如果要用双符号法,还得增加一个原码与补码转换机制。所以,笔者直接偷了懒,感兴趣的朋友可以尝试下。


总结

  • 关于浮点数的、针对性的学习与研究可能会随着本篇文章的发布告一段落了。
  • 不过,依旧欢迎大家阅读本文,并且在评论区参与讨论,共同进步。
  • 接下来呢,会继续学习FPGA,想进一家还不错的FPGA原厂,做自己喜欢的事情。
  • 最后,放几个笔者在查阅资料时看得到的不错的链接,供大家参考、学习。
    1 https://www.cnblogs.com/fsjohnhuang/p/5109766.html
    2 https://www.bilibili.com/video/BV1gR4y1K7By?p=16&vd_source=25f1258778282ed0831c1ab9a29c1e69
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/1014706
推荐阅读
相关标签
  

闽ICP备14008679号