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模擬階段就能檢測出這種誤差呢?