当循环包含变量边界时,将禁止执行 Vitis HLS 可应用的某些最优化操作。在以下代码示例中,循环边界由顶层输入驱动的变量 width
来判定。在此情况下,循环被视为包含变量边界,因为 Vitis HLS 无从知晓循环将何时完成。
#include "ap_int.h"
#define N 32
typedef ap_int<8> din_t;
typedef ap_int<13> dout_t;
typedef ap_uint<5> dsel_t;
dout_t code028(din_t A[N], dsel_t width) {
dout_t out_accum=0;
dsel_t x;
LOOP_X:for (x=0;x<width; x++) {
out_accum += A[x];
}
return out_accum;
}
尝试对上述示例中的设计进行最优化时,会报告由变量循环边界造成的问题。变量循环边界的第一个问题是阻止 Vitis HLS 判定循环时延。Vitis HLS 可判定完成一次循环迭代所需的时延,但由于它无法静态判定变量宽度的精确值,因此无从知晓执行的迭代次数,因而无法报告循环时延(即完全执行循环的每次迭代的周期数)。
存在变量循环边界时,Vitis HLS 会将时延报告为问号 (?
) 而不是使用精确值。以下显示了完成上述示例的综合后的结果。
+ Summary of overall latency (clock cycles):
* Best-case latency: ?
* Worst-case latency: ?
+ Summary of loop latency (clock cycles):
+ LOOP_X:
* Trip count: ?
* Latency: ?
变量循环边界的另一个问题是设计性能未知。解决此问题的方法是使用 pragma HLS loop_tripcount 或 set_directive_loop_tripcount。
tripcount
指令允许为循环指定 tripcount
最小值和/或最大值。tripcount
表示循环的迭代次数。如果对第 1 个示例中的 LOOP_X
应用 tripcount
最大值 32,那么报告将更新为显示如下内容:
+ Summary of overall latency (clock cycles):
* Best-case latency: 2
* Worst-case latency: 34
+ Summary of loop latency (clock cycles):
+ LOOP_X:
* Trip count: 0 ~ 32
* Latency: 0 ~ 32
用户为 tripcount
指令提供的值仅用于报告。tripcount
值允许 Vitis HLS 显示报告中的数值,并支持与来自其它解决方案的报告进行对比。要将此循环边界信息用于综合,必须更新 C/C++ 语言代码。
要对第 1 个示例进行最优化以降低启动时间间隔,请执行下列后续步骤:
- 展开循环,允许并行执行累加。
- 通过单一存储器端口对阵列输入进行分区或者限制并行累加。
应用这些最优化操作后,Vitis HLS 的输出会高亮显示变量边界循环的最显著的问题:
@W [XFORM-503] Cannot unroll loop 'LOOP_X' in function 'code028': cannot completely
unroll a loop with a variable trip count.
由于变量边界循环无法展开,因此不仅阻止应用展开 (unroll) 指令,而且还会阻止循环上层的层级的流水打拍操作。
对于含变量边界的循环,解决方案是通过循环内部的条件执行来将循环迭代次数设置为固定值。可重写变量循环边界示例中的代码,如以下代码示例所示。此处循环边界显式设置为变量宽度的最大值,循环主体则以有条件方式来执行:
#include "ap_int.h"
#define N 32
typedef ap_int<8> din_t;
typedef ap_int<13> dout_t;
typedef ap_uint<5> dsel_t;
dout_t loop_max_bounds(din_t A[N], dsel_t width) {
dout_t out_accum=0;
dsel_t x;
LOOP_X:for (x=0; x<N; x++) {
if (x<width) {
out_accum += A[x];
}
}
return out_accum;
}
以上示例中的 for 循环 (LOOP_X
) 可展开。由于此循环的上限固定,因此 Vitis HLS 知晓需创建的硬件数量。在 RTL 设计中包含 N(32)
份循环主体副本。每份循环主体副本都包含与之关联的条件逻辑,并根据变量宽度值来执行。请参阅 Github 上的 Vitis-HLS-Introductory-Examples/Modeling/variable_bound_loops 以获取示例。