目录
1. 简介
Vitis HLS 支持的 AXI4 接口包括 AXI4-Stream 接口 (axis)、AXI4-Lite (s_axilite) 和 AXI4 主接口 (m_axi)。
m_axi:适用于阵列和指针(以及 C++ 中的引用)。
s_axilite:适用于在除串流外的任意类型的实参上指定此协议。
axis:适用于输入实参或输出实参上指定此协议,而不得在输入/输出实参上指定。
AXI4 存储器映射 (m_axi) 接口允许内核在全局存储器(DDR、HBM 和 PLRAM)内读写数据。存储器映射接口便于跨加速应用的不同元素共享数据。
本文分享使用 AXI4 存储器映射 (m_axi) 接口的经验总结。
2. 认识MAXI
AXI4 存储器映射接口、AXI4 主接口、maxi、axi4-master指的是同一个事,因为会从处理器中接管AXI总线,从而操作全局存储器,体现出一个“主动的”、“全局的”、“存储器的”含义。
MAXI 可在阵列或指针/参考实参上使用,通过以下任一模式来实现该接口:
- 单独数据传输
- 突发模式数据传输
很少会用到单独数据传输,我们先通过这个突发模式数据传输了解 MAXI:
#include <stdio.h>
#include <string.h>
void func(volatile int *a, volatile int *b){
#pragma HLS INTERFACE mode=s_axilite port=return
#pragma HLS INTERFACE mode=m_axi port=a depth=50
#pragma HLS INTERFACE mode=m_axi port=b depth=50
int i;
int buff[50];
memcpy(buff, (const int*)a, 50*sizeof(int));
for(i=0; i < 50; i++){
buff[i] = buff[i] + 100;
}
memcpy((int *)b, buff, 50*sizeof(int));
}
在这个例子中,函数 func 接收两个指向整数的 volatile 指针 a 和 b,然后将 a 指向的数据拷贝到一个本地缓冲区 buff,对每个元素增加 100,最后将结果拷贝回 b 指向的内存位置。
这段代码经过综合后将在 FPGA 硬件上执行,此时指针 a 和 b 分别指向全局内存中的地址。因此,可以看出,M_AXI 接口在此扮演了 DMA(直接内存访问)的角色,实现了高效的内存数据传输。
3. MAXI突发操作
3.1 全局/本地存储器
1)全局存储器
通常是片外存储器,包括 DDR、HBM 和 PLRAM 等,这些存储器通过FPGA的外部接口与之连接。片外存储器通常用于存储大量数据,片外存储器的访问速度通常比本地存储器慢,受限于接口速度和通信协议。
访问全局存储器可能需耗费大量周期:
2)本地存储器
本地存储器位于 FPGA 芯片内部的存储资源。这些存储资源通常访问速度快,延迟低,因为它们直接嵌入在 FPGA 逻辑中,无需经过外部接口。本地存储器通常用于存储小量数据,如配置参数、中间计算结果或小数组。
本地存储器包括:
Block RAM(BRAM):一种较大的、可配置的内部存储块,适用于实现FIFO、缓冲区、查找表等。
Distributed RAM:利用FPGA内部逻辑单元(如LUTs)的存储能力,适合于小规模存储需求。
寄存器:非常小的存储单元,用于存储极少量的数据,如状态机的状态、计数器的当前值等。
URAM:Ultra RAM
3.2 MAXI优势与特点
以下列出了 m_axi 接口的主要优势:
- 此接口有独立的读取通道和写入通道
- 支持基于突发的访问,潜在性能可达 ~17 GB/s
- 它可为未完成传输事务提供支持
突发
突发是一种对内核执行的最优化,它会尝试以智能方式聚集对 DDR 的存储器访问操作,以便尽可能提升吞吐量带宽和/或减小时延。通常可以实现 4 到 5 倍的提升,结合其它最优化(例如,访问拓宽或者确保不存在通过 DDR 的依赖关系)甚至可提供更大的性能提升。通常 DDR 端口上存在争用(源于多个相互竞争的内核)时,适合使用突发。
传输速度
计算方式如下:
((传输的字节数) * (内核频率)/(时间))
最大内核接口位宽为 512位,如果内核编译为按 300 MHz 频率运行,那么理论上每个 DDR 可达成 (512* 300 MHz)/1 秒 = ~17 GB/s。
未完成传输事务
允许HLS内核以流水线方式管理存储器请求的数量,这意味着它可以连续发送请求到全局存储器,而不