Vivaodo HLS 编写第一个IP核并在 Vivado 中实例化(2017.4)


前言[1] :

Xilinx Vivado® 高层次综合(High Level Synthesis)工具将C语言转换为寄存器传输级(RTL)实现,并能够综合到Xilinx现场可编程逻辑门阵列(FPGA)中。可以使用C,C++,SystemC或开放计算语言(OpenCL™)API C内核编写C规范,并且FPGA提供了一个大规模并行体系结构,在性能,成本和功耗方面优于传统处理器。

其主要优势有 :

   1、提高硬件设计的开发效率。

   2、提高软件设计的系统性能。

   3、在C语言层面完成算法开发并验证。

   4、使用优化指令完成C语言到HDL的多个实现。

   5、创建可读性和可移植性强的C语言代码。

1、新建第一个project。

点击create new project后出现的对话框

按照图中配置后点击next,将出现 :

添加文件对话框

这里可以先添加文件,也可以选择直接next。如果选择next在Vivado HLS中编辑C源文件后要记得添加Top Function。这里演示先添加源文件的方法 :

添加C源文件

先点击Add File添加源文件(包含.cpp和.h),添加完成后,点击Top Function后的Browser按钮,即可弹出Select Top Function的对话框,这里我们的Top Function是hier_func.cpp,点击ok,然后点击next。

添加C-testbench

可以在这里添加C-testbench也可以直接点击next在之后再添加testbench,我在这里直接点击next。然后出现如下对话框 :

选择器件

在这里是提醒我们选择器件,点击part后面的...按钮,则会出现 :

器件型号选择

这里可以在左边的part里选择FPGA芯片具体型号,也可以在右边选择开发板型号,我选择的是ZYNQ-7 ZC702开发板,点击ok继续,点击finish。


2、我的C源码 :

1) : hier_func.h

   #ifndef _HIER_FUNC_H_
   #define _HIER_FUNC_H_
   
   #include <stdio.h>
   
   #define NUM_TRANS 40
   
   typedef int din_t;
   typedef int dint_t;
   typedef int dout_t;
   
   void hier_func(din_t A, din_t B, dout_t *C, dout_t *D);
   
   void sumsub_func(din_t *in1, din_t *in2, dint_t *outSum, dint_t *outSub);
   
   void shift_func(dint_t *in1, dint_t *in2, dout_t *outA, dout_t *outB);
   
   #endif

可以看出.h文件;里主要做了常量参数声明,自定义数据类型名,声明主要函数等工作。


2) : hier_func.cpp

   #include "hier_func.h"
   
   void sumsub_func(din_t *in1, din_t *in2, dint_t *outSum, dint_t *outSub)
   {
      *outSum = *in1 + *in2;
      *outSub = *in1 - *in2;
   }
   void shift_func(dint_t *in1, dint_t *in2, dout_t *outA, dout_t *outB)
   {
      *outA = *in1 >> 1;
      *outB = *in2 >> 2;
   }
   void hier_func(din_t A, din_t B, dout_t *C, dout_t *D)
   {
      dint_t apb, amb;
      sumsub_func(&A,&B,&apb,&amb);
      shift_func(&apb,&amb,C,D);
   }

可以看出,func sumsub_func主要输出两个输入的和与差、func shift_func主要输出in1右移一位的值以及in2右移2位的值。在hier_func中调用两个子函数,最后的输出结果满足计算式 :

C = (int)(A+B)/2

D = (int)(A-B)/4

3、规范型C-testbench编写 :

 #include "hier_func.h"
 int main() {
 // Data storage
    int a[NUM_TRANS], b[NUM_TRANS];  //输入
    int c_expected[NUM_TRANS], d_expected[NUM_TRANS];  //应该得到的输出结果
    int c[NUM_TRANS], d[NUM_TRANS];  //实际得到的输出结果
 
 //Function data (to/from function)
    int a_actual, b_actual;
    int c_actual, d_actual;
 
 // Misc
    int retval=0, i, i_trans, tmp;
    FILE *fp;
 
 // Load input data from files
 //载入输入数据A的输入样本文件

    fp = fopen("tb_data/inA.dat","r");
    for (i=0; i<NUM_TRANS; i++){
        fscanf(fp, "%d", &tmp);
        a[i] = tmp;
    }
    fclose(fp);

 //载入输入数据B的输入样本文件
    fp=fopen("tb_data/inB.dat","r");
    for (i=0; i<NUM_TRANS; i++){
        fscanf(fp, "%d", &tmp);
        b[i] = tmp;
    }
    fclose(fp);
 
 // Execute the function multiple times (multiple transactions)
 //依次从样本文件中取出数据进行运算
    for(i_trans=0; i_trans<NUM_TRANS-1; i_trans++){
    //Apply next data values
        a_actual = a[i_trans];
        b_actual = b[i_trans];
        hier_func(a_actual, b_actual, &c_actual, &d_actual);
 
    //Store outputs
    //存储输出结果
        c[i_trans] = c_actual;
        d[i_trans] = d_actual;
    }

    // Load expected output data from files
    //从标准输出结果文件中载入输出结果C
    fp=fopen("tb_data/outC.dat","r");
    for (i=0; i<NUM_TRANS; i++){
        fscanf(fp, "%d", &tmp);
        c_expected[i] = tmp;
    }
    fclose(fp);

    //从标准输出结果文件中载入输出结果D     
    fp=fopen("tb_data/outD.dat","r");
    for (i=0; i<NUM_TRANS; i++){
        fscanf(fp, "%d", &tmp);
        d_expected[i] = tmp;
    }
    fclose(fp);
 
    // Check outputs against expected
    //比较得到的输出结果和标准输出结果
    for (i = 0; i < NUM_TRANS-1; ++i) {
        if(c[i] != c_expected[i]){
            retval = 1;
        }
        if(d[i] != d_expected[i]){
            retval = 1;
        }
    }

    // Print Results
    if(retval == 0){
        printf(" *** *** *** *** \n");
        printf(" Results are good \n");
        printf(" *** *** *** *** \n");
    }
    else{
        printf(" *** *** *** *** \n");     
        printf(" Mismatch: retval=%d \n", retval);
        printf(" *** *** *** *** \n");
    }
 
    // Return 0 if outputs are corret
    return retval;
 }

从上述testbench中我们可以看出,在进行仿真是我们还需要加入4个文件,分别是inA.txt,inB.txt,outC.txt,outD.txt,其中inA和inB作为输入的测试数据,outC和outD作为inA和inB输入后应该得到的标准输出结果。输入数据用space或者enter隔开即可,这四个文件可以按照下图放置 :

test file 放置位置

4、HLS综合以及仿真 :

点击Run Synthesis(图中绿色三角形)

点击C综合按钮

之后在左侧选项卡中会出现impl和syn文件夹 :

synthesis得到的文件

在impl文件夹下或者syn文件夹下的verilog文件夹下会生成.v文件,在vhdl文件夹下会生成.vhd文件。这里以.v文件进行分析,生成的.v文件如下 :

// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2017.4
// Copyright (C) 1986-2017 Xilinx, Inc. All Rights Reserved.
// 
// ===========================================================

`timescale 1 ns / 1 ps 

(* CORE_GENERATION_INFO="hier_func,hls_ip_2017_4,            
{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,
HLS_INPUT_PART=xc7vx690tffg1761-    
2,HLS_INPUT_CLOCK=10.000000,
HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=1.514000,
HLS_SYN_LAT=0,HLS_SYN_TPT=none,HLS_SYN_MEM=0,
HLS_SYN_DSP=0,HLS_SYN_FF=0,HLS_SYN_LUT=78}" *)

module hier_func (
    ap_start,
    ap_done,
    ap_idle,
    ap_ready,
    A,
    B,
    C,
    C_ap_vld,
    D,
    D_ap_vld
);


    input   ap_start;
    output   ap_done;
    output   ap_idle;
    output   ap_ready;
    input  [31:0] A;
    input  [31:0] B;
    output  [31:0] C;
    output   C_ap_vld;
    output  [31:0] D;
    output   D_ap_vld;

   reg C_ap_vld;
   reg D_ap_vld;

   wire   [31:0] apb_fu_54_p2;
   wire   [30:0] tmp_1_i_fu_66_p4;
   wire   [31:0] amb_fu_60_p2;
   wire   [29:0] tmp_3_i_fu_81_p4;

   always @ (*) begin
       if ((ap_start == 1'b1)) begin
           C_ap_vld = 1'b1;
       end else begin
           C_ap_vld = 1'b0;
       end
   end

   always @ (*) begin
       if ((ap_start == 1'b1)) begin
           D_ap_vld = 1'b1;
       end else begin
           D_ap_vld = 1'b0;
       end
   end

   assign C = $signed(tmp_1_i_fu_66_p4);

   assign D = $signed(tmp_3_i_fu_81_p4);

   assign amb_fu_60_p2 = (A - B);

   assign ap_done = ap_start;

   assign ap_idle = 1'b1;

   assign ap_ready = ap_start;

   assign apb_fu_54_p2 = (B + A);

   assign tmp_1_i_fu_66_p4 = {{apb_fu_54_p2[31:1]}};

   assign tmp_3_i_fu_81_p4 = {{amb_fu_60_p2[31:2]}};

   endmodule //hier_func

可以看出,核心语句只有这四句话 :

   assign amb_fu_60_p2 = (A - B);

   assign apb_fu_54_p2 = (B + A);

   assign tmp_1_i_fu_66_p4 = {{apb_fu_54_p2[31:1]}};

   assign tmp_3_i_fu_81_p4 = {{amb_fu_60_p2[31:2]}};

点击Run C SImulation 按钮(绿色三角形左边的按钮)

Run C SImulation 按钮

出现下图对话框,直接选择ok,这里主要选择仿真选项和配置argument,没有特殊需要直接选择ok即可。

C SImulation configuration

仿真结束后,则会弹出 : hier_func_csim.log,其内容为 :

INFO: [SIM 2] *************** CSIM start ***************
INFO: [SIM 4] CSIM will launch GCC as the compiler.
   Compiling ../../../testbench.cpp in debug mode
   Compiling ../../../hier_func.cpp in debug mode
   Generating csim.exe
 *** *** *** *** 
 Results are good 
 *** *** *** *** 
INFO: [SIM 1] CSim done with 0 errors.
INFO: [SIM 3] *************** CSIM finish ***************

可以看出CSim done with 0 errors,仿真通过。


5、导出IP至Vivado :

点击下图中的Export 按钮,

Export 按钮

则会弹出下图对话框 :

Export RTL 对话框

按照需求配置后点击ok,Export完成后,则会弹出 :

Export Report

这个时候我们发现在solution/impl/ip目录下生成了一个.zip文件 :

zip 文件

这个zip就是之后导入时需要用到的文件,现在我们打开Vivado 2017.4,新建一个Project,在选择器件型号时记得选择与HLS中相同的器件型号。

New Project Summary

点击Finish,完成新建工程之后,点击界面左侧的Settings :

在弹出的页面下添加IP repositories。(添加路径为在HLS工程中的/solution1/impl/ip)

添加ip

之后在Block Design中就可以添加IP了 :


参考资料 :

1、Vivado Design Suite User Guide - High-Level Synthesis

2、Vivado Design Suite Tutorial - High-Level Synthesis

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容