重要: 任意精度定点类型要求代码中包含 ap_fixed.h 头文件。
C++ 函数可利用 Vitis HLS 所含的任意精度定点类型。下图汇总了这些定点类型的基本功能:
- 字型可采用有符号 (
ap_fixed
) 或无符号 (ap_ufixed
) 类型。 - 可定义任意大小
W
的字。 - 小数点 I 前的位数还可定义代码字的小数位数
W-I
(在下图中以B
来表示)。 - 可选择舍入或量化 (
Q
) 类型。 - 可选择上溢行为(
O
和N
)。
图 1. 任意精度定点类型
提示: 在上图中,整数值 (
I
) 指定了二进制小数点左侧的整数位数(包括符号位)。在使用 ap_[u]fixed
类型的超大阵列时以及在 C 语言仿真期间,任意精度定点类型会占用更多存储器。
使用定点类型的优势包括:
- 支持轻松显示小数。
- 当变量包含的整数位数和小数位数不同时,可处理小数点的对齐。
- 当小数位数太少无法准确表示结果精度时,有多个选项可用于处理舍入方式。
- 当结果大于可显示的整数位数时,有多个选项可用于处理变量上溢方式。
请查看如下示例中的代码,其中汇总了各项属性。首先,包含 ap_fixed.h 头文件。随后使用 typedef
语句定义 ap_fixed
类型:
- 10 位输入:8 位整数值和 2 个小数位。
- 6 位输入:3 位整数值和 3 个小数位。
- 用于累加的 22 位变量:17 位整数值和 5 个小数位。
- 用于表示结果的 36 位变量:30 位整数值和 6 个小数位。
函数不含用于管理执行运算后的小数点对齐的代码。对齐自动执行。
以下代码样本显示的类型为 ap_fixed
。
#include "ap_fixed.h"
typedef ap_ufixed<10,8, AP_RND, AP_SAT> din1_t;
typedef ap_fixed<6,3, AP_RND, AP_WRAP> din2_t;
typedef ap_fixed<22,17, AP_TRN, AP_SAT> dint_t;
typedef ap_fixed<36,30> dout_t;
dout_t cpp_ap_fixed(din1_t d_in1, din2_t d_in2) {
static dint_t sum;
sum += d_in1;
return sum * d_in2;
}
通过使用 ap_(u)fixed
类型,C++ 仿真可保证位精度。快速仿真可确认算法及其准确性。综合后,RTL 会显示完全相同的位精确行为。
在此代码中可为任意精度定点类型自由赋予字面值。如以上示例中使用的测试激励文件中所示(请参阅以下示例),其中已声明 in1
和 in2
的值,并对其赋予常量值。
赋予含运算符的字面值时,字面值必须首先强制转换为 ap_(u)fixed
类型。否则,C 语言编译器和 Vitis HLS 会将字面值解释为整数或 float/double
类型,并且可能无法找到合适的运算符。如以下示例所示,在 in1 = in1 + din1_t(0.25)
的赋值中,字面值 0.25 强制转换为 ap_fixed
类型。
#include <cmath>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <cstdlib>
using namespace std;
#include "ap_fixed.h"
typedef ap_ufixed<10,8, AP_RND, AP_SAT> din1_t;
typedef ap_fixed<6,3, AP_RND, AP_WRAP> din2_t;
typedef ap_fixed<22,17, AP_TRN, AP_SAT> dint_t;
typedef ap_fixed<36,30> dout_t;
dout_t cpp_ap_fixed(din1_t d_in1, din2_t d_in2);
int main()
{
ofstream result;
din1_t in1 = 0.25;
din2_t in2 = 2.125;
dout_t output;
int retval=0;
result.open(result.dat);
// Persistent manipulators
result << right << fixed << setbase(10) << setprecision(15);
for (int i = 0; i <= 250; i++)
{
output = cpp_ap_fixed(in1,in2);
result << setw(10) << i;
result << setw(20) << in1;
result << setw(20) << in2;
result << setw(20) << output;
result << endl;
in1 = in1 + din1_t(0.25);
in2 = in2 - din2_t(0.125);
}
result.close();
// Compare the results file with the golden results
retval = system(diff --brief -w result.dat result.golden.dat);
if (retval != 0) {
printf(Test failed !!!\n);
retval=1;
} else {
printf(Test passed !\n);
}
// Return 0 if the test passes
return retval;
}