阵列 - 2021.2 Chinese

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

Document ID
UG1399
Release Date
2021-12-15
Version
2021.2 Chinese

在探讨编码样式对综合后的阵列实现的影响之前,有必要探讨阵列可能引发问题(即使在综合之前)的情况,例如,在 C/C++ 仿真期间。

如果您指定的阵列过大,可能导致 C/C++ 仿真因存储器不足而失败,如以下示例所示:

#include "ap_int.h"
  
  int i, acc; 
  // Use an arbitrary precision type
  ap_int<32>  la0[10000000], la1[10000000]; 
  
  for (i=0 ; i < 10000000; i++) { 
      acc = acc + la0[i] + la1[i]; 
  } 

仿真可能因存储器不足而失败,因为阵列置于存储器中存在的栈上,而不是置于由操作系统管理并且可使用本地磁盘空间来扩展的堆上。

这可能导致设计运行时出现存储器不足,某些问题还会提高出现此问题的概率:

  • 在 PC 上,可用存储器通常小于大型 Linux 系统,并且可用存储器可能进一步减少。
  • 而使用如上所示任意精度类型则可能使此问题更严重,因为这些类型所需存储器比标准 C/C++ 类型所需存储器更多。
  • 使用 C/C++ 中的更复杂的定点任意精度类型可能还会提高设计出现存储器不足问题的概率,因为各类型所需存储器更多。

增加 C/C++ 代码开发中的存储器资源的标准方法是使用连接器选项增大栈大小,例如以下选项将栈大小显式设置为 -z stack-size=10485760。在 Vitis HLS 中可转至Project Settings > Simulation > Linker flags来应用此类选项,或者还可作为 Tcl 命令的选项来提供此类选项:

csim_design -ldflags {-z stack-size=10485760} 
cosim_design -ldflags {-z stack-size=10485760} 

在某些情况下,机器可能没有足够存储器,增大栈大小无效。

解决方案是使用动态存储器分配执行仿真,但使用固定大小的阵列执行综合,如以下示例所示。这意味着此操作所需存储器将在由操作系统管理并可使用本地磁盘空间来扩展的堆上进行分配。

对代码进行此类更改并非理想方式,因为仿真的代码将不同于综合的代码,但有时这是推动设计进程继续进行的唯一途径。如果采用此方法,请务必确认 C/C++ 测试激励文件涵盖阵列访问的各方面。由 cosim_design 执行的 RTL 仿真将验证存储器访问是否正确。

#include "ap_int.h"
  
  int i, acc; 
#ifdef __SYNTHESIS__
  // Use an arbitrary precision type & array for synthesis
  ap_int<32>  la0[10000000], la1[10000000]; 
#else 
  // Use an arbitrary precision type & dynamic memory for simulation
 ap_int<int32> *la0 = malloc(10000000  * sizeof(ap_int<32>));
 ap_int<int32> *la1 = malloc(10000000  * sizeof(ap_int<32>));
#endif
  for (i=0 ; i < 10000000; i++) { 
      acc = acc + la0[i] + la1[i]; 
  } 
注释: __SYNTHESIS__ 宏仅限在要综合的代码中使用。请勿在测试激励文件中使用该宏,因为 C/C++ 语言仿真或 C/C++ RTL 协同仿真不会遵循其指示进行操作。

综合后,阵列通常作为存储器(RAM、ROM 或 FIFO)来实现。顶层函数接口上的阵列作为访问外部存储器的 RTL 端口来进行综合。而在设计内部,大小小于 1024 的阵列将作为 FIFO 来综合。大于 1024 的阵列将综合到块 RAM、LUTRAM 和 UltraRAM 中(取决于最优化设置)。

就像循环一样,阵列是直观的编码构造,通常可在 C/C++ 程序中找到。同样像循环一样,Vitis HLS 包含最优化和指令,可通过应用这些最优化和指令来最优化阵列在 RTL 中的实现,而无需修改代码。

在下列情况下,阵列在 RTL 中可能引发问题:

  • 阵列访问通常会造成性能瓶颈。作为存储器来实现时,存储器端口的数量会限制对数据的访问。
  • 请确保在 RTL 中将只需读访问权的阵列作为 ROM 来实现。
Vitis HLS 支持指针阵列。每个指针都只能指向 1 个标量或 1 个标量阵列。
注释: 阵列大小必须固定。支持调整大小后的阵列,包括函数实参(C++ 编译器忽略其大小,但 Vitis HLS 使用此大小),例如,Array[10];。但不支持非固定大小的阵列,如:Array[];