syn.directive.cache - 2024.1 简体中文

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

Document ID
UG1399
Release Date
2024-07-03
Version
2024.1 简体中文

描述

在 FPGA 中,对 DDR 存储器的非突发访问代价不菲,可能影响设计的整体性能。因此,设计一种方案来缩短访问必要信息所需的时间就显得尤为重要。有一种有效的解决方案是重写代码或使用手动突发,但如果无效,那么另一种解决方案是使用高速缓存存储器。

高速缓存在 M_AXI 适配器中提供了一个临时存储区域,因此设计可以更快检索数据。高速缓存机制的效果是以命中/未命中率来度量的,该指标以计算机程序中所谓访问局部性 (locality of reference) 的属性为基础,即某个程序在短时间内重复访问同一组存储器位置的趋势。它表明在访问特定的存储器块时,很可能不久之后就会再次访问该存储器块以及位于附近的存储器。例如,在存储器中执行连续指令时,下一组要访问的指令很可能就在附近的连续数据块内。

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

语法

syn.directive.cache=<location> port=<name> lines=<value> depth=<value>

其中:

<location>
指定函数,可在该函数所在位置找到指定端口。这是顶层函数。
port=<name>
指定高速缓存要添加到的端口。这是必需实参。
lines=<value>
表示缓存行的数量。行数可指定为 1,表示单个高速缓存行;也可指定为大于 1 的值(指定为 2 的幂值),表示多个高速缓存行。这是可选值,如不指定则默认为 1。
depth=<value>
以字数为单位,指定每行的大小。深度必须指定为 2 的幂,表示每个行的指针数据类型的大小(以字数为单位)。
这是可选值,如不指定则默认为最大突发长度。最大突发长度默认值为 16,但可通过 syn.interface.m_axi_max_read_burst_length 命令来全局指定(如 接口配置 中所述),或者通过 syn.directive.interface 命令来为特定接口指定该值。

限制

CACHE 指令或编译指示存在如下限制:

  • 仅限只读端口才支持 CACHE
  • CACHE 是作为单端口单向高速缓存来实现的。
  • m_axi 端口的每条读取通道都有一个关联的高速缓存。如果某个捆绑没有通道规格,则映射到该捆绑的所有读取端口都必须满足以下条件:
    • 全都不含高速缓存,或者全都采用行大小(字节数)和行数相同的高速缓存。
    • 如果字大小不同,那么深度也必须不同,这样以字节为单位的行大小才会相同。
    • 在以下代码中,对应 char* 的行深度(例如,字数)必须是对应 int* 的行深度的 4 倍以上,因为每个 int 包含 4 个 char:
      void top(int *int_arr, char *char_arr, …) { #pragma HLS interface m_axi port=int_arr bundle=gmem … #pragma HLS interface m_axi port=char_arr bundle=gmem … #pragma HLS cache port=int_arr lines=8 depth=8 #pragma HLS cache port=char_arr lines=8 depth=32
    • 而下面这段代码则是违规的,因为各行的大小都不同:
      void top(int *int_arr, char *char_arr, …) { #pragma HLS interface m_axi port=int_arr bundle=gmem … #pragma HLS interface m_axi port=char_arr bundle=gmem … #pragma HLS cache port=int_arr lines=8 depth=8 #pragma HLS cache port=char_arr lines=8 depth=16
    • 这段代码是违规的,原因则是行数不同:
      void top(int *int_arr, char *char_arr, …) { #pragma HLS interface m_axi port=int_arr bundle=gmem … #pragma HLS interface m_axi port=char_arr bundle=gmem … #pragma HLS cache port=int_arr lines=8 depth=8 #pragma HLS cache port=char_arr lines=4 depth=32
    • 最后,这段代码是违规的,因为只有一个阵列有高速缓存:
      void top(int *int_arr, char *char_arr, …) { #pragma HLS interface m_axi port=int_arr bundle=gmem … #pragma HLS interface m_axi port=char_arr bundle=gmem … #pragma HLS cache port=int_arr lines=8 depth=8 y
    • 如果为捆绑指定了通道,那么每条通道的高速缓存大小都可能不同,有些通道可能有高速缓存,而其他通道则可能没有。在任一通道内,同样适用以上规则。例如,现在这段代码完全合规,但由于存在两个高速缓存,因此耗用的资源比前一个示例更多:
      void top(int *int_arr, char *char_arr, …) { #pragma HLS interface m_axi port=int_arr bundle=gmem channel=0 … #pragma HLS interface m_axi port=char_arr bundle=gmem channel=1 … #pragma HLS cache port=int_arr lines=8 depth=32 #pragma HLS cache port=char_arr lines=8 depth=32
    • 高速缓存将生成与行大小相同的读取请求。这表示在协同仿真中,阵列大小(以给定数据类型的字数为单位)必须是行大小(同样以给定数据类型的字数为单位)的整数倍。
    • 在部署中,主机代码在 DRAM 中执行的阵列分配必须对齐到行大小,而且阵列的总大小必须是行大小的倍数。
    • 否则,协同仿真期间会生成以下错误消息:
      ERROR: Index ... out of bound 0 to ...

示例

以下示例显示的设计中,重叠访问将导致突发失败。使用 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]; } }