• HLS:跑马灯实验


    跑马灯实验的第一部分记录:

    1. vivado 2018.2的HLS在跑C/RTL co-simulation的时候,一直报错,不论是用modelsim 还是vivado自带的similator。使用vivado 2015.4的HLS没有问题。

    2. modelsim 我用的是10.1c版本,vivado 2018.2对modelsim支持至少是10.5以上。

    3. 在vivado hls跑co-simulation未结束的情况下,打开modelsim会报错。等协同仿真跑完,再用modelsim打开波形文件。

    4. Vivado 2015.4的HLS做的IP核,在VIvado 2018.2中是可以使用的。

    打开Vivado HLS,新建一个工程。

      工程位置和名称自定义,一直点下一步,中间添加到文件暂时不用添加,直到出现下面一步。在part selection中选好芯片型号,时钟周期 Clock Period 按照默认 10ns,Uncertaintly 和 Solution Name 均按照默认设置,然后点击 finish。 

      一个建立好的工程如下图所示。

       在工程左侧添加如下空文件。

     代码:

    main.c

    #include "shift_led.h"
    #include <stdio.h>
    
    using namespace std;
    
    int main()
    {
        led_t led_o;
        led_t led_i = 0xFE;//1111_1110
        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&0xFF,string,2);//&oxFF是为了取led_o的8位,转化为二进制数出
            if(i == 6)
                fprintf(stdout,"shift_out= 0%s
    ",string);//数据对齐,高位补零
            else
                fprintf(stdout,"shift_out= %s
    ",string);
        }
    }
    #ifndef _SHIFT_LED_H_
    #define _SHIFT_LED_H_
    
    #include "ap_int.h"
    
    #define MAX_CNT 100000000/2
    #define SHIFT_FLAG  MAX_CNT-2
    
    typedef ap_fixed<4,4> led_t; 
    typedef ap_fixed<32,32> cnt32_t;
    
    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_ovld port=led_o
        #pragma HLS INTERFACE ap_ovld port=led_o
        #pragma HLS INTERFACE ap_vld port=led_i
    
        led_t tmp_led;
        cnt32_t i;
        tmp_led = led_i;
        for(i = 0;i < MAX_CNT;i++)
        {
            if(i==SHIFT_FLAG)
            {
                tmp_led = ((tmp_led>>7)&0x01) + ((tmp_led<<1)&0xFE);
                *led_o = tmp_led;
            }
        }
    }

     代码综合步骤:

    步骤一:点击 Project -> Project Settings, 在 Synthesis 界面下选择综合的顶层函数名。 单击 Browse 指定工程的顶层文件, 最后单击 OK 完成修改。

    步骤二:因为当前工程中只存在一个 Solution(解决方案) , 我们右键选择 Solution –> Run C Synthesis–>Active Solutions 或者直接点击 绿色三角进行综合, 等待一段时间, 在经过优化的情况下综合报告如图所示(未经优化就是没有加任何#pragma的), 我们可以看到 FF 和 LUT 分别使用了 37 和 140。 

    步骤三:单击solution->Open Analysis Perspective打开分析报告

      在 shift_led.h 文件中我们包含一个设置 int 自定义位宽的头文件"ap_int.h", 我们使用ap_fixed()函数自定义 int 型的 bit 数, 其函数原型为:
    ap_int_sim.h中class ap_fixed: public ap_fixed_base<_AP_W, _AP_I, true, _AP_Q, _AP_O, _AP_N> 。

      ap_fixed<M,N>,第一个 M 代表数据总位宽, N 代表数据整数部分的位宽, 那么小数部分的位宽即 M – N; 头文件中的第6和7行代码体现了ap_fixed的用法!
    步骤四:优化端口

      现在把所有的#pragma都删除掉,可以看到右侧的Derective是没有指令的,只显示了一些端口信息。

    右键led_o,插入directive。

      因为 led_o 是接口, 所以 Directive 我们选择为 INTERFACE,Destination 选择为 Source File。Source File 是针对所有的 Solution 采用同一个优化手段, 而 Directive File 是对当前的 Solution 有效, mode(optional)我们选为 ap_ovld,即输出使能。 对 led_i 进行同样的约束, 并选择输入使能,ap_vld。 我们再次综合,就可得到前面步骤二的经过优化后的报告了。
    仿真实现步骤:

    步骤一:单击 Project 下的 Run C Simulation  

    步骤二:单击 Solution 下的 Run C/RTL cosimulation 运行协同仿真。

    步骤三:使用Modelsim打开sim->verilog->wave.wlf文件,添加interface信号。

    打包HLS代码成IP核步骤:

    步骤一:单击 Solution 菜单下的 Export RTL 或直接单击 那个“田”的按钮导出 RTL 级。

      这个压缩包就是我们在后面Vivado中建立工程要用的。

      建立Vivado工程,添加顶层文件和约束文件。

    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  ;
    
    always@(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
            
    always@(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 <= 4'h1;
        else if(led_o_vld == 1'b1)
            led_i_V <= led_o_V;
    end
    
    always@(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

    开发板现象:

  • 相关阅读:
    Eureka获取服务列表源码解析
    Eureka客户端续约及服务端过期租约清理源码解析
    Eureka应用注册与集群数据同步源码解析
    Eureka重要对象简介
    EurekaClient自动装配及启动流程解析
    idea2019注册码
    EurekaServer自动装配及启动流程解析
    程序员的算法课(5)-动态规划算法
    程序员的算法课(4)-二分查找
    程序员的算法课(3)-递归(recursion)算法
  • 原文地址:https://www.cnblogs.com/yiwenbo/p/10744198.html
Copyright © 2020-2023  润新知