Vitis HLS 学习笔记--初始化与复位

1. 简介

初始化行为
在 C/C++ 中,默认情况下,以静态限定符定义的变量和全局作用域中定义的变量都初始化为 0。(可选)对于这些变量,可赋予特定初始值。对于这些已初始化的变量,C/C++ 语言代码中的值在编译时(时序为 0 时)进行赋值,并且不再进行赋值。上述 2 种情况下,在 RTL 中实现初始值。
• 在 RTL 仿真期间,为这些变量设置的初始值与 C/C++ 语言代码中相同。
• 在用于对 FPGA 进行编程的比特流中,也会对这些变量进行初始化。当器件上电时,变量将以其初始状态启动。

在 RTL 中,虽然变量启动时使用的初始值与 C/C++ 语言代码相同,但无法强制该变量返回至此初始状态。要复原初始状态,必须通过复位信号来实现这些信号变量。

2. 阵列初始化和复位

对于阵列,推荐使用含 static 限定符的存储器来实现。这不仅可确保 HLS 工具以存储器来实现阵列,还允许使用"static"(静态)类型的默认初始化行为。

最为对比,我们看一下两种情况:

不使用 static 限定符。

cpp 复制代码
int coeff[8] = {-2, 8, -4, 10, 14, 10, -4, 8, -2};

每次执行函数时,都会为 coeff 阵列分配这些值。综合后,每次执行 kernel 时,用于实现 coeff 的 RAM 都会随这些值一起加载。

如果使用单端口 RAM,此操作耗时 9 个时钟周期。对于 1024 阵列,当然也就需要 1024 个时钟周期,在此期间无法执行任何依赖于 coeff 的运算。

使用 static 限定符。

cpp 复制代码
static int coeff[8] = {-2, 8, -4, 10, 14, 10, -4, 8, -2};

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

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

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

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

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

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

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

  • 初始化行为:适用于所有平台上的所有 BRAM,仅适用于 Versal URAM。这是上电初始化(或上电复位)期间的行为。
  • 如果读取/写入阵列,则保留"initial value array"(初始值阵列)和"run time array"(运行时阵列)。此行为适用于 BRAM 和 URAM,对应于器件执行期间的硬件 RESET 信号。

3. 控制初始化与复位行为

3.1 复位行为

复位端口在 FPGA 中用于在应用复位信号时,立即将连接到复位端口的寄存器和块 RAM 还原为初始值。通常 RTL 配置中最重要的操作即选择复位行为。

对于复位行为,重要的是理解初始化与复位之间的差异。

复位设置包含设置复位极性以及使用同步复位还是异步复位的功能,但更重要的是,它可通过"reset"选项来控制应用复位信号时要复位的寄存器。

复位设置包含设置复位极性以及使用同步复位还是异步复位的功能,但更重要的是,它可通过"reset"选项来控制应用复位信号时要复位的寄存器。

"reset"选项包含 4 项设置:

  • "none":在设计中不添加复位。
  • "control":这是默认设置,用于确保将所有控制寄存器复位。控制寄存器即状态机中使用的寄存器,用于生成I/O 协议信号。此设置可确保设计可立即启动其操作状态。
  • "state":该选项可为控制寄存器添加复位(与"control"设置相同),并且还可为衍生自 C/C++ 语言代码中的静态变量和全局变量的任意寄存器或存储器添加复位。此设置可确保应用复位后,C/C++ 语言代码中初始化的静态变量和全局变量均复位为其初始值。
  • "all":此设置用于为设计中的所有寄存器和存储器添加复位。

通过 RESET 编译指示或指令可提供更精细的复位控制。静态变量和全局变量均可通过 RESET 指令来添加复位。还可使用 RESET 指令的 off 选项从复位的变量中移除变量。

3.2 初始化行为

在 C/C++ 中,默认情况下,以静态限定符定义的变量和全局作用域中定义的变量都初始化为 0。(可选)对于这些变量,可赋予特定初始值。对于这些已初始化的变量,C/C++ 语言代码中的值在编译时(时序为 0 时)进行赋值,并且不再进行赋值。上述 2 种情况下,在 RTL 中实现初始值。

  • 在 RTL 仿真期间,为这些变量设置的初始值与 C/C++ 语言代码中相同。
  • 在用于对 FPGA 进行编程的比特流中,也会对这些变量进行初始化。当器件上电时,变量将以其初始状态启动。

在 RTL 中,虽然变量启动时使用的初始值与 C/C++ 语言代码相同,但无法强制该变量返回至此初始状态。要复原初始状态,必须通过复位信号来实现这些信号变量。

4. 总结

对于阵列,推荐使用带有 static 限定符的存储器来实现。这样不仅可以确保 HLS 工具以存储器形式实现阵列,还允许使用默认初始化行为。静态阵列在 C/C++ 代码中的行为与 RTL 中的存储器行为相同。

在复位方面,你可以选择不添加复位、控制复位、状态复位或全部复位。通过 RESET 指令,你可以更精细地控制哪些变量需要复位。

了解初始化和复位之间的差异对于有效设计和编程至关重要。

相关推荐
冰帝海岸3 小时前
01-spring security认证笔记
java·笔记·spring
‘’林花谢了春红‘’4 小时前
C++ list (链表)容器
c++·链表·list
小二·4 小时前
java基础面试题笔记(基础篇)
java·笔记·python
机器视觉知识推荐、就业指导5 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
朝九晚五ฺ5 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
wusong9997 小时前
mongoDB回顾笔记(一)
数据库·笔记·mongodb
猫爪笔记7 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html
Resurgence037 小时前
【计组笔记】习题
笔记
Yang.997 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3