XAPP599-Vivado HLS的浮点设计

本文深入探讨了使用Vivado HLS工具进行浮点设计的基础知识,涵盖了IEEE-754标准、数学库函数的正确使用、常量传播与折叠、浮点运算的并行性与资源共享,以及如何在C/C++项目中集成hls_math库以确保软件与硬件行为一致。文章还介绍了如何控制资源使用、理解浮点运算的顺序效应,以及如何在验证阶段设置合理的误差阈值。

  Vivado HLS工具支持C/C ++浮点和双精度数据类型,它们基于IEEE-754标准定义的单、双精度二进制浮点格式。浮点数值格式由于精度有限不能表示每个实数。

计算不匹配的来源包括

  • 舍入误差的累积,舍入误差对运算的顺序很敏感
  • FPU支持的扩展精度对舍入结果的影响,例如x87 80位格式;SIMD (SSE等)指令与x87的行为不同
  • 库函数近似,例如浮点三角函数
  • 许多浮点字面值只能近似表示,即使是有理数
  • 传播常数/折叠效果
  • subnormals的处理
    (subnormals有时用于表示比普通浮点格式所能表示的数字小的数字。例如,在单精度格式中,最小的标准浮点值是2-126。但是,当支持subnormals时,尾数位用于表示具有固定指数值2-127的定点数。)
    正规数、次正规数 见https://www.cnblogs.com/HDK2016/p/10506083.html
    (把常量表达式的值求出来作为常量嵌在最终生成的代码中,这种优化叫做常量折叠(constant folding))
    (常数传播(constant propagation)都是编译器最佳化技术,被使用于现代的编译器中。)

使用Vivado HLS工具进行浮点设计的基础知识

尽管可以使用CORE Generator工具为自定义精度浮点类型生成这些内核,但是Vivado HLS工具仅生成IEEE-754标准描述的内核的单精度和双精度版本。
基于浮点运算符内核的软件与硬件生成的结果可能(微小)差异的来源是,这些内核通过“冲洗为零”来处理次标准输入(subnormal inputs),也就是说,遇到这种情况时将它们替换为0.0。

在基于ANSI / ISO-C的项目中使用<math.h>

要在基于ANSI/ISO-C的项目中使用受支持的标准数学库函数,math.h头文件应该包含在所有调用它们的源文件中。基函数用于操作(并返回)双精度值,例如,double sqrt(double)。
  大多数函数的单精度版本都在函数名后面附加了一个“f”,例如,float sqrtf(float)、float sinf(float)和float ceilf(float)。记住这一点很重要,因为如果不这样做,即使参数和返回变量是单精度的,也会实现更大的(在FPGA资源中)双精度版本,而且会使用额外的资源并增加计算的延迟。

在ANSI/ISO-C中工作时的另一个考虑是,当将代码作为软件编译和运行时(包括RTL co-simulation期间的C测试台端),使用的算法与在HLS生成的RTL中实现的算法不同。在软件中,调用GCC libc函数,在硬件端使用Vivado HLS工具math library代码。这可能导致两者之间的位级不匹配(bit-level mismatches ),当两个结果可能非常接近实际答案(在分析意义上)时.

Example 3: Unintended Use of Double-Precision Math Function:
// Unintended consequences?
#include <math.h>
float top_level(float inval)
{
   
   
	return log(inval); // double-precision natural logarithm
}

这个示例生成了一个RTL实现,它将输入转换为双精度格式,以双精度计算自然对数,然后将结果转换为单精度输出

Example 4: Explicit Use of Single-Precision Math Function:
// Be sure to use the right version of math functions...
#include <math.h>
float top_level(float inval)
{
   
   
	return logf(inval); // single-precision natural logarithm
}

return logf(inval); // single-precision natural logarithm 因为调用了对数函数的单精度版本,所以该版本在RTL中实现,不需要进行输入/输出格式转换

Using in C++ Projects

使用C ++设计时,获得对标准数学库的支持的最直接方法是在所有调用其函数的源文件中包括<cmath>系统头文件。
这个头文件提供了重载的基(双精度)函数的版本,以接受参数并在std名称空间中返回单精度(浮点)值。
对于要使用的单精度版本,必须通过作用域解析操作符(::)或通过使用using指令导入整个名称空间,将std名称空间包含在范围内。

C++ 的基函数对于单精度浮点、双精度浮点使用重载的方式。在使用单精度时方法如下
std:: 或 using namespace std

Example 5: Explicit Scope Resolution:
// Using explicit scope resolution
#include <cmath>
float top_level(float inval)
{
   
   
	return std::log(inval); // single-precision natural logarithm
}

Example 6: Exposing Contents of a Namespace to File Scope:
// import std:: namespace
#include <cmath>
using namespace std;
float top_level(float inval)
{
   
   
	return log(inval); // single-precision natural logarithm
}

  当在由Vivado HLS工具合成的代码中使用cmath的函数时,软件运行的代码与RTL实现之间的结果可能会不同,因为使用了不同的近似算法。
因此,可以访问用于合成RTL的算法,以用于C ++建模。?

  当验证HLS的C++代码,以及使用C++的测试平台对RTL进行co-simulating时,建议HLS源码调用相同的数学库,而测试代码使用 C++标准库生成参考值。这为开发期间的HLS模型和数学库提供了额外的验证。

  为了遵循这种方法,Vivado HLS头文件<hls_math.h>应该只包含在任何要综合的RTL源文件中。对于验证HLS设计的源文件,如测试程序和支持代码,应该包括系统头文件。
hls_math头文件中的函数是HLS::名称空间的一部分。
对于要为软件建模/验证而编译的HLS版本,请对每个函数调用使用hls ::作用域解析。

NOTE:在使用c++标准数学库调用时,不建议导入hls:: namespace(通过’using namespace hls’),因为这可能导致在hls期间出现编译错误。
示例7a说明了这种用法

测试程序7a使用标准的c++数学库
Example 7a: Test Program Uses Standard C++ Math Library:
// Contents of main.cpp - The C++ test bench
#include <iostream>
#include <cmath>
using namespace std;
extern float hw_cos_top(float);
int main(void)
{
   
   
	int mismatches = 0;
	for (
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值