当我们安装好Vivado 的时候,也同时装好了Vivado HLS.。 这是个什么东西?我就有一种想一探究的感觉。网上一查,Vivado High-Level Synthesis。学习了一段时间的Zynq 7000, 找了一个HLS的教程,就开始了如下入门实验,体验高级语言综合设计IP。Vivado HLS是Xilinx 推出的高层次综合工具,采用C/C++语言进行FPGA设计。HLS提供了一些样例方便大家熟悉其开发流程。另外关于HLS的使用介绍,Xilinx官方提供了2个重要开发文档ug871 和 ug902。里面详细介绍了包括怎么建立HLS 工程,怎么编写Testbench,怎么进行优化等问题。在HLS软件界面,在右侧有个directive, 里面列出了程序中所有用到的变量,函数和循环结构,点右键可以给其配置。

 对循环结构, 一般选择 unroll( 即展开循环) , 可以自己设定展开因子 factor。 为提高程序的并行化处理, 可以给函数选择 PIPELINE。 对应数组, 可以设置为 ARRAY_PARTITION,数组维数可以自己设定。 HLS 软件其实很智能的, 简单的结构, 一般软件自己会优化好。 每一个优化方案都保存在一个 Solution 里, HLS 可以创建多个 Solution, 用于比较不用的优化效果。

如同软件开发都是从“ Hello Wrold! ” 进入编程的大门一样, 这一个实验我们就通过 HLS 封装一个移位流水灯的程序, 包括工程的创建, 仿真, 综合, 封装, 以及在硬件平台上的实现,来熟悉HLS的开发流程。

本文参考了米联的zynq 修炼秘籍 网手版。

实验代码和工程的下载:

链接:http://pan.baidu.com/s/1c1BXkvm 密码:h2i2

 

1:HLS工程建立

打开 Vivado HLS 开发工具, 单击 Creat New Project 创建一个新工程, 设置好工程路
径和工程名, 一直点击 Next 按照默认设置,

Vivado HLS 入门实验

 

出现如下图所示界面,时钟周期 Clock Period 按照默认 10ns,Uncertaintly 和 Solution
Name 均按照默认设置, 点击红色圆圈部分选择芯片类型, 然后点击 OK。下图示是选择好后的界面。

Vivado HLS 入门实验

 

下面是选择芯片型号的界面。根据你自己的硬件选择,我的是如图

Vivado HLS 入门实验

 

工程建立完后的界面是这样的。下面就是导入工程里用到的源文件。

Vivado HLS 入门实验

 

需要在工程添加3个源文件。都可以在文件开头介绍的下载地址下载。右键点击source , Add Files 分别添加shift_led.cpp 和 shift_led.h。 右键点击Test Bench , Add Files 添加Test_shift_led.cpp.

添加完成后效果如下:

Vivado HLS 入门实验

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)
{
    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 ,也可以点击红箭所指那样的快捷键。

Vivado HLS 入门实验

出现如下界面 ,在Syntheses 界面下选择综合的顶层函数名。

Vivado HLS 入门实验

 

因为当前工程中只存在一个Solution, 我们选择Solution ->Run C Sytheses -> Active Solutions 进行综合,菜单旁有个快捷键的图标,所以也有快捷可以直接点取:

Vivado HLS 入门实验

在未经优化的情况下综合报告如图所示, 出现这个界面需要把上下条拉到合适位置, 并收起Latency (Clock cycles)。

Vivado HLS 入门实验

 

3: 优化和添加约束

在原文中, led_t tmp_led=led_i; 最开始是int , 然后把他定义为4位整数。我这里一开始就是这样,也就没有什么优化了。

但这里做一下他的约束添加,或者也是优化的内容。

在主页面里,点击如下3出红箭,如果不是这个界面。选择文件 shift_led.cpp 文件, 选择 synthesis, 选择 directive。

Vivado HLS 入门实验

 

这里把led_o 设置为输出,右键点击led_o 出现Insert Drrective.. ,选择后如下界面:

选择 INTERFACE  mode 选择 ap_ovld。

Vivado HLS 入门实验

 

同样对led_i 进行基本相同的工作,mode 选择 ap_vld。

Vivado HLS 入门实验

 

进行如上操作后,看看源程序出现的变化。还有Directive 的变化。

Vivado HLS 入门实验

优化和约束就说这么多。

 

3: 仿真实现

菜单Project -> Run C Simulation 或者点击快捷键(看菜单旁图示),就开始 C 仿真:

Vivado HLS 入门实验

 

仿真运行的情况是这样的:

Vivado HLS 入门实验

 

4:波形仿真(如果不熟悉ModelSim 就跳过这一节):

在这之前需要运行Vivado 的编译仿真库,我是开始这个试验前就做了这个设置。


打开Vivado 后,菜单 Tools -> Compile Simulation Libraries...

Vivado HLS 入门实验

 

出现对话框后,选择Simulator 为 ModelSim, 选择编译库的位置,看红箭。

Vivado HLS 入门实验

做好设置后, 点击Compile 就开始生成仿真库。

 

如果做好了上面的仿真库编译准备,就可以开始看波形仿真了。

菜单Solution -> Run C/RTL Cosimulation 运行C协同仿真。做了如图所示选择。

Vivado HLS 入门实验

运行C 协同仿真一段时间后,就可以防线在solution 1目录下多了一个sim 文件夹,在其verilog 文件夹下看到生成的波形文件shift_led.wlf 文件。

Vivado HLS 入门实验

利用ModelSim 打开该文件。在Objects 下选择需要显示的波形信号, Add  wave 到波形显示里。

Vivado HLS 入门实验

 

波形显示就是这样的。

Vivado HLS 入门实验Vivado HLS 入门实验

这就是波形仿真。

 

5: HLS代码封装

通过前面的实验,我们进行了HLS的工程创建,仿真,但这只是把算法实现从C 到RTL的转换。下面我们开始把其打包成IP, 在硬件平台上进行测试,也方便Vivado 进行调用,应用。

菜单 Solution -> Export RTL 也可以点快捷(菜单图示)。

Vivado HLS 入门实验

 

在弹出的对话框中,点击Configuration 对一些参数进行输入,修改,然后点击OK。

Vivado HLS 入门实验

Configuration 的对话框设置。

Vivado HLS 入门实验

 

点击2次OK 之后,就开始IP 打包封装。

运行结束后,就在solution1 目录下多了一个impl 文件夹,并且在0等待一段时间后在 solution1 目录下多了一个 impl 文件夹, 并且在ip 文件夹中生成了一个压缩包,这就是我们需要的打包好的IP。

Vivado HLS 入门实验

 

6 测试和应用:

打开Vivado, 新建一个工程,工程名为test_shift_led。

在Project Manager 中点击 Project Settings。

Vivado HLS 入门实验

 

在这解压刚才建立的IP 压缩包到一个新建的文件夹里,这是在文件管理器里完成的。

Vivado HLS 入门实验

选择IP 设置区的 Repository Manager 页面,然后点击+号, 下面图示是添加后的结果。

 

进行了以上设置后,开始添加我们的IP包。

点击Project Manager 下的IP Catalog 。 在右边的IP Catalog 里点开User Repository,然后选择我们建立的IP, 显示的是shifted_led_4bits。这和我们添加其他的ip 是一样的。

Vivado HLS 入门实验

 

可以设置下IP, 名字为shift_led_0

Vivado HLS 入门实验

 

在这个对话框里选择Generate

Vivado HLS 入门实验

 

现在右键 Design Sources ,添加shift_led.v 文件,可以在下载链接出获取。右键Constraints,添加led
的约束文件。特别注意这个约束文件必须和你硬件的led 引脚定义一致。

看看下图,ip取名和程序中必须一致,就是左边和右边。

Vivado HLS 入门实验

 

shift_led.v 的代码如下(如果不想下载,也可以复制):


`timescale 1ns / 1ps
module shift_led
  #(
    parameter  DATA_WIDTH  = 4
    )
   (
    input                        i_clk,
    input                        i_rst_n,
    output  reg [DATA_WIDTH-1:0] led
    );

reg             [1:0]  cnt      ;
reg  [DATA_WIDTH-1:0]  led_i_V  ;
wire                   ap_start ;
wire                   led_i_vld;
wire [DATA_WIDTH-1:0]  led_o_V  ;

[email protected](posedge i_clk or negedge i_rst_n)begin
    if(i_rst_n == 1'b0)
        cnt <= 2'd0;
    else if(cnt[1]==1'b0)
        cnt <= cnt + 1'b1;
end
        
[email protected](posedge i_clk or negedge i_rst_n)begin
    if(i_rst_n == 1'b0)
        led_i_V <= 2'd0;
    else if(cnt[0]==1'b1)
        led_i_V <= 8'h1;//
    else if(led_o_vld == 1'b1)
        led_i_V <= led_o_V;
end

[email protected](posedge i_clk or negedge i_rst_n)begin
    if(i_rst_n == 1'b0)
        led <= 1'b0;
    else if(led_o_vld == 1'b1)
        led <= led_o_V;
end
        
assign ap_start  = cnt[1];
assign led_i_vld = cnt[1];

shift_led_0 u_shift_led_0(
                          .led_o_V_ap_vld  (led_o_vld),// output wire led_o_vld
                          .led_i_V_ap_vld  (led_i_vld),// input wire led_i_vld  
                          .ap_clk          (i_clk    ),// input wire ap_clk          
                          .ap_rst          (~i_rst_n ),// input wire ap_rst          
                          .ap_start        (ap_start ),// input wire ap_start        
                          .ap_done         (         ),// output wire ap_done        
                          .ap_idle         (         ),// output wire ap_idle        
                          .ap_ready        (         ),// output wire ap_ready       
                          .led_i_V         (led_i_V  ),// output wire [7 : 0] led_o_V
                          .led_o_V         (led_o_V  ) // input wire [7 : 0] led_i_V
                          );

endmodule

 

zynq.xdc 文件内容如下:

set_property IOSTANDARD LVCMOS33 [get_ports i_clk]
set_property IOSTANDARD LVCMOS33 [get_ports i_rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports {led[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}]
set_property PACKAGE_PIN M14 [get_ports {led[0]}]
set_property PACKAGE_PIN M15 [get_ports {led[1]}]
set_property PACKAGE_PIN K16 [get_ports {led[2]}]
set_property PACKAGE_PIN R19 [get_ports {led[3]}]
set_property PACKAGE_PIN U18 [get_ports i_clk]
set_property PACKAGE_PIN R18 [get_ports i_rst_n]

 

下面就和你硬件板提供的 FPGA led 实验程序一样了。综合,执行,生成流文件,下载运行。

你的led 应该流水运行了。

相关文章: