pragma HLS cache - 2025.2 简体中文 - UG1399

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

Document ID
UG1399
Release Date
2026-01-22
Version
2025.2 简体中文

描述

在 FPGA 设计中,对片外 DDR 存储器进行非突发访问的成本很高,而且会使性能劣化。为了缓解该问题,Vitis HLS 在 M_AXI 适配器中支持一种高速缓存机制,通过利用引用的局部性(时间性和空间性)来减少平均访问时延。访问某个存储器区域时,很可能很快会再次访问该区域,并且还可能访问附近的位置。

这种高速缓存机制既支持单端口高速缓存,也支持多端口层级:

  • 单端口高速缓存:直接映射、只读高速缓存,连接到单个 m_axi 端口。这样在内核重复访问同一行时可以减少对 DRAM 的重复读取。
  • 多端口高速缓存:一种分层高速缓存,每个端口都有 L1 高速缓存,并共享 L2 高速缓存。它支持在单个时钟周期内对同一个顶层 m_axi 指针进行最多 N 次读取访问,而无需更改源代码,适用于类似 stencil 的访问模式以及编译器无法推断窗口缓冲器的其他动态访问模式。相比于编译器推断的窗口缓冲器,多端口高速缓存更灵活(处理动态模式),但通常会耗用更多的资源。

多端口高速缓存架构

  • L2 高速缓存(共享):
    • 所有端口共享一个直接映射的高速缓存。

    • 通过突发传输从片外 DRAM 加载。

    • 将各行广播到发出请求的 L1 高速缓存,通过避免冗余 DRAM 加载来优化存储器带宽。

  • L1 高速缓存(各端口):
    • 每个高速缓存端口一个直接映射的 L1 高速缓存。

    • 每个 L1 均可在每个周期内提供一个数据项,允许每个周期对同一个 m_axi 指针进行最多 N 次读取访问。

    • 从共享的 L2 高速缓存加载 L1 行。

提示: 您可使用 syn.interface.m_axi_cache_impl 命令控制高速缓存实现资源。

语法

pragma HLS cache port=<name> lines=<value> depth=<value>

其中:

port=<name>
指定高速缓存要添加到的只读端口(顶层 m_axi 指针)。
lines=<value>
每个 L1 高速缓存中的高速缓存行数(针对单端口的情况:唯一的一个高速缓存)。针对单行指定 1,针对多行指定大于 1 的 2 的幂值。可选;如不指定,则默认值为 1。
depth=<value>
每个高速缓存行的大小,以字数为单位,必须为 2 的幂值。适用于指针的元素类型(例如,深度以 int 或 float 为单位)。可选;默认值为最大突发长度。最大突发长度默认为 16,但可通过 syn.interface.m_axi_max_read_burst_length 来全局指定,或通过 syn.directive.interface 来按接口指定。
注释: 在多端口高速缓存中,L1 和 L2 缓存共享相同的行深度;深度同时适用于两个级别。
ports=<N>
启用多端口高速缓存功能特性。定义在一个时钟周期内可以针对对应顶层 m_axi 指针调度执行的读取访问次数。仅适用于映射到其 m_axi 捆绑的只读指针;当端口数量大于 1 时,只能将一个只读阵列映射到该捆绑(请参阅“限制”)。
l2_lines=<M>
可选;默认情况下,L1 和 L2 高速缓存的行数由深度选项来选择。在共享 L2 高速缓存中显式设置行数。每个 L2 行的大小与 L1 行大小相等,并受深度控制。必须大于行数;L2 高速缓存行数必须大于 L1 高速缓存行数。

不含 L2 高速缓存的单端口高速缓存示例:

#pragma HLS cache port=A lines=4 depth=32

启用每个周期最多 3 次读取的多端口高速缓存,显式设置共享 L2 的大小:

#pragma HLS cache port=A lines=4 depth=32 ports=3 l2_lines=16

行为与性能注释

  • 多端口高速缓存是专为类似 stencil 的访问模式以及无法推断窗口缓冲器的动态访问模式而设计的。它可以在每个周期内允许多个读取请求,同时减少通过共享 L2 的冗余 DRAM 突发,从而提高吞吐量。
  • L1 与 L2 高速缓存均为直接映射。命中/未命中行为由局部性决定;增大行数并选择合适的深度可以提高命中率,但会增加资源消耗。
  • 共享 L2 高速缓存每次未命中时会加载一个 DRAM 行,并将该行广播到需要它的任意 L1 高速缓存,从而优化与窗口缓冲器类似的带宽,但支持动态模式。

限制

  • 仅限只读端口才支持高速缓存。写端口可以与缓存的只读指针共享一个捆绑,因为它们使用的是独立通道,但不支持 inout 输入输出端口。
  • 在多端口模式(端口数大于 1)下:
    • 缓存的顶层 m_axi 指针必须是映射到其捆绑的唯一读端口。
    • 写端口也可以映射到同一个捆绑,但 inout 端口对此不予支持。
  • 高速缓存在 L1 和 L2 级处均为直接映射(单路)。
  • 指定的 l2_lines 值必须大于行数。
  • 只能将一个只读阵列映射到多端口缓存指针的 m_axi 捆绑。

其他控制

  • syn.interface.m_axi_cache_impl 可用于控制高速缓存实现资源。
  • syn.interface.m_axi_max_read_burst_lengthsyn.directive.interface 可通过最大突发长度来控制默认深度。

示例

以下示例显示的设计中,重叠访问会导致突发失败。使用 CACHE 编译指示或指令会改善设计性能。

extern "C" {
  void dut(
    const double *in,  // Read-Only Vector 1
    double *out,       // Output Result
    int size                 // Size in integer
  )
#pragma HLS INTERFACE m_axi port=in  bundle=aximm depth = 1026
#pragma HLS INTERFACE m_axi port=out bundle=aximm depth = 1024
#pragma HLS cache port=in lines=8 depth=128    
for(int i = 0; i < size; i++)
    {
      out[i] = in[i] + in[i + 1];
    }
}