Vitis HLS 加法器(整数)设计

目录

一、简介

二、安装jtag

 三、vitis HLS

1.创建工程

         2.软件设计

3.编译

①C Simulation(C 语言仿真)

②C Synthesis (C 语言综合)  

③Co-Simulation(协同仿真)

④Export RTL (导出 RTL)

四、vivado

五、vitis


一、简介

Vitis HLS 是一种高层次综合工具, 支持将 C、 C++ 和 OpenCL函数硬连线到器件逻辑互连结构和 RAM/DSP 块上。Vitis HLS 可在 Vitis 应用加速开发流程中实现硬件内核, 并使用 C/C++ 语言代码在 Vivado Design Suite 中为赛灵思器件设计开发 RTL IP。使用Vitis HLS开发时,最好不要再使用C语言,而是C++。

二、安装jtag

在linux下使用vitis下载程序需要jtag,但是需要我们自己手动安装。找到vivado的安装目录:

cd  /opt/Xilinx/Vivado/2020.2

cd  ./data/xicom/cable_drivers/lin64/install_script/install_drivers

sudo ./install_drivers

 三、vitis HLS

使用vitis HLS设计加法器IP核,供在vivado调用次模块实现电路加法功能。

1.创建工程

添加工程名字和目录

 点击NEW File创建所需要的文件,设计文件:add.cpp 和add.h   顶层函数文件这里不设置,Top Function 这里可以不用管,后面再设置顶层函数文件。IP核就是由顶层文件综合出来的。

然后添加testbench测试文件,这在做C综合过程中也是必不可少的,添加方法更上面添加顶层文件和头文件是一样的。

 然后选择开发板信息

 

 选择pynq-z2

 点击完成,主界面如下图

 2.软件设计

在add.cpp添加如下代码

int add(int a, int b)
{
	return (a+b);
}

在add.h添加如下代码

#ifndef add_h_
#define add_h_
int add(int, int);
#endif

在add_tb.cpp添加如下代码

#include "add.h"
#include <iostream>
#include <cstdio>
#include <fstream>
int main()
{
	int a, b;
	a = 5;
	b = 10;
	int res;
	res = add(a, b);
	if(res == 15)
	{
		printf("OK");
		return 0;
	}
	else
		return 1;
}

testbench文件 中一般都会有一个验证顶层函数是否正确的语句,如果一个 main 函数的返回值是0的话,程序就是正确的,如果返回值是1的话(条件是我们自己设定的),程序在做C仿真的时候是会出现错误的。

设置顶层函数文件

右键点击add.cpp

 设置add.cpp为整个工程的顶层函数文件

最后要是设置接口,添加 AXI接口协议 。接口不仅涉及到数据的输入输出效率,还涉及到生成IP之后,如何进行和PS的连接等问题。

点击到 add.cpp 顶层文件,再点击 Directive ,如下图所示

 分别用右键点击这三个对象,然后点 Insert Directive。

选择 Directive 类型 INTERFACE ,再选择 mode 类型为 s_axiite 。三个对象都要这样操作。

 3.编译

只有依次执行如下四步即可仿真、综合、联合仿真、导出

 ①C Simulation(C 语言仿真

支持您为已打开的工程启动 C 语言仿真

在 Vitis HLS 流程中, 验证可分为 2 个独立进程

综合前确认, 用于确认 C 语言程序是否正确实现了所需的功能
综合后验证, 用于验证生成的 RTL 代码是否按期望的方式来执行

这两个进程都称为仿真: C 语言仿真和 C/RTL 协同仿真。

综合之前, 应使用 C 语言仿真通过测试激励文件确认要综合的函数。 C 语言测试激励文件包含一个 main() 顶层函数, 用于调用函数以供 Vitis HLS 工程进行综合。测试激励文件还可包含其它函数。理想的测试激励文件具有以下功能特性:

①测试激励文件可以自查, 并确认要综合的函数的结果是否正确。
②如果结果正确, 测试激励文件将向 main() 返回 0 值。否则, 测试激励文件应返回任何非零值。

 点击仿真

在此对话框中单击“OK”后, 就会编译 C 语言代码并运行 C 语言仿真。运行仿真时, 该控制台会显示来自测试激励文件的任何 printf 语句或者来自内核或 IP 的 hls::print 语句。仿真成功完成后, 还会向控制台返回以下消息:

C 语言仿真完成后, 就会在 solution 文件夹内创建 csim 文件夹。该文件夹包含以下元素:

csim/build: C 语言仿真相关的所有文件的主要位置
        ○ 测试激励文件所读取的所有文件都会复制到此文件夹中
        ○ 在此文件夹中创建并运行 C 语言可执行文件 csim.exe
        ○ 测试激励文件写入的所有文件都是在此文件夹中创建的
        ○ csim/obj: 包含用于已编译的源代码的对象文件 (.o)用于源代码构建的依赖关系文件 (.d)
csim/report: 包含用于 C 语言仿真构建和运行的 log 日志文件

②C Synthesis (C 语言综合)  

用于启动 C 语言源代码以便在 Vitis HLS 中执行 RTL 综合

C/C++ 语言源代码将综合到 RTL 实现中。综合进程期间, 消息将被转录到控制台窗口内, 并记录到 vitis_hls.log文件中。当综合完成后, Vitis HLS 会在信息窗格中自动打开顶层函数的“Synthesis Summary” (综合汇总) 报告。

 General Information:(常规信息)可提供有关报告生成时间、所用软件版本、工程名称、解决方案名称和目标流程以及技术详情的信息。

Timing Estimate:(时序估算)可显示解决方案所指定的时序的快速估算结果, 如指定时钟频率中所述。其中包括指定的“Target” (目标) 时钟周期和“Uncertainty” (不确定性) 的周期。时钟周期减去不确定性即可生成“Estimated”(估算) 时钟周期。

Performance & Resource Estimates

Performance Estimate:(性能估算) 列可报告顶层函数和顶层中例化的任何子块的时延和启动时间间隔。 C/C++ 源代码中在此级别调用的每个子函数都是生成的 RTL 块中的一个实例, 除非使用 INLINE 编译指示或指令将该子函数内联(或者自动内联) 到顶层函数内。
 

• Slack (裕量) 列可显示实现中的任何时序问题

• Latency(时延) 列可显示生成输出所需的周期数和时间 (ns)

• Initiation Interval(启动时间间隔) 是可应用新输入之前的时钟周期数

如果时延显示为“?” , 则表示 Vitis HLS 无法确定循环迭代次数
• Iteration Latency(迭代时延) 表示单个循环的单次迭代的时延

• Trip Count(循环次数) 列显示的是特定循环在已实现的硬件内的迭代次数。它用于反映硬件中的任意循环展开行为

• BRAM、 DSP、 FF 和 LUT 列用于指示实现 RTL 代码中的软件函数所需的资源估算结果

HW Interfaces(硬件接口) 部分提供了对应于综合期间生成的不同硬件接口的表格。该工具生成的硬件接口类型取决于解决方案所指定的流程目标以及应用于代码的任何 INTERFACE 编译指示或指令。在上图中, 该解决方案目标为 Vitis 内核流程, 因此会按需生成 AXI 接口。

查看这些表格时, 应注意下列信息:

• 针对不同接口提供了不同的表格
• 所提供的列用于显示接口的不同属性

• Bundle (捆绑) 列可显示来自 INTERFACE 编译指示或指令的任意指定的捆绑名称
• Bit Fields (位字段) 列可显示 s_axilite 接口中寄存器所使用的位

 

SW I/O Information:(软件 I/O 信息)会高亮来自 C/C++ 源代码的函数实参与生成的 RTL 代码中的端口名称之间的关联方式。

完成综合后, 就会在 solution 文件夹内创建 syn 文件夹。该文件夹包含以下元素:

• verilog 和 vhdl 文件夹包含输出 RTL 文件
        ○ 顶层文件与综合的顶层函数同名
        ○ 针对尚未内联到更高层次的函数中的每个子函数, 都会创建一个 RTL 文件
        ○ 此外还可能包含其它 RTL 文件, 用于实现 RTL 层级的子块
• report 文件夹包含顶层函数的报告文件, 对于 Vitis HLS 尚未内联到更高层次函数中的每个子函数, 还各包含一个报告文件。顶层函数的报告提供了有关整个设计的详细信息。

③Co-Simulation(协同仿真

允许您启动 Vitis HLS 中的 C/RTL 协同仿真

测试激励文件会为综合验证顶层函数输出, 如果输出正确, 则会向测试激励文件的main() 函数返回 0 值。 Vitis HLS 针对 C 语言仿真和 C/RTL 协同仿真使用相同的返回值, 以判定结果是否正确。如果C 语言测试激励文件返回非 0 值, Vitis HLS 就会报告仿真失败。

C/RTL 协同仿真完成后, 控制台会显示以下消息以确认验证成功

仿真后, Vitis HLS GUI 会自动切换至Analysis(分析) 透视图, 并打开Cosimulation Report (协同仿真报告), 其中显示状态为通过或失败。

 C/RTL 协同仿真完成后, 就会在 solution 文件夹内创建 sim 文件夹。该文件夹包含以下元素:

• sim/report 文件夹中包含对应仿真的每一类 RTL 的报告和 log 日志文件


• 对于验证的每一种 RTL 语言, 都会创建一个验证文件夹, 名为 sim/verilog 或 vhdl
        ○ 用于仿真的 RTL 文件存储在 verilog 或 vhdl 文件夹内
        ○ RTL 仿真在验证文件夹内执行

        ○ 所有输出(如追踪文件和波形文件) 都写入 verilog 或 vhdl 文件夹


• 其它文件夹(如 sim/autowrap、 tv、 wrap 和 wrap_pc) 均为 Vitis HLS 使用的工作文件夹。这些文件夹内不含任何用户文件。

C/RTL 协同仿真流程使用运行 main() 函数的 C 语言测试激励文件来自动验证行为仿真中运行的 RTL 设计。 C/RTL 验证进程由 3 个阶段组成:

①执行 C 语言仿真, 顶层函数输入或待测设计 (DUT) 将保存为“输入矢量”

②“输入矢量”在 RTL 仿真中使用, 此类 RTL 仿真使用的是在 Vivado 仿真器或受支持的第三方 HDL 仿真器中由Vitis HLS 创建的 RTL。 RTL 输出或仿真结果将保存为“输出矢量”

③RTL 仿真返回的“输出矢量”将返回至 C 语言测试激励文件的 main() 函数, 以验证结果是否正确。 C 语言测试激励文件在某些情况下通过与已知良好的结果相比较来执行结果验证

④Export RTL (导出 RTL

支持您导出已打开的工程, 如 导出 RTL 设计 中所述

RTL 导出选择

导出格式默认位置解释
Vivado IP (.zip)
 
solution/impl/
export.zip
此 IP 作为 ZIP 文件导出, 可添加到 Vivado IP 目录内。impl/ip 文件夹还包含解压后的 IP 的内容
 
Vitis 内核 (.xo)
 
solution/impl/
export.xo
 
XO 文件输出可在应用加速开发流程内供 Vitis 编译器用于执行链接。可将 Vitis 内核与其它内核及目标加速器卡相链接, 来为加速应用构建 xclbin 文件
Vivado IP
 

solution/impl/ip
该选项创建的 IP 可搭配 System Generator for DSP 的 Vivado版本一起使用。
 


 导出成功后会在控制台输出以下信息

 运行“Export RTL” (导出 RTL) 命令时, Vitis HLS 会写入活动解决方案的 impl 文件夹

• export.zip: IP 及其内容的 zip 存档。此 zip 文件可直接添加到 Vivado IP 目录中
• impl/ip: 解压后的 IP 内容
• impl/ip/example: 此文件夹内包含用于生成封装后的 IP 的 Tcl 脚本和用于导出此 IP 的 shell 脚本
• impl/verilog: 包含 Verilog 格式的 RTL 输出文件
• impl/vhdl: 包含 VHDL 格式的 RTL 输出文件

至此加法器IP设计完成。

四、vivado

这里就只记录怎么导入IP,关于vivado操作可以看前面的笔记:vivado

首先创建工程,然后添加ZYNQ IP核,下面就是导入加法器IP核

按如下步骤添加即可。

 然后核添加ZYNQ IP核一样的操作添加加法器IP核

然后自动连线,ZYNQ IP核可以不用修改。

 然后就是生产顶层HDL文件,生产位流文件并导出硬件信息(Export Hardware)。启动vitis进行软件设计。

五、vitis

 创建vitis相关工程请参考上面vivado的笔记链接。

点开导航栏左侧的 Project Explorer 

 xadd.h头文件存放着我们调用自定加法器IP核 的库函数(或者叫做 驱动),文件名字与IP核命名相关,只是在前面加了一个'x'。

 xparameters.h头文件里面有我们所用到的加法器IP核映射到FPGA的DDR中的内存地址和相关驱动参数

#include <stdio.h>
#include "xil_printf.h"
#include "xadd.h"

int main()
{
    print("Hello World\n\r");

    XAdd MyAdd;
    int ps_res;
	int ps_a = 15;
	int ps_b = 5;
	int pl_res, pl_a, pl_b;
    int status;

    status = XAdd_Initialize(&MyAdd, XPAR_ADD_0_DEVICE_ID);
    if(status == XST_SUCCESS)
    {
    	print("IP Initialize successfully !\n\r");
    }

    XAdd_Set_a(&MyAdd, ps_a);
    XAdd_Set_b(&MyAdd, ps_b);
    XAdd_Start(&MyAdd);
    while(!XAdd_IsDone(&MyAdd));

    pl_a = XAdd_Get_a(&MyAdd);
    pl_b = XAdd_Get_b(&MyAdd);
    pl_res = XAdd_Get_return(&MyAdd);
    ps_res = ps_a + ps_b;

    printf("\n\ARM(PS) : %d + %d = %d \n\r", ps_a, ps_b, ps_res);
    printf("\n\rFPGA(PL) : %d + %d = %d", pl_a, pl_b, pl_res);

    return 0;
}

首先需要定义 XAdd 类型的结构体 MyAdd ,再调用 XAdd_Initialize() 初始化 IP核

然后定义PS端(ZYNQ,ARM)和PL(FPGA)端的变量,利用 XAdd_Set_a() 和 XAdd_Set_b() 把变量送到PL端,接着调用XAdd_Start() 启动PL端的 IP核 开始计算,然后利用 while(!XAdd_IsDone(&MyAdd)); 阻塞方式等待 IP核 运算完毕。

最后用 XAdd_Get_return() 取得 IP核 的返回值。最终用ARM和FPGA做计算,对比结果,验证是否有误。

XAdd 结构体类型以及对 IP核 的调用的函数全部来自于头文件 xadd.h 中。其中 XAdd_Initialize() 的第二个参数是 IP核 的 ID ,定义在xparameters.h 头文件中。

最后编译下载。
 

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是一个简单的 Vitis HLS 设计案例: 假设我们有一个输入为整数数组和一个常数值的函数,需要将数组中的每个元素与该常数值相加并返回新的数组。我们可以使用 Vitis HLS 设计这个函数。 第一步:定义输入和输出 我们需要定义输入和输出的数据类型和大小。在这个案例中,我们定义输入为一个大小为 10 的整数数组和一个常数值,输出为一个大小为 10 的整数数组。因此,我们可以使用以下代码定义输入和输出: ```c++ #define N 10 typedef int in_data_t; typedef int out_data_t; void array_add(in_data_t input[N], in_data_t constant, out_data_t output[N]) { ... } ``` 第二步:编写算法 我们需要编写一个算法,将输入数组中的每个元素与常数值相加,并将结果存储在输出数组中。这可以使用一个简单的 for 循环完成,如下所示: ```c++ void array_add(in_data_t input[N], in_data_t constant, out_data_t output[N]) { for (int i = 0; i < N; i++) { output[i] = input[i] + constant; } } ``` 第三步:进行 Vitis HLS 优化 在进行 Vitis HLS 优化之前,我们需要将输入和输出数据类型转换为 ap_int 和 ap_fixed 类型,以便在 FPGA 上进行计算。我们还需要添加一些 HLS 指令来告诉编译器如何优化代码。 ```c++ #include "ap_int.h" #include "ap_fixed.h" #define N 10 typedef ap_int<32> in_data_t; typedef ap_int<32> out_data_t; #pragma HLS INTERFACE s_axilite port=return bundle=control #pragma HLS INTERFACE s_axilite port=input bundle=control #pragma HLS INTERFACE s_axilite port=constant bundle=control #pragma HLS INTERFACE s_axilite port=output bundle=control void array_add(in_data_t input[N], in_data_t constant, out_data_t output[N]) { #pragma HLS PIPELINE II=1 #pragma HLS INTERFACE axis port=input #pragma HLS INTERFACE axis port=output for (int i = 0; i < N; i++) { #pragma HLS UNROLL output[i] = input[i] + constant; } } ``` 在这个例子中,我们使用了以下 HLS 指令: - `#pragma HLS PIPELINE II=1`:指定流水线间隔为 1,以最大化吞吐量。 - `#pragma HLS INTERFACE axis port=input` 和 `#pragma HLS INTERFACE axis port=output`:指定输入和输出流的类型为 AXIS,这是一种常用的数据接口。 - `#pragma HLS UNROLL`:指定循环展开,以最大化吞吐量。 第四步:编译和验证 最后,我们需要使用 Vivado HLS 编译代码,并在 FPGA 上验证结果是否与预期相符。这可以通过 Vivado 开发环境中的仿真和合成工具完成。如果一切正常,我们可以将生成的 IP 核组成一个 Vivado 设计,并将其部署到 FPGA 上以实现加速。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Super.Bear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值