在 Vitis 工具流程中,Vitis HLS 能够自动将 m_axi
接口端口的大小调整为 512 位,以改善突发访问能力。但是,端口宽度自动调整仅支持标准 C 语言数据类型和 2 的幂值 struct
大小,其中对指针分配拓宽后期望的字节大小。如果该工具无法自动拓宽此端口,那么您可通过使用矢量或任意精度 (AP) 作为该端口的数据类型来手动更改端口宽度。
重要: 接口上的结构体会阻止端口的自动拓宽操作。您必须将结构体拆分为多个独立元素才能启用该功能。
Vitis HLS 使用以下 2 条命令来自动调整端口宽度:
-
syn.interface.m_axi_max_widen_bitwidth=<N>
:指令该工具将 M-AXI 接口上的突发自动拓宽至指定的位宽。<N> 的值必须为 2 的幂(介于 0 到 1024 之间)。 -
syn.interface.m_axi_alignment_byte_size=<N>
:请注意,突发拓宽还需要强大的对齐属性。假定映射到m_axi
接口的指针至少对齐到所提供的宽度(以字节为单位,值为 2 的幂)。这样有助于自动进行突发拓宽。
在 Vitis 内核流程中,默认通过以下命令启用端口宽度自动调整功能:
syn.interface.m_axi_max_widen_bitwidth=512
syn.interface.m_axi_alignment_byte_size=64
在 Vivado IP 流程中,默认禁用此功能:
syn.interface.m_axi_max_widen_bitwidth=0
syn.interface.m_axi_alignment_byte_size=1
仅当工具可看到突发访问时,端口宽度自动调整功能才能调整端口大小。因此,突发所需的所有前置条件(如 AXI 突发传输 中所述)都必须得到满足后才能调整端口大小。这些前置条件包括:
- 必须按单调递增访问顺序(访问的存储器位置和访问时间两方面都是如此)。不能访问位于先前访问的两处存储器位置之间的存储器位置,即没有重叠。
- 从全局存储器进行访问时使用的模式应采用顺序访问模式,并具有下列附加要求:
- 顺序访问需在原语类型或非矢量的 2 的幂大小的聚合类型上进行
- 顺序访问的起始位置需对齐到拓宽后的字大小
- 顺序访问的长度需被拓宽因子整除
以下代码示例在后续计算过程中使用:
vadd_pipeline:
for (int i = 0; i < iterations; i++) {
#pragma HLS LOOP_TRIPCOUNT min = c_len/c_n max = c_len/c_n
// Pipelining loops that access only one variable is the ideal way to
// increase the global memory bandwidth.
read_a:
for (int x = 0; x < N; ++x) {
#pragma HLS LOOP_TRIPCOUNT min = c_n max = c_n
#pragma HLS PIPELINE II = 1
result[x] = a[i * N + x];
}
read_b:
for (int x = 0; x < N; ++x) {
#pragma HLS LOOP_TRIPCOUNT min = c_n max = c_n
#pragma HLS PIPELINE II = 1
result[x] += b[i * N + x];
}
write_c:
for (int x = 0; x < N; ++x) {
#pragma HLS LOOP_TRIPCOUNT min = c_n max = c_n
#pragma HLS PIPELINE II = 1
c[i * N + x] = result[x];
}
}
}
}
上述代码的自动最优化宽度需通过 3 个步骤来执行:
- 该工具检查 read_a 循环中的访问模式数量。每个循环迭代期间有一次访问,因此最优化判定接口位宽为 32= 32 *1(整数变量位宽 * 访问次数)。
- 该工具会尝试使用以下表达式来达到
config_interface -m_axi_max_widen_bitwidth 512
指定的默认最大值:length = (ceil((loop-bound of index inner loops) * (loop-bound of index - outer loops)) * #(of access-patterns))
- 在上述代码中,该工具支持非完美循环嵌套。如果 a 和 b 捆绑到相同端口,那么由于冲突,该工具将不会在 a 和 b 上扩展突发。如果 a 和 b 捆绑到不同端口,那么该工具将在 a 和 b 上将突发扩展至外层循环。因此,该公式将缩短为:
length = (ceil((loop-bound of index inner loops)) * #(of access-patterns))
或者:length = ceil(128) *32 = 4096
- 在上述代码中,该工具支持非完美循环嵌套。如果 a 和 b 捆绑到相同端口,那么由于冲突,该工具将不会在 a 和 b 上扩展突发。如果 a 和 b 捆绑到不同端口,那么该工具将在 a 和 b 上将突发扩展至外层循环。因此,该公式将缩短为:
- 计算所得是否为 2 的幂?如果是,那么长度将限为
syn.interface.m_axi_max_widen_bitwidth
所指定的宽度。
使用端口宽度自动调整功能有利有弊,您需在使用时审慎考量。此功能特性改善的是访问吞吐量,而不是数据类型大小。它还会添加更多必要资源,以缓冲巨型矢量,并且可能需要将数据相应转换为数据路径大小。