Vitis HLS 学习笔记--global_array_RAM初始化及复位

目录

1. 简介

2. 示例代分析

2.1 源代码

2.2 URAM 不可用 

2.3 代码功能解释

2.4 综合报告

2.4.1 顶层控制接口

2.4.2  软件 IO 信息

2.4.3 存储绑定

3. 对比两种 solution

3.1 solution_A

3.2 solution_B

4. 总结


1. 简介

在C++程序中,数组是一种基本的数据结构,用来存储一系列的数据。程序员可以动态地分配和释放数组的内存空间。

但是在将程序综合到硬件上时,就不能再动态地分配内存了,因为硬件需要提前知道需要多少内存来存储数组的数据。在FPGA上,有一个本地存储器,相比于全局存储器(比如DDR或HBM存储器),本地存储器的访问速度更快,通常只需要一个或多个周期。

本文例子展示了如何将全局数组映射到具有不同实现的RAM,并展示了它们如何初始化以及如何重置。

2. 示例代分析

2.1 源代码

#include <ap_int.h>ap_int<10> A[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
ap_int<10> B[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
ap_int<10> C[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};int example(int i) {
#pragma HLS BIND_STORAGE variable = A type = RAM_2P impl = BRAM
#pragma HLS BIND_STORAGE variable = B type = RAM_2P impl = LUTRAMA[i] += B[i] + C[i];B[i] += 5;C[i] += 10;int result = (A[i] + B[i] + C[i]).to_int();return result;
}

2.2 URAM 不可用 

// #pragma HLS BIND_STORAGE variable=C type=RAM_2P impl=URAM 

该指令不可用!

有用户提出了类似的问题,发现即使使用了 #pragma HLS BIND_STORAGE 指令指定将数组存储到 URAM 中,综合报告显示每个 URAM 单元只存储了一个数组元素,而没有充分利用 URAM 的容量。解决方法是在代码中手动对数据进行打包,将多个较小位宽的数打包成一个更大位宽的数后存入 URAM。

这表明,虽然 URAM 可以通过手动优化来使用,但 Vitis HLS 可能没有直接支持全局数组使用 URAM 的内置机制。

2.3 代码功能解释

首先定义三个数组:A、B 和 C,每个数组都包含了 10 个 ap_int<10> 类型的元素。这些数组在 HLS 中被绑定到不同的存储实现类型上。

#pragma HLS BIND_STORAGE 是用于指定存储实现类型的指令。在这里,我们有两个绑定:

  • A 使用 BRAM(Block RAM)作为存储实现类型。
  • B 使用 LUTRAM(Look-Up Table RAM)作为存储实现类型。

然后,对这些数组进行了一系列操作:

  • A[i] += B[i] + C[i]:将 B[i] 和 C[i] 的值相加,并将结果加到 A[i] 上。
  • B[i] += 5:将 B[i] 的值增加 5。
  • C[i] += 10:将 C[i] 的值增加 10。
  • 最后,计算了 A[i] + B[i] + C[i] 的和,并将其转换为整数类型,然后返回该结果。 

2.4 综合报告

2.4.1 顶层控制接口

包含:块级控制协议、时钟、复位、中断;

* TOP LEVEL CONTROL
+-----------+---------------+-----------+
| Interface | Type          | Ports     |
+-----------+---------------+-----------+
| ap_clk    | clock         | ap_clk    |
| ap_rst_n  | reset         | ap_rst_n  |
| interrupt | interrupt     | interrupt |
| ap_ctrl   | ap_ctrl_chain |           |
+-----------+---------------+-----------+

2.4.2  软件 IO 信息

================================================================
== SW I/O Information
================================================================
* Top Function Arguments
+----------+-----------+----------+
| Argument | Direction | Datatype |
+----------+-----------+----------+
| i        | in        | int      |
| return   | out       | int      |
+----------+-----------+----------+* SW-to-HW Mapping
+----------+---------------+----------+-------------------------------------+
| Argument | HW Interface  | HW Type  | HW Info                             |
+----------+---------------+----------+-------------------------------------+
| i        | s_axi_control | register | name=i offset=0x18 range=32         |
| return   | s_axi_control | register | name=ap_return offset=0x10 range=32 |
+----------+---------------+----------+-------------------------------------+

2.4.3 存储绑定

变量A、B、C和编译指令期望的输出是一致的:

================================================================
== Bind Storage Report
================================================================
+-----------+------+------+--------+----------+---------+--------+---------+
| Name      | BRAM | URAM | Pragma | Variable | Storage | Impl   | Latency |
+-----------+------+------+--------+----------+---------+--------+---------+
| + example | 1    | 0    |        |          |         |        |         |
|   B_V_U   | -    | -    | pragma | B_V      | ram_2p  | lutram | 1       |
|   C_V_U   | -    | -    |        | C_V      | ram_1p  | auto   | 1       |
|   A_V_U   | 1    | -    | pragma | A_V      | ram_2p  | bram   | 1       |
+-----------+------+------+--------+----------+---------+--------+---------+

3. 对比两种 solution

3.1 solution_A

对 kernel 代码不做复位相关编译指令,进行综合后,查看图示文件:

在 HLS 设计中,为了初始化全局 RAM 数组(不包括URAM),会生成一种特定的结构,这种结构专门用于配置 BRAM/LUTRAM:

---
变量A
---
(* ram_style = "block" *)reg [DataWidth-1:0] ram[0:AddressRange-1];initial begin$readmemh("./example_A_V_RAM_2P_BRAM_1R1W.dat", ram);
end---
变量B
---
(* ram_style = "distributed" *)reg [DataWidth-1:0] ram[0:AddressRange-1];initial begin$readmemh("./example_B_V_RAM_2P_LUTRAM_1R1W.dat", ram);
end

*.dat文件包含相应数组的初始值。

3.2 solution_B

对 kernel 代码添加优化指令:

#pragma HLS reset variable=A
#pragma HLS reset variable=B
#pragma HLS reset variable=C

进行综合后,可以看到当对 BRAM/LUTRAM 使用复位指令生成的代码结构:

解释:

当在静态数组/全局数组(这里的A、B、C)上使用复位指令后,生成的RTL代码中,每个数组都会通过ROM和RAM来实现。数组的初始值只会被加载到ROM里面,这一点和solution_A是一样的。

但是,每当复位信号被激活,从数组读取的数据就默认会来自ROM。当然,如果有新数据写入了某个地址,该地址将被记录,滞后读取的数据就会转到RAM中。这样做的结果是,每次重置之后,数组都会回到它的初始状态,就像重新启动一样。

三个数组 A/B/C 的相同结构如下所示:

module example_A_V_RAM_2P_BRAM_1R1W
#(parameterDataWidth    = 10,AddressWidth = 4,AddressRange = 10
)(input  wire                    clk,input  wire                    reset,input  wire [AddressWidth-1:0] address0,input  wire                    ce0,output wire [DataWidth-1:0]    q0,input  wire [AddressWidth-1:0] address1,input  wire                    ce1,input  wire                    we1,input  wire [DataWidth-1:0]    d1
);
//------------------------Local signal-------------------
reg  [AddressRange-1:0] written = {AddressRange{1'b0}};
wire [DataWidth-1:0]    q0_ram;
wire [DataWidth-1:0]    q0_rom;
wire                    q0_sel;
reg  [0:0]              sel0_sr;
//------------------------Instantiation------------------
example_A_V_RAM_2P_BRAM_1R1W_ram #(.DataWidth(DataWidth),.AddressWidth(AddressWidth),.AddressRange(AddressRange))
example_A_V_RAM_2P_BRAM_1R1W_ram_u(.clk      ( clk ),.reset    ( reset ),.ce0      ( ce0 ),.address0 ( address0 ),.q0       ( q0_ram ),.ce1      ( ce1 ),.address1 ( address1 ),.we1      ( we1 ),.d1       ( d1 )
);example_A_V_RAM_2P_BRAM_1R1W_rom #(.DataWidth(DataWidth),.AddressWidth(AddressWidth),.AddressRange(AddressRange))
example_A_V_RAM_2P_BRAM_1R1W_rom_u(.clk      ( clk ),.ce0      ( ce0 ),.address0 ( address0 ),.q0       ( q0_rom )
);
//------------------------Body---------------------------
assign q0     = q0_sel? q0_ram : q0_rom;
assign q0_sel = sel0_sr[0];always @(posedge clk) beginif (reset)written <= 1'b0;else beginif (ce1 & we1) beginwritten[address1] <= 1'b1;endend
endalways @(posedge clk) beginif (ce0) beginsel0_sr[0] <= written[address0];end
endendmodule

语句说明:

assign q0     = q0_sel? q0_ram : q0_rom;

用于选择输出数据来源于 RAM 或者 ROM。而 q0 来自于 written[address0]。

reg  [AddressRange-1:0] written = {AddressRange{1'b0}};

用于记录某个地址是否被写入过,写入过的地址会被标记,下次读取时,就会从 RAM 中读取。

4. 总结

在本文中,我们探讨了如何在Vitis HLS中处理FPGA的全局数组映射和初始化问题。通过示例代码,我们了解了如何将C++数组映射到不同类型的RAM,并使用#pragma HLS BIND_STORAGE指令来指定存储实现。我们还讨论了URAM的使用限制和手动数据打包的解决方案。最后,我们比较了两种解决方案:一种是不使用复位指令的solution_A,另一种是使用复位指令的solution_B。solution_B通过ROM和RAM的结合,提供了一种在复位信号激活时能够将数组恢复到初始状态的方法。这些知识对于理解和优化FPGA设计中的内存管理至关重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/25377.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库漫谈-MongoDB

MongoDB是非关系型数据库&#xff0c;适合存储文档&#xff0c;存储大数据。MongoDB其实是广告公司发明的&#xff0c;因为现有的关系型数据库不适合广告行业&#xff0c;所以他们就自己做了一个数据库。MongoDB具有如下几个特点&#xff1a; 1、高可用。它是分布式数据库&…

LLM的基础模型8:深入注意力机制

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;则提…

jspm基于Java Web的网上购物系统的设计与实现-手把手调试搭建

jspm基于Java Web的网上购物系统的设计与实现-手把手调试搭建 jspm基于Java Web的网上购物系统的设计与实现-手把手调试搭建

整理好了!2024年最常见 20 道分布式、微服务面试题(六)

上一篇地址&#xff1a;整理好了&#xff01;2024年最常见 20 道分布式、微服务面试题&#xff08;五&#xff09;-CSDN博客 十一、什么是服务网格&#xff08;如Istio或Linkerd&#xff09;&#xff1f; 服务网格&#xff08;Service Mesh&#xff09;是一种微服务架构中的基…

在线按模板批量生成文本工具

具体请前往&#xff1a;在线按模板批量生成文本工具

URL的编码解码(一),仅针对ASCII码字符

用十六进制对特定字符编码&#xff0c;利用百分号标识搜索字符串解码十六进制字符。 (笔记模板由python脚本于2024年06月09日 18:05:25创建&#xff0c;本篇笔记适合喜好探寻URL的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free…

Java Set系列集合的使用规则和场景(HashSet,LinkedHashSet,TreeSet)

Set集合 package SetDemo;import java.util.HashSet; import java.util.Iterator; import java.util.Set;public class SetDemo {public static void main(String[] args) {/*Set集合的特点&#xff1a;1.Set系列集合的特点&#xff1a;Set集合是一个存储元素不能重复的集合方…

Synchronized的锁膨胀艺术:深入源码的探险之旅

1. 引言 在Java的并发编程中,synchronized关键字一直扮演着举足轻重的角色。然而,随着并发需求的不断增长和性能要求的日益提高,单纯的synchronized关键字已经无法满足所有场景的需求。从JDK 1.6开始,Java对synchronized进行了深度的优化,其中最为引人注目的便是“锁膨胀…

如何使用 Python 的字典来存储和检索数据,以提高数据操作的效率?

Python 的字典&#xff08;Dictionary&#xff09;是一种基于键值对的数据结构&#xff0c;它提供了高效的数据存储和检索方式。以下是一些使用字典来提高数据操作效率的技巧&#xff1a; 使用合适的键&#xff1a; 选择不可变类型&#xff08;如字符串、数字或元组&#xff09…

VB6.0 调用存储过程

最近有在做一个需求&#xff0c;需要在VB6.0中调用存储过程&#xff0c;整理了一下&#xff0c;供大家参考&#xff0c; 范例&#xff1a; 1 Function callStoredProcedure(sEmployeeID As String, Optional sNotes As String "") As String2 On Error GoTo er…

Vue13-计算属性的简写

一、计算属性的简写 注意&#xff1a; 当计算属性只有get&#xff0c;没有set的时候&#xff0c;才能用简写形式&#xff01;&#xff01;&#xff01;

svn的使用

【图文详解】入职必备——SVN使用教程-CSDN博客 使用SVNBucket作为服务端,来辅助学习. 什么时候会产生冲突呢? 原本A,B,服务器的版本都一致,都是最新版. A修改文件m,向服务器提交 B修改文件m,向服务器提交,这时候出现了冲突 双击冲突的文件,手动修改

---java 抽象类 和 接口---

抽象类 再面向对对象的语言中&#xff0c;所以的对象都是通过类来描述的&#xff0c;但如果这个类无法准确的描述对象的 话&#xff0c;那么就可以把这个类设置为抽象类。 实例 这里用到abstract修饰&#xff0c;表示这个类或方法是抽象方法 因为会重写motifs里的show方法…

【爬虫实战项目一】Python爬取豆瓣电影榜单数据

目录 一、环境准备 二、编写代码 2.1 分页分析 2.2 编码 一、环境准备 安装requests和lxml pip install requests pip install lxml 二、编写代码 2.1 分页分析 编写代码前我们先看看榜单的url 我们假如要爬取五页的数据&#xff0c;那么五个url分别是&#xff1a; htt…

Python基础教程(七):函数编程-从基础到进阶

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

再读高考作文题

新课标I卷&#xff1a;讨论了随着互联网和人工智能的普及&#xff0c;问题是否会变得越来越少&#xff0c;要求考生写一篇文章&#xff0c;表达自己对于这一现象的联想和思考。 从来就没有什么救世主 AI也不是​​​​​ 一直不会写作文&#xff0c;直到高中&#xff0c;才堪堪…

【环境搭建】5.阿里云ECS服务器 安装Nginx

在阿里云的 Alibaba Cloud Linux 3.2104 LTS 64位系统上安装 Nginx&#xff0c;您可以按照以下步骤进行。Alibaba Cloud Linux 基于 CentOS&#xff0c;因此大部分步骤与 CentOS 系统类似。 步骤 1&#xff1a;更新系统软件包 首先&#xff0c;更新系统软件包以确保所有软件包…

Java Web学习笔记30——打包部署

打包&#xff1a; 到资源管理器中再看下&#xff1a; 将这些文件压缩成一个zip文件&#xff0c;然后到nginx的html目录中执行unzip 解压即可。 部署&#xff1a; Nginx&#xff1a;Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代…

Leetcode 3177. Find the Maximum Length of a Good Subsequence II

Leetcode 3177. Find the Maximum Length of a Good Subsequence II 1. 解题思路2. 代码实现 题目链接&#xff1a;3177. Find the Maximum Length of a Good Subsequence II 1. 解题思路 这一题我一开始的思路是直接使用暴力的动态规划的方式进行实现&#xff0c;结果遇到了…

使用JMeter软件压测接口配置说明

1、下载完该软件https://blog.csdn.net/wust_lh/article/details/86095924 2.点击bin文件中jmeter.bat脚本https://blog.csdn.net/wust_lh/article/details/86095924 3.官网地址https://jmeter.apache.org/download_jmeter.cgi 通过 【Options】->【Choose Language】变更为…