目录
1. 简介
2. 代码解析
2.1 代码总览
2.2 优化指令
2.3 综合报告
3. 总结
1. 简介
Vivado IP 流程中的 AP_Memory,它用于与存储器资源(如 BRAM 和URAM)进行通信。不同于全局存储器(DDR),对此专用存储器执行的访问称为本地数据访问,比如 BRAM/URAM 中存储的数据。此类访问十分快速。
本地数据交互的唯一方式是通过其输出端口和输入端口。
使用本地存储器 (BRAM/LUTRAM/URAM) 访问时,存储器端口的数量可能限制对数据的访问带宽,导致流水打拍循环内出现 II 违例。
ap_memory 协议同样遵循地址和数据阶段方式来进行操作。该协议首先请求读/写资源,并等待至它收到资源可用确认为止。随后,它会发起读/写的数据传输阶段。
使用UltraRAM(URAM)有几个关键意义和优势,特别是对于需要处理大量数据或需要高性能内存解决方案的应用。以下是使用URAM的主要理由和好处:
- 增加内存容量:URAM提供了比Block RAM (BRAM)更大的存储容量。在Xilinx一些FPGA设备中,URAM可以提供高达288Kb的存储容量,这是BRAM容量的四倍。使用URAM可以在不牺牲FPGA上其他资源的情况下,增加设计的内存容量。
- 改善资源利用率:对于需要大量内存的设计,使用URAM可以更有效地利用FPGA的内存资源。通过用更少的URAM实现相同的存储需求,可以释放BRAM资源供其他用途使用,这有助于优化整体的资源分配和利用率。
- 提高性能:URAM能够提供与BRAM相似的访问速度,同时提供更大的存储容量。对于大规模数据处理和存储密集型应用,使用URAM可以减少数据访问延迟,提高系统的数据吞吐量和性能。
- 降低功耗:相对于使用多个BRAM实现同等存储容量,使用URAM可以在一定程度上降低系统的总体功耗。因为减少了所需内存单元的数量,从而降低了功耗。
- 优化数据局部性:通过在设计中合理地使用URAM,可以优化数据的局部性,减少对外部存储的访问需求。这对于那些对延迟和性能有严格要求的应用来说是非常重要的。
- 支持高级特性:在Vitis HLS中,URAM可以支持一些高级的内存管理和访问特性,如双端口访问、异步读写等,这为复杂的算法实现提供了更多的灵活性和可能性。
2. 代码解析
2.1 代码总览
以下代码展示了一个在Vitis HLS环境中设计的简单存储器模型。它实现了一个可读写的存储器,其中使用UltraRAM(URAM)作为存储介质:
#include "ap_int.h"#define ADDRBITS 14
#define NWORDS 1 << ADDRBITStypedef ap_uint<128> data_t;
typedef ap_uint<ADDRBITS> addr_t;void example(bool wren, bool rden, addr_t addrW, data_t datain,addr_t AddrR, data_t* dataout) {
#pragma HLS PIPELINE II = 1static data_t buffer[NWORDS];
#pragma HLS DEPENDENCE variable = buffer inter WAR false
#pragma HLS BIND_STORAGE variable = buffer type = ram_2p impl = uramif (rden)*dataout = buffer[AddrR];if (wren)buffer[addrW] = datain;
}
其中,
ADDRBITS 定义了地址位数,这里是14位。
NWORDS 定义了存储器的地址数,通过左移操作计算得到,即1 << 14,表示存储器中有16384(2^14)个地址。
以上代码生成的IP:
- wren:写使能信号。
- rden:读使能信号。
- addrW:写操作的地址。
- datain:写入的数据。
- AddrR:读操作的地址。
- dataout:读出的数据。
2.2 优化指令
#pragma HLS PIPELINE II = 1
这条指令指示 HLS 工具尝试以流水线方式执行这个函数,每个时钟周期开始一个新的操作(迭代间隔II=1)。
static data_t buffer[NWORDS];
#pragma HLS DEPENDENCE variable = buffer inter WAR false
#pragma HLS BIND_STORAGE variable = buffer type = ram_2p impl = uram
这段定义了一个静态的 buffer 数组,大小为 NWORDS,用作存储数据。
#pragma HLS DEPENDENCE指示编译器这个变量(buffer)不存在写后读(WAR)的数据依赖问题,优化并行执行。
#pragma HLS BIND_STORAGE将buffer绑定为双端口RAM(ram_2p),并指定实现为URAM。这使得buffer在FPGA上的物理实现是使用URAM资源。
2.3 综合报告
================================================================
== HW Interfaces
================================================================
* REGISTER
+-----------+---------+----------+
| Interface | Mode | Bitwidth |
+-----------+---------+----------+
| AddrR | ap_none | 14 |
| addrW | ap_none | 14 |
| datain | ap_none | 128 |
| dataout | ap_none | 128 |
| rden | ap_none | 1 |
| wren | ap_none | 1 |
+-----------+---------+----------+================================================================
== Bind Storage Report
================================================================
+--------------+------+------+--------+----------+---------+------+---------+
| Name | BRAM | URAM | Pragma | Variable | Storage | Impl | Latency |
+--------------+------+------+--------+----------+---------+------+---------+
| + example | 0 | 8 | | | | | |
| buffer_V_U | - | 8 | pragma | buffer_V | ram_2p | uram | 1 |
+--------------+------+------+--------+----------+---------+------+---------+================================================================
== Pragma Report
================================================================
* Valid Pragma Syntax
+--------------+---------------------------------------------+---------------------------+
| Type | Options | Location |
+--------------+---------------------------------------------+---------------------------+
| pipeline | II = 1 | example.cpp:12 in example |
| dependence | variable = buffer inter WAR false | example.cpp:15 in example |
| bind_storage | variable = buffer type = ram_2p impl = uram | example.cpp:16 in example |
+--------------+---------------------------------------------+---------------------------+
从综合报告来看,我们成功绑定了 URAM 作为 buffer 的实现方式,并且II=1。
3. 总结
本文提供了对使用 URAM 进行高性能内存解决方案设计的全面理解,详细介绍了在 Vivado IP 流程中使用 AP_Memory 进行与存储器资源通信的方法,并介绍了使用 UltraRAM(URAM)的优势和意义。通过代码解析,展示了在 Vitis HLS 环境中设计的一个简单存储器模型。