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 指令,你可以更精细地控制哪些变量需要复位。

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

相关推荐
冰红茶兑滴水10 分钟前
Linux 线程控制
linux·c++·算法
c语言鹌鹑蛋12 分钟前
C++进阶 --- 多继承中的虚表问题
开发语言·c++
Magnetic_h30 分钟前
【iOS】单例模式
笔记·学习·ui·ios·单例模式·objective-c
华清远见成都中心33 分钟前
哪些人适合学习人工智能?
人工智能·学习
重生之我在20年代敲代码1 小时前
HTML讲解(二)head部分
前端·笔记·html·web app
天下无贼!1 小时前
2024年最新版TypeScript学习笔记——泛型、接口、枚举、自定义类型等知识点
前端·javascript·vue.js·笔记·学习·typescript·html
秋秋秋叶1 小时前
Python学习——【2.3】for循环
python·学习
Deryck_德瑞克1 小时前
Java集合笔记
java·开发语言·笔记
MengYiKeNan1 小时前
C++二分函数lower_bound和upper_bound的用法
开发语言·c++·算法