当前位置: 首页 > article >正文

FPGA学习笔记#4 Vitis HLS 入门的第一个工程

本笔记使用的Vitis HLS版本为2022.2,在windows11下运行,仿真part为xcku15p_CIV-ffva1156-2LV-e,这一篇终于没有再大量使用别人的内容,是我自己从头捋到尾的结果,不过之后的笔记还是要参照别人的教程就是了。


学习笔记:《FPGA学习笔记》索引
FPGA学习笔记#1 HLS简介及相关概念
FPGA学习笔记#2 基本组件——CLB、SLICE、LUT、MUX、进位链、DRAM、存储单元、BRAM
FPGA学习笔记#3 Vitis HLS编程规范、数据类型、基本运算
FPGA学习笔记#4 Vitis HLS 入门的第一个工程
FPGA学习笔记#5 Vitis HLS For循环的优化(1)
FPGA学习笔记#6 Vitis HLS For循环的优化(2)
FPGA学习笔记#7 Vitis HLS 数组优化和函数优化
FPGA学习笔记#8 Vitis HLS优化总结和案例程序的优化


目录

  • 1.工程的创建
  • 2.添加程序文件
  • 3.程序编写
  • 4.指定Top函数(第一次执行)
  • 5.程序运行
  •     5.1.C仿真
  •     5.2.C综合
  •     5.3.C/RTL联合仿真
  • 6.简单的优化

1.工程的创建

Vitis的安装请自行查找教程,本教程使用的Xilinx IDE为Vitis HLS,比较早的版本则可以使用Vivado HLS,功能都差不多。

首先点击Create Project创建工程。

输入工程名和工程目录,点击Next。

无视添加Design文件和Testbench文件,我们之后再加,直接点Next。

选择FPGA型号,根据自己需要写,如果想完整复现结果就选一样的,选完后点OK,再点Finish完成创建。

工程创建结束。


2.添加程序文件

在工程界面左上角是资源管理器,右键Source->New Source File,创建top.h和top.cpp(一次只能创建一个文件),然后同样的方式右键Test Bench->New Test Bench File,创建test.cpp文件。文件存储位置任意,可以放在工程根目录。

创建完成后如下图所示:

至于为什么不和其他教程里叫VectorAdd.h和.cpp,因为这样以后用这个工程直接跑别的测试没有啥违和感。


3.程序编写

我们用一个经典的测试例程,数组A的每一个元素+数据t,其结果输出到数组B中。

top.h:

// top.h
#define N 5
typedef int data_t;
void VectorAdd(data_t A[N],data_t t,data_t B[N]);

top.cpp:

// top.cpp
#include "top.h"

void VectorAdd(data_t A[N],data_t t,data_t B[N])
{
	unsigned int i;
	myloop:
	for(i=0;i<N;i++)
	{
		B[i] = A[i] + t;
	}
}

test.cpp:

#include <iostream>
#include <iomanip>
#include "top.h"

using namespace std;

int main(){
	data_t A[N] = {-4,-3,0,1,2};
	data_t c = 5;
	data_t B[N] = {0};
	data_t RefB[N] = {1,2,5,6,7};
	unsigned int i = 0;
	unsigned int errcnt = 0;

	VectorAdd(A,c,B);

	cout<<setfill('-')<<setw(30)<<'-'<<'\n';
	cout<<setfill(' ')<<setw(10)<<left<<"A";
	cout<<setfill(' ')<<setw(10)<<left<<"C";
	cout<<setfill(' ')<<setw(10)<<left<<"B"<<'\n';
	cout<<setfill('-')<<setw(30)<<'-'<<'\n';

	for ( i = 0;i<N;i++)
	{
		cout<<setfill(' ')<<setw(10)<<left<<A[i];
		cout<<setfill(' ')<<setw(10)<<left<<c;
		cout<<setfill(' ')<<setw(10)<<left<<B[i];
		if(B[i] == RefB[i])
		{
			cout<<'\n';
		}
		else
		{
			cout << "(" << RefB[i] << ")" << '\n';
			errcnt ++ ;
		}
	}

	cout << setfill('-') << setw(30) << '-' <<'\n';

	if(errcnt > 0)
	{
		cout << "Test Failed" << '\n';
		return 1;
	}
	else{
		cout<< "Test Passed" << '\n';
		return 0;
	}
}

4.指定Top函数(第一次执行)

第一次执行前,我们要先配置程序的Top函数,HLS的程序分为内核代码(Top函数及其依赖)和主机代码(Test Bench及其依赖)。

点击菜单栏Project->Project Settings。

点击Synthesis->Browse,选择仿真的Top Fuction。

选择编写的VectorAdd函数,依次点击OK后配置完成。


5.程序运行

5.1.C仿真

点击左下角的Run C Simulation,执行C仿真,得到代码的执行结果。

直接点OK。

打印内容为下,说明仿真执行成功。


5.2.C综合

点击Run C Synthesis执行C综合。

点击OK。

可以看到C代码被综合成RTL代码后,会给出其性能指标、使用的硬件资源量,以及下面会给出接口等信息。

循环迭代延迟就是从上一轮循环结束到判断是否进入下一轮循环的延迟,比如for(int i=0; i<N; i++)中i++和i<N所需的时钟周期数,Interval就是循环之间的间隔周期数。


5.3.C/RTL联合仿真

进行RTL和C的联合仿真CoSimulation。

注意这里Dump Trace要选择port,仿真后才可以查看波形。

联合仿真结束后会打印报告,主要作用为显示执行性能指标Latency,同时如果Dump Trace为port,则左上角的波形图图标会亮起,点击可以查看仿真波形。

打开波形图后,首先将原来的展示部分全部删除,然后只将Top函数(VectorAdd)生成的结果拖动到波形窗口,然后点击图中的图标展开所有信号。

然后可以看到有一些值我们直接看看不懂,那是因为它默认按照十六进制显示,右键对应的数据,然后选择Signed Decimal,因为我们使用的是有符号数据,所以选择这个。

也可以设置Signal Color来配置不同数据的颜色,看起来更加方便一些。

从这张图可以很清晰的看到A数组、B数组取出的数据,用于取出数据的地址,以及运算得到的结果。


6.简单的优化

接下来我们对Top函数进行简单的优化,因为新版本的Vitis中对每个循环默认添加了PIPELINE(流水线)优化,因此我们对top.cpp的loop进行UNROLL(展开)优化。

首先New一个Solution:

编写solution的名称,并确定是否从其他solution中拷贝约束,因为solution1中没有配置任何约束,所以勾不勾选都可以。

添加solution后会自动切换到该solution,正在使用的solution图标左上角会有一个对钩。

选择top.cpp,点击右侧的Directive(没有的可以在Window->Show View->Directive打开),右键myloop标签,添加约束。

选择UNROLL,并点击OK,完成添加,这里选择Directive File会将约束语句放在solution_name/constraints/directive.tcl中,选择Source File会将约束语句直接写在程序中,这里以Source File为例,因为之后也会用到在程序中直接编写约束的情况。

添加Source约束后会在for循环左大括号的下一行添加#pragma HLS UNROLL,这也是我为什么目前更喜欢添加到源文件,因为学习起来更加直观一些,添加到directive文件的话测试移植等则更加方便。

再次执行C仿真,可以得到结果如下,应该是很明显有效率的提升,那我们该怎么更方便的对比呢?Vitis HLS提供了多个Solution仿真报告的比较功能。

点击Project->Compare Reports。

将左侧的可选报告双击或Add到右边,上下顺序在对比报告中会对应左右顺序,可以在这里调整。

生成的对比报告可以更清楚的区分和对比各个solution的性能,因为它把运行时间、Latency、资源消耗都分开展示,所以这个功能也可以用来分析单个报告,可以更直观一些。

性能对比:

资源使用量对比:

可以看到性能提升很明显,同时LUT的使用量也变多了,是用资源换取性能的操作。


http://www.kler.cn/a/392875.html

相关文章:

  • 【安全编码】Web平台如何设计防止重放攻击
  • Unity3D仿星露谷物语开发8之角色移动
  • springboot使用自定义的线程池 完成 多线程执行网络请求,返回数据后,统一返回给前段
  • Go C编程 第6课 无人机 --- 计算旋转角
  • Java 异常类详细介绍
  • Spring Boot对访问密钥加解密——HMAC-SHA256
  • 人工智能理论之opencv图像预处理、数据库、GUI布局的综合应用(图像预处理版块)
  • 【GPT使用技巧】用AI出一门课
  • 阿里云智能语音交互产品试用,基于语音识别、语音合成、自然语言理解
  • 将Docker中nginx静态资源目录映射到宿主机的某个目录及配置文件映射到宿主机
  • 大语言模型LLM综述
  • day13|C++重难点之 静态变量、全局变量、局部变量的区别,在内存上是怎么分布的、指针和引用的区别、C++内存分区
  • 想让三维模型与实时视频融合?这款软件值得一试
  • 大模型落地之ollama控制设备
  • 【MySQL】explain之type类型
  • Rust学习(四):作用域、所有权和生命周期:
  • MATLAB 使用教程 —— 命令窗口输入命令,工作区显示变量
  • Halcon深度学习之全局上下文异常值模型
  • 使用热冻结数据层生命周期优化在 Elastic Cloud 中存储日志的成本
  • python如何使用Rabbitmq
  • 从入门到了解C++系列-----内存管理 + 初步了解模板
  • CSS Modules是什么?
  • 【软件开发】Spring 面向切面编程(头歌作业)
  • 小程序租赁系统打造便捷租赁体验助力共享经济发展
  • HO-PEG-MACA中PEG的修饰使其提高了稳定性,有助于其在各种溶剂中保持稳定的性能。
  • 冗余连接2 hard题 代随C#写法