Vivado IP 流程接口 - 2023.2 简体中文

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

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 简体中文
由于需要为各种应用提供 FPGA 设计支持,因此 Vivado IP 流程支持各种 I/O 协议和握手。此流程支持将多个 IP 集成到单个系统内的传统系统设计流程。IP 可通过 Vitis HLS 来生成。在此 IP 流程中,有两种控制模式可用于系统执行:
  • 软件控制:通过在嵌入式 Arm 处理器或外部 x86 处理器上运行的软件应用来控制系统,使用驱动程序来访问硬件设计的各种元件,并通过读取和写入硬件中的寄存器来控制系统中 IP 的执行。
  • 自同步:在此模式下,IP 将公开各种信号,用于启动和停止内核。这些信号受系统设计的其他 IP 或其他元件驱动,此系统设计负责处理 IP 的执行。

Vivado IP 流程支持存储器、串流和寄存器接口范例,其中每个范例都支持不同接口协议与外部世界进行通信,如下表所示。请注意,虽然 Vitis 内核流程仅支持 AXI4 接口适配器,但此流程支持多种不同的接口类型。

表 1. 接口类型
范例 描述 接口类型
存储器 内核通过存储器(如 DDR、HBM、PLRAM/BRAM/URAM)来访问数据 ap_memorybramAXI4 存储器映射 (m_axi)
串流 数据将从其他串流源(如视频处理器或其他内核)串流至内核,并且可从内核向外串流。 ap_fifo, AXI4‑Stream (axis)
寄存器 内核通过寄存器读取和写入所执行的寄存器接口来访问数据。 ap_noneap_hsap_ackap_ovldap_vldAXI4‑Lite 适配器 (s_axilite)。

默认接口由顶层函数中的 C 语言实参类型和默认范例来定义,如下表所示。

表 2. 默认接口
C 语言实参类型 受支持的范例 默认范例 默认接口协议
输入 输出 输入输出
标量变量(通过值来传递) 寄存器 寄存器 ap_none 不适用 不适用
阵列 存储器、串流 存储器 ap_memory ap_memory ap_memory
指针 存储器、串流、寄存器 寄存器 ap_none ap_vld ap_ovld
参考 寄存器 寄存器 ap_none ap_vld ap_vld
hls::stream 串流 串流 ap_fifo ap_fifo 不适用

Vivado IP 流程的默认执行模式为顺序执行,要求 HLS IP 完成前一次迭代后才能开始下一次迭代。这是通过 ap_ctrl_hs 块控制协议指定的。控制协议可按 块级控制协议 中指定的方式来更改。

以下代码中的 vadd 函数提供了在 Vivado IP 流程中进行接口综合的示例。

#define VDATA_SIZE 16

typedef struct v_datatype { unsigned int data[VDATA_SIZE]; } v_dt;

extern "C" {
void vadd(const v_dt* in1, // Read-Only Vector 1
          const v_dt* in2, // Read-Only Vector 2
          v_dt* out_r, // Output Result for Addition
          const unsigned int size // Size in integer 
) {

   unsigned int vSize = ((size - 1) / VDATA_SIZE) + 1;

   // Auto-pipeline is going to apply pipeline to this loop
   vadd1:
   for (int i = 0; i < vSize; i++) {
      vadd2:
      for (int k = 0; k < VDATA_SIZE; k++) {
         out_r[i].data[k] = in1[i].data[k] + in2[i].data[k];
      }
   }
}
}

vadd 函数包括:

  • 两个指针输入:in1in2
  • 指针:out_r,结果写入该指针
  • 标量值 size

通过 Vivado IP 流程所使用的默认接口综合设置,设计将综合到含端口的 RTL 块中,如下图所示。

图 1. 默认接口综合后的 RTL 端口

在默认 Vivado IP 流程中,该工具会在 RTL 上创建三种类型的接口端口,以处理数据流和控制流。

  • 时钟和复位端口:ap_clkap_rst 均添加到内核中。
  • 块级控制协议:ap_ctrl 接口是作为 s_axilite 接口来实现的。
  • 端口级协议:这些协议是针对顶层函数和函数返回(如果函数返回值)中的每个实参创建的。如上表所述,大部分实参都使用端口协议 ap_none,并且不含控制信号。在以上 vadd 示例中,这些端口包括:in1in2size。但是,out_r_o 输出端口使用 ap_vld 协议,因此与 out_r_o_ap_vld 信号相关联。

Vivado IP 流程中的 AP_Memory

ap_memory 是上表中所述存储器范例的默认接口。在 Vivado IP 流程中,它用于与存储器资源(如 BRAM 和 URAM)进行通信。ap_memory 协议同样遵循地址和数据阶段方式来进行操作。该协议首先请求读/写资源,并等待至它收到资源可用确认为止。随后,它会发起读/写的数据传输阶段。

ap_memory 的重要注意事项之一是它仅执行单节拍数据传输并传输至单一地址,这有别于 m_axi,后者可执行突发访问。因此,相比其他协议,ap_memory 属于轻量级协议。

  • 存储器资源:默认情况下,Vitis HLS 会实现协议以便与单端口 RAM 资源进行通信。您可在 INTERFACE 编译指示或指令中指定 storage_type 来控制该协议的实现。storage_type 指令允许您显式定义使用的 RAM 类型,以及所创建的 RAM 端口(单端口或双端口)。如果不指定 storage_type,那么 Vitis HLS 会使用:
    • 单端口 RAM(默认情况下)。
    • 双端口 RAM,前提是这样可缩短启动时间间隔或减少时延。

Vivado IP 流程中的 M_AXI 接口

AXI4 存储器映射 (m_axi) 接口允许 IP 读取和写入全局存储器(DDR、HBM 或 PLRAM)中的数据,存储器映射接口是跨多个 IP 共享数据的便利方法。以下列出了 m_axi 接口的主要优势:
  • 每个接口均有独立的读取通道和写入通道
  • 它支持基于突发的访问
  • 它可提供未完成传输事务队列
认识突发访问
AXI4 存储器映射接口支持高达 4K 字节的高吞吐量突发,且只需单一地址阶段即可。对于突发模式传输,Vitis HLS 会使用单一基址读取或写入数据,后接多次顺序数据采样,因此,该模式支持更高的数据吞吐量。使用 C memcpy 函数或经流水打拍的 for 循环时,即可执行突发模式操作。如需了解更多信息,请参阅 控制 AXI4 突发行为AXI 突发传输
自动端口拓宽和端口宽度对齐
端口宽度自动调整 中所述,Vitis HLS 能够自动拓宽端口宽度以便执行数据传输,并改善突发访问,前提是突发的所有前置条件均得到满足。在 Vivado IP 流程中,默认情况下,以下配置设置会禁用端口宽度自动调整。要启用此功能,必须更改这些配置选项(请注意,其中一条命令指定为位,另一条命令则指定为字节):
syn.interface.m_axi_max_widen_bitwidth=0
syn.interface.m_axi_alignment_byte_size=0
Vivado IP 模式指定对齐

m_axi 端口的对齐允许该端口根据指定对齐方式来读取和写入存储器。选择正确的对齐方式之所以如此重要,是因为最好情况下,它会影响性能,最差情况下,则会影响功能。

对齐的存储器访问意味着指针(或数据起始地址)是特定类型的值(称为对齐)的倍数。对齐是自然地址倍数,其类型必须或者应该存储在存储器上(例如,出于性能原因)。例如,标准 32 位架构在存储器中存储的数据字为 32 位,每个字均为 4 字节。此数据对齐到单个字或 4 字节边界。

对齐方式在整个系统中应保持一致。当 IP 在 AXI4 主模式下工作时,即可确定并且应该指定对齐方式,如采用 4 字节对齐的 32 位架构。当此 IP 在从模式下工作时,对齐应与主模式对齐方式相匹配。

偏移规则

m_axi 偏移默认设置为 offset=directsyn.interface.default_slave_interface=s_axilite。但在 Vivado IP 流程中,您可按 偏移和操作模式 中所述方式对其进行更改。

捆绑接口 - 性能对比资源使用情况

默认情况下,Vitis HLS 将具有兼容选项的函数实参组合到单个 m_axi 接口适配器中,如 M_AXI 捆绑 中所述。将端口捆绑到单个接口中可消除 AXI4 逻辑,因而有助于节省器件资源,在拥塞的设计内工作时可能需要这些资源。

但是,单一接口捆绑可能会限制 IP 性能,因为所有存储器传输都必须穿越单个接口。m_axi 接口具有独立的读取 (READ) 和写入 (WRITE) 通道,因此单个接口即可同时执行读取和写入,但仅限单一位置。使用多个捆绑即可创建多个接口以连接到存储体,从而能够改善性能。

Vivado IP 流程中的 S_AXILITE

Vivado IP 流程中,默认执行流程由寄存器读取和写入通过 s_axilite 接口使用默认 ap_ctrl_hs 控制协议来进行管理。此 IP 由软件控制,方法是读取和写入 s_axilite 接口的控制寄存器,如 S_AXILITE 控制寄存器映射 中所述。

s_axilite 接口可提供下列功能特性:

控制协议
采用 块级控制协议 中指定的块控制协议。
标量实参
来自顶层函数的标量实参可映射到 s_axilite 接口,此接口会为值创建寄存器,如 S_AXILITE 控制寄存器映射 中所述。软件可对此寄存器空间执行读/写操作。
偏移规则
Vivado IP 流程可以基于顶层函数中关联的 C 语言实参的数据类型来定义端口的大小或分配给端口的地址范围。但该工具还允许您手动定义偏移大小,如 S_AXILITE 偏移选项 中所述。
捆绑规则
Vivado IP 流程中,您可使用 s_axilite 接口来指定多个捆绑,这样将为您定义的每个捆绑创建一个独立的接口适配器。但您应熟悉一些有关使用多个捆绑的规则,如 S_AXILITE 捆绑规则 中所述。

Vivado IP 流程中的 AP_FIFO

Vivado IP 流程中,ap_fifo 接口协议是默认接口,用于供该接口上的串流范例与存储器资源 FIFO 进行通信,并用作为 IP 内不同函数之间的通信通道。仅当数据采用顺序访问时,才应使用此协议,并且 AMD 强烈建议使用 hls::stream<data type>,它可实现 FIFO。

提示: <data type> 不应与 T_data_type 相同,后者应仅限在接口上使用。

Vivado IP 流程中的 AXIS 接口

AXI4‑Stream 协议 (axis) 可作为备选用于串流接口,该协议定义了一条单向通道用于按顺序串流数据。不同于 m_axi 协议,AXI4‑Stream 接口可突发的数据量是无限的,故而能显著提升性能。不同于需要地址才能读/写存储器的 AXI4 存储器映射接口,axis 接口可直接将数据传递至另一个 axis 接口,无需地址,因此使用的器件资源更少。通过将这些功能特性相结合,即可使串流接口成为轻量级高性能接口,如 AXI4-Stream 接口 中所述。