HyperFlex 架构系列(4):可变延迟模块与自动流水线插入
一、在可变延迟位置做流水线
FPGA 设计中通常存在一些对额外延迟不敏感的位置,例如时钟域边界、主要功能块之间的连接和 false path。在这些位置添加流水线级是最佳实践。但过多添加流水线级也会膨胀面积并增加布线拥塞。
当前版 Quartus Prime 包含了针对延迟不敏感路径的新功能:Hyper-Retimer 可以自动在你标记为 latency-insensitive 的 false path 上添加流水线级,也可以在你指定的寄存器处插入适当数量的流水线级。这些添加的寄存器会被 retime 到设计中的时序关键部分。Hyper-Retimer 添加的流水线级数量会在每次编译或每次设计变更时发生变化。
注意:
- 如果不指定 latency-insensitive false path 也不使用 auto-pipelining,Hyper-Retimer 的输出网表与你的 RTL 是 cycle-equivalent 的。
- 如果指定了 latency-insensitive false path 或使用 auto-pipelining,输出网表与 RTL 不再是 cycle-equivalent 的。因此仿真和验证环境必须能适应电路延迟的变化。
1.1 指定延迟不敏感的 False Path
可以指定 latency-insensitive false path 来允许 Hyper-Retimer 在路径上自动添加流水线级。仅在跨时钟域路径上使用这个选项,例如低速配置时钟域与高速数据路径时钟域之间:
set_false_path -latency_insensitive -from [get_clocks {clock_a}] \
-to [get_clocks {clock_b}]
注意,虽然语法上允许在 from 或 to 中使用寄存器、cell、网线、pin 或 keeper 名称,但 Compiler 会将这种 register-to-register 的 false path 视为 retiming restriction,阻止 Hyper-Retimer 对这些端点做 retiming。在 register-to-register false path 上使用 latency_insensitive 没有收益。
set_false_path 约束的优先级高于所有其他基于路径的 SDC 约束。如果 latency-insensitive false path 所在的时钟域传输包含 FIFO、总线同步器或其他跨域电路,且这些电路上存在 set_max_skew、set_max_delay 或 set_min_delay 等路径约束,那么 clock-to-clock 的 set_false_path 会覆盖这些约束。仅在已从时序分析中实际切断的跨时钟域路径上使用 latency-insensitive false path。
下图上半部分是 RTL,标记了 latency-insensitive false path。下半部分展示了 Hyper-Retimer 在 false path 端点的寄存器另一侧添加流水线级。Hyper-Retimer 可以在 latency-insensitive false path 的源端输入和目的端输出添加寄存器,然后将寄存朝两个时钟域中做 backward 和 forward retiming。

Hyper-Retimer 分别分析每个跨时钟域路径的性能,决定自动添加的级数。不同路径可能插入不同数量的流水线级。例如,一条被 latency_insensitive 切断的总线,在 Hyper-Retimer 运行后可能各个比特的延迟不同。因此要确保跨时钟域的数据保持恒定多个时钟周期,使数据在目的端成为确定值。
编译报告不会显示 Hyper-Retimer 在 latency-insensitive false path 上插入的级数。但可以在 Hyper-Retimer 完成后检查时序网表的连接关系来确定。
二、自动流水线插入
自动流水线插入允许 Hyper-Retimer 在你指定的位置插入一定数量的流水线级。你可以为每个寄存器指定最大流水线级数。

Quartus Prime 提供了 hyperpipe_vlat(Variable Latency Module)模板来简化实现。也可以用 QSF 赋值的组合来实现自动流水线插入。
当例化 hyperpipe_vlat 模块且 Enable AutoPipelining(HYPER_RETIMER_ENABLE_ADD_PIPELINING)选项使能时(该选项默认打开),Hyper-Retimer 会在 retiming 过程中在指定寄存器处添加适当数量的额外流水线级,最多不超过你指定的最大值。这个选项位于 Assignments > Settings > Compiler Settings > Advanced Settings (Fitter)。

例如,如果指定最大 10 级,Hyper-Retimer 可能判断只需要 3 级就能满足时序要求。它只添加实际需要的级数。

可以为不同的 hyperpipe_vlat 实例指定不同的最大流水线级数。

最大额外流水线级数的有效范围是 1 到 100。
2.1 创建可变延迟模块
hyperpipe_vlat 模块包含单个流水线级。Hyper-Retimer 为同一实例中位宽的所有比特添加相同数量的流水线级。模块参数:
- WIDTH:总线位宽,默认 1
- MAX_PIPE:Hyper-Retimer 在该实例上最多可添加的流水线级数,范围 1 至 100,默认 100

在 Quartus Prime 中创建步骤:
- File > New,创建新的 Verilog HDL 或 VHDL 设计文件。
- 在新文件中右键,Insert Template。
- 选择 Verilog HDL (或 VHDL) > Full Designs > Pipelining > Hyper-Pipelining Variable Latency Module,Enter and Close。
- 例化时指定 WIDTH 和 MAX_PIPE 参数的值。
- 保存文件。
2.2 例化可变延迟模块
可以使用 Fast Forward 编译来帮助找到适合自动流水线插入的位置。以下位置通常适合:
- 时钟域边界:当传输的是持续变化的数据时,允许 Fitter 在有利时将这些模块放置得更远。
- 紧邻复杂组合功能的位置:适用于难以满足时序的功能。
- 同一时钟域中两个独立功能块之间:允许 Fitter 在有利时将模块放置得更远。
在时钟域边界例化
Fast Forward 编译建议在时钟域边界添加流水线级,这些位置容纳额外延迟通常比较简单。在时钟边界例化可变延迟模块允许 Fitter 在有利时将模块放置得更远。只需在同步器或 FIFO 之前或之后例化 hyperpipe_vlat。例化时不应在 hyperpipe_vlat 与其目标之间有其他寄存器或逻辑。这样 Hyper-Retimer 可以自动插入刚好够用的流水线寄存器来满足时序。在这种情况下 latency-insensitive false path 不合适,因为数据是持续变化的。
紧邻复杂组合功能例化
可以在复杂组合模块之后例化 hyperpipe_vlat(向后 retiming 不需要额外的复位周期来适应初始条件)。你无法控制 hyperpipe_vlat 中的寄存器是向前 retime 到跟随的逻辑,还是向后 retime 到组合模块中。
在独立功能块之间例化
可以在同一时钟域中的两个独立功能块之间例化 hyperpipe_vlat。这样功能块在布局时可以拉开距离,只在块之间添加满足时序所需的最少流水线级数。
不要将可变延迟模块直接放在 partition 边界旁边。需要在模块和 partition 端口之间放置一个寄存器来分隔。如果 hyperpipe_vlat 紧邻 partition 边界,retiming 时不会 auto-pipeline。


施加 False Path 或例外约束
如果在独立功能块之间例化 hyperpipe_vlat,需要添加 false path 或其他时序例外,允许连接的功能块在布局时浮开。将 false path 或例外施加到 hyperpipe_vlat 模块中的 vlat_r 寄存器上。通过将时序例外放在条件 if 语句内,当时序分析器在 vlat 添加寄存器时以及最终时序签核时,不会使用该例外,确保每个寄存器满足时钟要求。
if { ! [is_post_route] } {
set_false_path -to my|top|design|hyperpipe_vlat_inst|vlat_r[*]
}
如果没有对应的 false path 或例外约束,hyperpipe_vlat 几乎没有收益。没有 false path 约束时,Hyper-Retimer 在布局布线期间只识别到单个流水线级,额外的流水线级在布局布线完成后才添加。Compiler 倾向于将两个仅由单级流水线连接的功能块放在靠近彼此的位置,除非它们之间的路径被切断。
如果使用 MAX_PIPE 参数限制流水线数量,建议使用 max_delay 或 multicycle 例外替代 set_false_path。set_false_path 可能导致逻辑被放置得过远,使 MAX_PIPE 约束不足。例如当 NUM_PIPES=3 时:
if {![is_post_route]} {
set_multicycle_path -setup -to my|top|design|hyperpipe_vlat_inst|vlat_r[*] 3
set_multicycle_path -hold -to my|top|design|hyperpipe_vlat_inst|vlat_r[*] 2
}
施加 -from 或 -to 约束
使用可变延迟模块将 Hyper-Register 向前或向后推入寄存器链:
- -from 约束:将 vlat_r 放在需要流水线化的组合逻辑之前。
- -to 约束:将 vlat_r 放在需要流水线化的组合逻辑之后。


2.3 验证 Auto-Pipelining 选项
Enable Auto-Pipelining(HYPER_RETIMER_ENABLE_ADD_PIPELINING)选项默认打开。在 Assignments > Settings > Compiler Settings > Advanced Settings (Fitter) 中可以验证或修改。关闭它会阻止在 hyperpipe_vlat 实例中进一步添加流水线级。
set_global_assignment -name HYPER_RETIMER_ENABLE_ADD_PIPELINING <ON|OFF>
2.4 不使用可变延迟模块的自动流水线插入
如果不使用 hyperpipe_vlat 模块,对目标寄存器按以下步骤启用 auto-pipeline:
- 在 Assignment Editor 中选择 Maximum Additional Pipelining,输入最大流水线数,指定目标寄存器的层级路径:
set_instance_assignment -name HYPER_RETIMER_ADD_PIPELINING \
<maximum stages> -to <register path>
- 指定 preserve pragma 并将目标寄存器的 Netlist Optimizations 设为 Never Allow,防止 auto-pipelining 插入前对总线做任何优化:
set_instance_assignment -name \
ADV_NETLIST_OPT_ALLOWED NEVER_ALLOW -to <register path>
- 创建赋值组使关联的寄存器获得相同数量的额外流水线级。如果不定义组,组名会自动以 add_pipelining_group 为前缀生成:
set_instance_assignment -name \
HYPER_RETIMER_ADD_PIPELINING_GROUP <group name string> \
-to <register path>
三、用寄存器替代 Multicycle 例外
设计中常有包含复杂组合逻辑的模块(如 CRC 和其他算术功能),需要多个时钟周期处理。这些模块通常用 multicycle 例外放宽时序要求。HyperFlex 架构 FPGA 设计中可以使用这些模块和约束。
另一种做法是在模块的一个方便位置插入若干寄存器级,Compiler 自动进行平衡。例如要流水线化一个 CRC 功能,不需要识别最优的分解位置和中间项。在它的输入或输出处添加寄存器即可,Compiler 会负责平衡。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)