阵列分区 - 2023.2 简体中文

Vitis 高层次综合用户指南 (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 简体中文

阵列可分区到块中或者分区到其各元素中。在某些情况下,Vitis HLS 会将阵列分区到各独立元素中。这可使用自动分区配置设置来加以控制。将阵列分区到多个块中时,单一阵列将作为多个 RTL RAM 块来实现。分区到元素中时,每个元素都作为 RTL 中的 1 个寄存器来实现。在这 2 种情况下,分区允许并行访问更多元素,并且有助于提升性能;设计将在性能与实现性能所需的 RAM 或寄存器数量之间加以权衡取舍。

以下消息显示了函数流水打拍时常见的问题:

INFO: [SCHED 204-61] Pipelining loop 'SUM_LOOP'.
WARNING: [SCHED 204-69] Unable to schedule 'load' operation ('mem_load_2', 
bottleneck.c:62) on array 'mem' due to limited memory ports.
WARNING: [SCHED 204-69] The resource limit of core:RAM:mem:p0 is 1, current 
assignments: 
WARNING: [SCHED 204-69]     'load' operation ('mem_load', bottleneck.c:62) on array 
'mem',
WARNING: [SCHED 204-69] The resource limit of core:RAM:mem:p1 is 1, current 
assignments: 
WARNING: [SCHED 204-69]     'load' operation ('mem_load_1', bottleneck.c:62) on array 
'mem',
INFO: [SCHED 204-61] Pipelining result: Target II: 1, Final II: 2, Depth: 3.

在此示例中,Vitis HLS 声明它无法达成指定的启动时间间隔 (II) 值 1,因为它受存储器端口所限,无法在存储器上调度 load(读取)操作 (mem_load_2)。以上消息指出了第 62 行上的 mem_load 操作所使用的“core:RAM:mem:p0 is 1”的资源限制。块 RAM 的第 2 个端口同样仅含 1 项资源,该资源同样供 mem_load_1 操作使用。由于存在此存储器端口争用,Vitis HLS 报告的最终 II 为 2,而不是所期望的值 1。

此问题通常是由阵列所导致的。如果阵列不属于顶层函数的接口,则会作为包含最多 2 个数据端口块 RAM 来实现。这可能限制读写(或加载/存储)密集型算法的吞吐量。通过将该阵列(单一块 RAM 资源)拆分为多个更小的阵列(多个块 RAM)从而有效增加端口数量,即可改善带宽。

阵列可使用 ARRAY_PARTITION 指令来进行分区。Vitis HLS 可提供 3 种类型的阵列分区,如下图所示。这 3 种分区样式分别是:

block
原始阵列分割为原始阵列的连续元素块(大小相同)。
cyclic
原始阵列分割多个大小相同的块,这些块交织成原始阵列的元素。
complete
默认操作是将阵列按其独立元素进行拆分。这对应于将存储器解析为寄存器。
图 1. 阵列分区

对于 blockcyclic 分区,factor 选项可指定要创建的阵列数量。在前图中,使用因子 2,即将阵列分割为 2 个更小的阵列。如果阵列的元素数量并非该因子的整数倍,那么最后一个阵列所含元素数量较少。

对多维阵列进行分区时,dimension 选项可用于指定对哪个维度进行分区。下图显示了使用 dimension 选项对以下代码示例进行分区的方式:

void foo (...) {
 int  my_array[10][6][4];
   ...   
}

此图中的示例演示了如何通过对 dimension 3 进行分区来生成 4 个独立阵列,以及如何对 dimension 1 进行分区以生成 10 个独立分区。如果针对 dimension 指定 0,则将对所有维度进行分区。

图 2. 对阵列维度进行分区