当试图在Vitis HLS工具中编写高效的C++时,你需要谨慎使用模数运算符。这是因为C = A % B等同于C = A - B * (A / B)。换句话说,模运算符在功能上等同于三种操作。
因此,使用模数运算符的代码会在Vitis HLS中引入一个很长的延迟。
尽管在某些情况下,除了使用模运算符之外没有其他的选择,但在许多情况下,可以对代码进行重组,这样就不需要模运算符了。
在Vitis HLS中,当调用模运算时,找到运算符的名称--SREM / UREM。
1) 对于整数数据类型:char, unsigned char, short, unsigned short, int, unsigned, long, unsigned long
#pragma HLS bind_op variable = ab op = srem
ab = b %ab;
#pragma HLS bind_op variable = ab op = urem
ab = (uint32_t)ab % (uint32_t)a;
2) 对于固定数据类型: ap_fixed, ap_ufixed
我们应该首先设置hls_math库。
#include
#pragma HLS bind_op variable = ab op = srem
ab = remainder(b, ab)。
我们可以在时间表查看器中找到带有srem运算符名称的运算符,并看到延迟非常高。
其他会调用UREM/SREM运算符的情况。
1)当应用阵列分区或阵列重塑的奇数因素时。
尽管作为设计者,我们知道一个数组可以被3整除,但编译器无法确认,只能调用modulo操作来分割和重塑数组。
#pragma HLS ARRAY_RESHAPE variable = buffer cyclic factor = 3 dim = 1
解决此问题最有效的方法是使因子幂为 2。这在 Vitis HLS 用户指南中也有推荐。
对于因子必须是 3 次方的场景。如果不是很大的循环和数组,我们可以手动计算数组索引并展开循环。
2) 任何其他的场景,我们看到UREM/SREM操作者在时间表视图中被抓住。
请考虑在代码里面是否有需要返回除法的余数或有符号的余数的操作,并考虑如何优化它。
这个问题将在未来的Vitis HLS版本中得到解决。然而,我们仍然建议在调用模子操作时要三思而后行,因为除法和余数操作在FPGA设计中的实现都是非常昂贵的。