HLS Math Library:csim和C/RTL co-sim仿真不一致?(1)

  • 2020 年 3 月 12 日
  • 笔记

Vivado HLS提供了数学库(需要添加头文件hls_math.h)。可以认为这个库是对标准C(math.h)和C++(cmath.h)中的函数提供了可综合的版本。该库中的所有函数既支持单精度浮点、双精度浮点和半精度浮点,同时,某些函数还支持定点数据类型。

HLS数学库中的函数是可综合的位近似(bit-approximate)的函数。所谓位近似,其实反映了函数的实现精度。这里的精度是指HLS库中的函数与标准库(math.h或cmath.h)中的函数的数值差异。通常采用ULP(Unit of Least Precision)来度量,ULP的典型值为1~4。这种精度上的差异既会影响C仿真,也会影响C/RTL协同仿真。

我们来看一个典型案例,头文件内容和函数定义部分分别如下图所示。不难看出,这里使用了C++中的cmath库,因此其中的sinf、cosf和sqrtf都来自这个库。

为了观察C仿真的结果和C/RTL协同仿真的结果,Testbench中特地将res写入到文件res.dat中保存。这样,C仿真时会生成res.dat文件,位于工程目录下的build文件夹里,具体路径如下所示。

solution1csimbuild

同样地,C/RTL协同仿真时也会生成res.dat,位于工程目录下的wrapc_pc文件夹里,具体路径如下所示。

solution1simwrapc_pc

比较这两个文件可以发现,C仿真的结果和C/RTL协同仿真的结果部分值是不一致的,如下图所示。

也可以在C/RTL协同仿真生成的波形中查看到结果,如下图所示。

可以看到小数部分是有差异的,用户要决定这种差异是否是可以接受的。为什么会有这种差异?其实就是因为C仿真时用的函数来源于cmath.h中,而C/RTL协同仿真用的是HLS数学库中的函数综合后的结果,存在精度损失,也就是前文所说的ULP。

一种更巧的方法是在Testbench中能够检查到这些精度损失的值,同时检查精度损失是否在可接受范围内,这就需要定义误差值。误差是期望值与真实值之差。这里期望值由cpp_math_sw决定,如下图所示。

cpp_math_sw和cpp_math的内容完全一样,但cpp_math_sw是作为testbench文件输入给VivadoHLS的,如下图所示。

紧接着,我们定义误差,并将不一致的结果写入文件,如下图所示。其中,fp_strmo为ofstream定义的输出文件流,AbsError为用户定义的可接受的绝对误差,diff则是实际误差值。

C仿真时,cpp_math和cpp_math_sw的输出结果是一致的。但在C/RTL协同仿真时,由于cpp_math中的函数采用了HLS数学库中的可综合函数,从而引入了误差。上述Testbench可以检查到误差超过允许范围之内的输入值,并将其写入文件中。最终生成的文件如下图所示。

那么,是否还有其他方法,在C仿真阶段就能检测出这种误差呢?