- 参考
1. 空间复杂度
- 程序的两个衡量指标:时间复杂度(时钟频率)和空间复杂度(资源)。
- 时间复杂度体现在循环语句,空间复杂度体现在数组上。
2. Partition展开操作
-
为什么Partition可以提升性能
- HLS将数组映射到Memory中。如果数组是作为顶层函数的形参,那么就会被综合成memory的接口;如果数组在设计内部,会根据数组大小及优化方式被综合成移位寄存器(大小<1024)/BRAM,LUTRAM,UltraRAM。
- 存在的问题
-
当数组作为存储器来实现时,存储器端口的数量会限制对数据的访问,可能导致流水线失败。
-
假设一数组用单端口RAM实现,功能:扫描数组,依次访问连续三个地址的数据求和;此时每个周期只能进行一次读/写,无法实现流水线。
- 若想实现吞吐量为1,需要预读取数据,并手动对数据访问流水打拍。
dout_t array_mem_perform(din_t mem[N]) { din_t tmp0, tmp1, tmp2; dout_t sum=0; int i; tmp0 = mem[0]; tmp1 = mem[1]; SUM_LOOP:for (i = 2; i < N; i++) { tmp2 = mem[i]; sum += tmp2 + tmp1 + tmp0; tmp0 = tmp1; tmp1 = tmp2; } return sum; }
-
即使使用双端口的RAM,每个时钟周期可进行两次访问,
-
- 可以不用更改设计,HLS可以使用优化指令:Array Partition、Array Reshape.
-
Array Partition 有3个type可选
- block、cyclic和complete
- factor为n,将原数组等分成n个小的数组,每个数组的长度 = 原长度/n。
- 以一维数组为例,如下图
#param HLS ARRAY_PARTITION variable=weight_group block factor = 4 dim = 1 #param HLS ARRAY_PARTITION variable=weight_group cyclic factor = 4 dim = 1 #param HLS ARRAY_PARTITION variable=weight_group complete dim = 1
- block、cyclic和complete
-
对多维数组采用Partition展开
3. 数组的映射和重组
- ARRAY_MAP
- 将多个较小的数组映射成一个数组,以减少内部资源用量。
- Horizontal:直接将多个数组拼接在一起,数组的长度等于N+M,数组的宽度为N和M的最大数组宽度。
- Vertical:对于数组的每一个元素进行拼接,数组的长度等于N/M中最大的长度。
- 命令介绍:其中variable是被map的数组;instance是map后的数组;mode可选horizontal/vertical;offset仅horizontal可选,int为合并的数组相较于0的偏移量。
- 注:命令相关例子和用法可以查看Xilinx官网,有较为全面的解释。
#pragma HLS array_map variable=<name> instance=<instance> <mode> offset=<int> //example 将C和D合并成CD #pragma HLS array_map variable=C instance=CD vertical #pragma HLS array_map variable=D instance=CD vertical
- ARRAY_RESHAPE
- 两步: