例16:使用“RESOURCE”指令设定浮点运算器内核变量
// Floating-point accumulator
float top(float x[32])
{
#pragma HLS interface ap_fifo port=x
float acc = 0;
for (int i = 0; i < 32; i++) {
#pragma HLS pipeline
#pragma HLS resource variable=acc \
core=FAddSub_nodsp
acc += x;
}
return acc;
}
关于RESOURCE 指令的详细使用介绍以及可用的内核清单,敬请参阅《Vivado HLS 用户指南》 UG902[7]。
验证浮点计算的结果
用不同方式运行相同计算所得的浮点结果之间存在数位级(或者更高)的差异,这里面的原因有很多。误差会发生的位置也不同,包括不同的近似算法、计算顺序的重新排序导致的舍入差异、以及次正常值的处理(此时浮点运算器内核清零)。
一般来说,两个浮点值的比较结果(特别是相等比较),可能造成误导。两个被比较的值可能只在“最后一位”(ULP;二进制格式中的作用最小的位)存在差异,从而导致极小的相对误差,造成“==”运算符号返回假值。例如,在使用单精度浮点格式的情况下,如果两个操作数都非零(也非次正常值),1ULP 的差异代表0.00001% 的相对误差。因此,在比较浮点数时,应避免使用“==”和“! =”运算符。要检查两个值是否“足够接近”,可以使用可接受误差阈值。
在大多数情况下,设置可接受的ULP 或相对误差级就可以,比设置绝对误差(或者“ε”)阈值要好。但是如果需要比较的值中有一个是零(0.0),这种方法就失效了。如果比较的值中有一个是恒零值或可以产生恒零值,那么就需要使用绝对误差阈值。下面的示例代码提供了一种用于比较两个浮点数近似相等的方法,便于您设置ULP 和绝对误差限值。这个函数可以用在C/C++“测试台”代码中,用于验证HSL 源代码的修改情况,并验证Vivado HLS 工具的RTL 协同仿真。您还可以在HLS 的实现代码中使用类似的方法。
例17:用于测试浮点值近似相等的C 语言代码
// Create a union based type for easy access to
// binary representation
typedef union {
float fval;
unsigned int rawbits;
} float_union_t;
bool approx_eqf(
float x, float y,
int ulp_err_lim, float abs_err_lim
)
{
float_union_t lx, ly;
lx.fval = x;
ly.fval = y;
// ULP based comparison is likely to be meaningless
// when x or y is exactly zero or their signs
// differ, so test against an absolute error
// threshold this test also handles (-0.0 == +0.0),
// which should return true. N.B. that the
// abs_err_lim must be chosen wisely, based on
// knowledge of calculations/algorithms that lead
// up to the comparison. There is no substitute for
// proper error analysis when accuracy of results
// matter.
if (((x == 0.0f) ^ (y == 0.0f)) ||
(__signbit(x) != __signbit(y))) {
return fabs(x - y) <= fabs(abs_err_lim);
}
// Do ULP base comparison for all other cases
return abs((int)lx.rawbits -
(int)ly.rawbits) <= ulp_err_lim;
}
关于应该将ULP 和绝对误差阈值设置在什么水平这个问题没有唯一的答案,因为设置会因设计而异。相对于基准结果而言,复杂的算法可能会在输出中累加更多ULP 误差。其他关系运算符也可能会误导结果。例如,在测试某值是否小于(或者大于)另一值时,误差仅有几个ULP,这种情况下是否可以做出合理的结论?我们可以将上面提供的函数与小于/ 大于比较法结合使用,用来判别含糊的结果。
强大的功能
在赛灵思FPGA 上用C/C++ 源代码轻松实现浮点算法硬件(RTL 代码)是Vivado HLS 工具所具备的一种强大功能。但浮点算法的使用不管是从软件的角度、硬件的角度还是混合的角度都并非像看上去那么直观。IEEE-754 标准二进制浮点格式的非精确性给验证计算结果带来难度。另外,设计人员在C/C++ 源代码层面以及应用HLS 优化指令的时候,都必须额外小心,才能在FPGA 资源利用和设计性能方面获得理想的结果。
关于更多实际操作的建议,请参阅“Vivado 高层次综合产品” 页:http://www.xilinx.com/products/d ... ion/esl-design/hls/ ;Vivado 视频辅导:http://www.xilinx.com/training/vivado;以及“浮点运算器产品”页:http://www.xilinx.com/products/i ... rty/FLOATING_PT.htm 。
参考资料:
1. 用于二进制浮点算法的ANSI/IEEE 标准,ANSI/IEEE 标准754-2008;IEEE-754
2. PG060,LogiCORE IP 浮点运算器6.1 版产品指南
3. http://randomascii.wordpress.com/category/floating-point/
4. http://docs.oracle.com/cd/E19957-01/8063568/ncg_goldberg.html
5. http://www.lahey.com/float.htm
6. Adam Taylor,《FPGA 数学基础知识》,赛灵思期刊第80 期,http://issuu.com/xcelljournal/docs/xcell80
7. UG902,《Vivado 设计套件用户指南:高层次综合2012.2版》;UG871,《Vivado 设计套件辅导:高层次综合V2012.2 版》