vivado和谐教程:
https://www.bilibili.com/read/cv15414254/
Vivado 2018.3 软件及license的下载地址:
链接:https://pan.baidu.com/s/1jkurhTLgnxavgRnmi-JLDA
提取码:sygh 作者:不吃葱的酸菜鱼 https://www.bilibili.com/read/cv15414254/
出处:bilibili
1. HLS是什么?与VHDL/Verilog编程技术有什么关系?
HLS是高层次综合的缩写,它是一种将高级语言(比如C/C++)描述的算法转换成数字电路的技术。在HLS中,用户可以使用高级语言描述其算法,然后自动将其转换成数字电路的形式。
VHDL和Verilog是用于数字电路描述的硬件语言,与HLS的关系是,HLS将高级语言转化为数字电路,而VHDL和Verilog则是直接用于数字电路的描述语言。在设计数字电路时,HLS可以作为一种辅助工具来快速设计和验证数字电路,而VHDL和Verilog则更为底层,需要对硬件的细节有深入的理解。
2. HLS有哪些关键技术问题?目前存在什么技术局限性?
HLS的关键技术问题包括算法建模、数据通路优化、资源分配和调度、存储器管理、高速数字信号处理等方面。具体来说,主要有以下几个方面:
高级语言到硬件描述语言的转换算法:实现从高级语言到硬件描述语言的自动转换算法是HLS的核心技术之一。
数据通路的优化:通过对数据通路的优化,可以实现更高效、更紧凑的电路设计。
资源分配和调度:资源分配和调度是为了最大化利用FPGA资源,并且实现设计的最佳性能。
存储器管理:在HLS设计中存储器多用于线缓存、阵列乘法器和存储器控制器等,因此存储器管理也是HLS关键技术之一。
目前,HLS存在一些技术局限性,如下所示:
1.HLS编译过程需要消耗大量时间,特别是当需要与其他工具集成时。
2.HLS可能会在代码优化、资源利用和平衡上存在问题,使得生成的电路并不是最优的。
HLS需要较高的掌握门槛,需要熟练掌握硬件描述语言和计算机体系结构,才能达到最佳效果。
3.HLS的使用场景还比较有限,在一些对性能、资源需求高的场景下,仍然需要手动编写硬件描述语言来实现最优电路设计。
3. 在win10(或者Ubuntu系统下)安装 Intel 或者 Xilinx 的支持HLS的FPGA编程开发软件(Quartus18或者Vivado18),设置好环境,完成一个入门级的HLS程序,并进行仿真或者实际开发板运行。
1:HLS工程建立
打开 Vivado HLS 开发工具, 单击 Creat New Project 创建一个新工程, 设置好工程路径和工程名, 一直点击 Next 按照默认设置
出现如下图所示界面,时钟周期 Clock Period 按照默认 10ns,Uncertaintly 和 Solution
Name 均按照默认设置, 点击红色圆圈部分选择芯片类型, 然后点击 OK。下图示是选择好后的界面。
工程建立完后的界面是这样的。下面就是导入工程里用到的源文件。
需要在工程添加3个源文件。都可以在文件开头介绍的下载地址下载。右键点击source , Add Files 分别添加shift_led.cpp 和 shift_led.h。 右键点击Test Bench , Add Files 添加Test_shift_led.cpp.
shift_led.h代码:
#ifndef _SHIFT_LED_H_
#define _SHIFT_LED_H_
//
#include "ap_int.h"
//#define MAX_CNT 10000/2 //仿真时可以用这个代替下面的行介绍仿真等待时间
#define MAX_CNT 100000000/2
#define SHIFT_FLAG MAX_CNT-2
//typedef int led_t;
typedef ap_fixed<4,4> led_t; // 1st: total width. 2nd: integer width
void shift_led(led_t *led_o,led_t led_i);
#endif
shift_led.cpp
#include "shift_led.h"
void shift_led(led_t *led_o,led_t led_i)
{
#pragma HLS INTERFACE ap_vld port=led_i
#pragma HLS INTERFACE ap_ovld port=led_o
led_t tmp_led=led_i;
int i; //for cycle variables
for(i = 0;i < MAX_CNT;i++)
{
if(i==SHIFT_FLAG)
{
//tmp_led = ((tmp_led>>7)&0x01) + ((tmp_led<<1)&0xFE);//left shift 8
tmp_led = ((tmp_led>>4)&0x01) + ((tmp_led<<1)&0xFE);//left shift 4
*led_o = tmp_led;
}
}
}
Test_shift.led.cpp
#include "shift_led.h"
#include <stdio.h>
using namespace std;
int main()
{
led_t led_o;
led_t led_i=0xfe;
const int SHIFT_TIME =8 ;
int i;
for(i=0;i<SHIFT_TIME;i++)
{
shift_led(&led_o,led_i);
led_i = led_o;
char string[25];
itoa((unsigned int)led_o & 0xf,string,2);
fprintf(stdout,"shift_out=%s\n",string);
}
}
2:工程综合
工程综合前,需要设置 Top Function。
点击 Project-> Project Settings
出现如下界面 ,在Syntheses 界面下选择综合的顶层函数名。
因为当前工程中只存在一个Solution, 我们选择Solution ->Run C Sytheses -> Active Solutions 进行综合,菜单旁有个快捷键的图标,所以也有快捷可以直接点取
3: 优化和添加约束
在原文中, led_t tmp_led=led_i; 最开始是int , 然后把他定义为4位整数。我这里一开始就是这样,也就没有什么优化了。
但这里做一下他的约束添加,或者也是优化的内容。
在主页面里,点击如下3出红箭,如果不是这个界面。选择文件 shift_led.cpp 文件, 选择 synthesis, 选择 directive。
3: 仿真实现
菜单Project -> Run C Simulation 或者点击快捷键(看菜单旁图示),就开始 C 仿真
仿真运行的情况是这样的:
波形仿真
5: HLS代码封装
通过前面的实验,我们进行了HLS的工程创建,仿真,但这只是把算法实现从C 到RTL的转换。下面我们开始把其打包成IP, 在硬件平台上进行测试,也方便Vivado 进行调用,应用。
菜单 Solution -> Export RTL 也可以点快捷(菜单图示)。
点击2次OK 之后,就开始IP 打包封装。
运行结束后,就在solution1 目录下多了一个impl 文件夹,并且在0等待一段时间后在 solution1 目录下多了一个 impl 文件夹, 并且在ip 文件夹中生成了一个压缩包,这就是我们需要的打包好的IP。
shift_led.v 的代码如下:
// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2018.3
// Copyright (C) 1986-2018 Xilinx, Inc. All Rights Reserved.
//
// ===========================================================
`timescale 1 ns / 1 ps
(* CORE_GENERATION_INFO="shift_led,hls_ip_2018_3,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=1,HLS_INPUT_PART=xc7z010clg400-2,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=1.988500,HLS_SYN_LAT=50000001,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=0,HLS_SYN_FF=32,HLS_SYN_LUT=57,HLS_VERSION=2018_3}" *)
module shift_led (
ap_clk,
ap_rst,
ap_start,
ap_done,
ap_idle,
ap_ready,
led_o_V,
led_o_V_ap_vld,
led_i_V
);
parameter ap_ST_fsm_state1 = 2'd1;
parameter ap_ST_fsm_state2 = 2'd2;
input ap_clk;
input ap_rst;
input ap_start;
output ap_done;
output ap_idle;
output ap_ready;
output [3:0] led_o_V;
output led_o_V_ap_vld;
input [3:0] led_i_V;
reg ap_done;
reg ap_idle;
reg ap_ready;
reg led_o_V_ap_vld;
(* fsm_encoding = "none" *) reg [1:0] ap_CS_fsm;
wire ap_CS_fsm_state1;
wire [25:0] i_1_fu_73_p2;
wire ap_CS_fsm_state2;
reg [25:0] i_reg_51;
wire [0:0] exitcond_fu_67_p2;
reg [3:0] tmp_led_V_1_fu_34;
wire [3:0] tmp_led_V_fu_100_p3;
wire [0:0] tmp_fu_79_p2;
wire [2:0] tmp_2_fu_96_p1;
wire [0:0] tmp_1_fu_88_p3;
reg [1:0] ap_NS_fsm;
// power-on initialization
initial begin
#0 ap_CS_fsm = 2'd1;
end
always @ (posedge ap_clk) begin
if (ap_rst == 1'b1) begin
ap_CS_fsm <= ap_ST_fsm_state1;
end else begin
ap_CS_fsm <= ap_NS_fsm;
end
end
always @ (posedge ap_clk) begin
if (((exitcond_fu_67_p2 == 1'd0) & (1'b1 == ap_CS_fsm_state2))) begin
i_reg_51 <= i_1_fu_73_p2;
end else if (((ap_start == 1'b1) & (1'b1 == ap_CS_fsm_state1))) begin
i_reg_51 <= 26'd0;
end
end
always @ (posedge ap_clk) begin
if (((tmp_fu_79_p2 == 1'd1) & (exitcond_fu_67_p2 == 1'd0) & (1'b1 == ap_CS_fsm_state2))) begin
tmp_led_V_1_fu_34 <= tmp_led_V_fu_100_p3;
end else if (((ap_start == 1'b1) & (1'b1 == ap_CS_fsm_state1))) begin
tmp_led_V_1_fu_34 <= led_i_V;
end
end
always @ (*) begin
if (((exitcond_fu_67_p2 == 1'd1) & (1'b1 == ap_CS_fsm_state2))) begin
ap_done = 1'b1;
end else begin
ap_done = 1'b0;
end
end
always @ (*) begin
if (((ap_start == 1'b0) & (1'b1 == ap_CS_fsm_state1))) begin
ap_idle = 1'b1;
end else begin
ap_idle = 1'b0;
end
end
always @ (*) begin
if (((exitcond_fu_67_p2 == 1'd1) & (1'b1 == ap_CS_fsm_state2))) begin
ap_ready = 1'b1;
end else begin
ap_ready = 1'b0;
end
end
always @ (*) begin
if (((tmp_fu_79_p2 == 1'd1) & (exitcond_fu_67_p2 == 1'd0) & (1'b1 == ap_CS_fsm_state2))) begin
led_o_V_ap_vld = 1'b1;
end else begin
led_o_V_ap_vld = 1'b0;
end
end
always @ (*) begin
case (ap_CS_fsm)
ap_ST_fsm_state1 : begin
if (((ap_start == 1'b1) & (1'b1 == ap_CS_fsm_state1))) begin
ap_NS_fsm = ap_ST_fsm_state2;
end else begin
ap_NS_fsm = ap_ST_fsm_state1;
end
end
ap_ST_fsm_state2 : begin
if (((exitcond_fu_67_p2 == 1'd1) & (1'b1 == ap_CS_fsm_state2))) begin
ap_NS_fsm = ap_ST_fsm_state1;
end else begin
ap_NS_fsm = ap_ST_fsm_state2;
end
end
default : begin
ap_NS_fsm = 'bx;
end
endcase
end
assign ap_CS_fsm_state1 = ap_CS_fsm[32'd0];
assign ap_CS_fsm_state2 = ap_CS_fsm[32'd1];
assign exitcond_fu_67_p2 = ((i_reg_51 == 26'd50000000) ? 1'b1 : 1'b0);
assign i_1_fu_73_p2 = (i_reg_51 + 26'd1);
assign led_o_V = {{tmp_2_fu_96_p1}, {tmp_1_fu_88_p3}};
assign tmp_1_fu_88_p3 = tmp_led_V_1_fu_34[32'd3];
assign tmp_2_fu_96_p1 = tmp_led_V_1_fu_34[2:0];
assign tmp_fu_79_p2 = ((i_reg_51 == 26'd49999998) ? 1'b1 : 1'b0);
assign tmp_led_V_fu_100_p3 = {{tmp_2_fu_96_p1}, {tmp_1_fu_88_p3}};
endmodule //shift_led