阵列初始化和复位 - 2023.2 简体中文

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

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

在以下代码中,阵列利用一组值来进行初始化。每次执行函数时,都会为 coeff 阵列分配这些值。综合后,每次执行设计时,用于实现 coeff 的 RAM 都会随这些值一起加载。对于单端口 RAM,此操作耗时 8 个时钟周期。对于 1024 阵列,当然也就需要 1024 个时钟周期,在此期间无法执行任何依赖于 coeff 的运算。

int coeff[8] = {-2, 8, -4, 10, 14, 10, -4, 8, -2};

以下代码使用 static 限定符来定义 coeff 阵列。该阵列开始执行时会使用指定的值进行初始化。每次执行该函数时,coeff 阵列都会保留上次执行的值。静态阵列在 C/C++ 语言代码中的行为与 RTL 中的存储器行为相同。

static int coeff[8] = {-2, 8, -4, 10, 14, 10, -4, 8, -2};

此外,如果变量包含 static 限定符,那么 Vitis HLS 会对 RTL 设计和 FPGA 比特流中的变量进行初始化。因此,无需经历多个时钟周期来初始化存储器,并且可确保大型存储器初始化不会产生任何运算开销。请参阅 GitHub 上提供的 initialization_and_reset 示例,以获取更多示例。

RTL 配置命令 syn.rtl.reset 可指定在应用复位后,静态变量是否返回其初始状态。这并非默认设置。使用 syn.rtl.reset=stateall 时,会强制作为块 RAM 实现的所有阵列都在复位后返回初始化状态。这可能导致 RTL 设计中出现 2 个非常不利的条件:

  • 不同于上电初始化(或上电复位),显式复位要求 RTL 设计对块 RAM 中的每个地址进行迭代以设置该值:如果 N 较大,这可能导致时钟周期数量显著增加,并增加实现复位所需的面积资源。
  • 在设计中每个阵列中都添加复位。

为防止在每个此类 BRAM 上添加复位逻辑,并因复位 RAM 内所有元素而产生周期开销,请指定默认 syn.rtl.reset=control 复位模式,并使用 RESET 编译指示或指令来识别要复位的个别静态变量或全局变量。

或者,可使用 syn.rtl.reset=state 复位模式,并使用 RESET 指令 off 选项选择不执行复位的个别静态变量或全局变量。

最后,根据您所选的硬件器件或平台(UltraScale+Versal 等),块 RAM 和 URAM 的初始化和/或复位方式可能不尽相同。总体上,Vitis HLS 支持两类复位:一种类型是器件上电(也称为上电初始化或上电复位),第二种类型是在器件执行期间,硬件 RESET 信号断言有效。以下显示了不同存储器资源的行为差异:

  • 初始化行为:适用于所有平台上的所有块 RAM,仅适用于 Versal URAM。这是上电初始化(或上电复位)期间的行为。
  • 如果读取/写入阵列,则保留“initial value array”(初始值阵列)和“runtime array”(运行时阵列)。此行为适用于块 RAM 和 URAM,对应于器件执行期间的硬件 RESET 信号。
提示: 将针对相同地址的读取和写入操作映射到相同存储器端口时,URAM 不支持 read-first(先读取)输出 write_mode(不同于块 RAM)。块 RAM 支持以下写入模式:write thruread firstno change。URAM 仅支持 no change。如果 Vitis HLS 在 URAM 端口上无法将存储器操作调度为在同一个周期内执行,那么将发出以下警告消息:
Usage of URAM can potentially cause worse II as Vitis HLS does not exploit 
read-first mode for URAMs. Consider using block RAMs instead.