vivado HLS c++/C

1. c++基本知识

  1. 宏定义
    typedef int led_t;
    typedef int cnt32_t;//计数器

  2. using namespace std;
    itoa (int, char*, int);//函数

    # include <stdio.h>
    # include <stdlib.h>
    
    void main (void)
    {
    int num = 100;
    char str[25];
    itoa(num, str, 10);
    printf("The number 'num' is %d and the string 'str' is %s. \n" ,
    num, str);
    }
    

    第一个参数是要转换的数字,第二个参数是要写入转换结果的目标字符串,第三个参数是转移数字时 所用的基数。在上例中,转换基数为10。10:十进制;2:二进制…

  3. 指针

    1. 数据在内存中存储时是分块存储的。变量都是存储东西的

    2. 指针变量是存储了一个指针,int *p;同变量定义相同,定义了一个p变量,但他属于指针型,但他存储的是地址。

    3. 变量的指针和指针变量:前者是指变量的存储地址,指针理解为地址;后者是是一个变量,这个变量存储的是一个地址。

    4. 指针变量的定义

      int *p;
      

      使用
      p = &a;//p是一个指针变量,指针变量是存储地址的一块空间,这块空间是存储变量a的地址

    5. “&”和“*”的结合方向
      都是右结合方向。假设有变量x=1,则

  4. 指针数组和数组指针
    指针数组:”指针的数组”,首先这个变量是一个数组。一个数组,每个元素都是单独的指针【地址】

    int *arr[4] = {1,2,3,4};
    //arr是指针数组,它有四个元素,每个元素是一个int *类型的指针,这些指针存放着其对应字符串的首地址。
    

    数组指针:一个指针,其指向一个数组的地址。

     int (*p)[6];
     //一个数组指针,总共六个
    
  5. const 作用和简答用法
    作用:
    1. 对变量声明只读特性,保护变量值以防被修改。
    2. 节省空间,避免不必要的内存分配。
    用法:

    int a=2;//普通定义
    const int a = 2;//在后续程序中无法修改
    //在普通变量中加上const即可
    
  6. static作用:只在本文件中使用变量。

  7. extern作用:可以在文件之外使用。

  8. 结构体的定义和使用:
    定义
    1. 第一种

    	struct stu{
    	int a;
    	int b;
    	int c;
    }
    //声明结构体变量
    struct stu aa,bb;
    //变量赋初值
    aa.a=1;
    aa.b=2;
    aa.c=3;
    
    1. 第二种 将struct stu替换,需要使用关键词typedef
    typedef struct stu{
    	int a;
    	int b;
    	int c;
    }STU;
    STU aa,bb;
    //赋初值 同上面一样。
    //
    //这种方式需要注意
    STU aa={
    	.a = 1,
    	.b = 2,
    	.c = 3
    	};
    

    定义成这种就能实现关键词替换成自己的类型名“STU”。
    结构体数组,数组的数据类型就是定义的结构体。
    比如:

    STU AA[3]={
    {1,2,3},//赋值时小的数据类型要对应
    {2,3,4},
    {3,4,5}
    };
    

    结构体指针

    1. struct 结构体名 *指针;

    2. 结构体访问变量的方法

      //定义结构体
      struct student{
      char name;
      int num;
      int score;
      }*p;
      //这里定义了一个结构体指针
      //访问方法
      //第一种
      p->name=
      p->num
      //第二种
      (*p).name
      (*p).num
      (*p).score
      
//VGA显示接口的参数定义方法。封装方式值得学习
typedef struct {
	char label[64]; /* Label describing the resolution */
	u32 width; /*Width of the active video frame*/
	u32 height; /*Height of the active video frame*/
	u32 hps; /*Start time of Horizontal sync pulse, in pixel clocks (active width + H. front porch)*/
	u32 hpe; /*End time of Horizontal sync pulse, in pixel clocks (active width + H. front porch + H. sync width)*/
	u32 hmax; /*Total number of pixel clocks per line (active width + H. front porch + H. sync width + H. back porch) */
	u32 hpol; /*hsync pulse polarity*/
	u32 vps; /*Start time of Vertical sync pulse, in lines (active height + V. front porch)*/
	u32 vpe; /*End time of Vertical sync pulse, in lines (active height + V. front porch + V. sync width)*/
	u32 vmax; /*Total number of lines per frame (active height + V. front porch + V. sync width + V. back porch) */
	u32 vpol; /*vsync pulse polarity*/
	double freq; /*Pixel Clock frequency*/
} VideoMode;
//这里运用了static const 结构体的声明
static const VideoMode VMODE_640x480 = {
	.label = "640x480@60Hz",
	.width = 640,
	.height = 480,
	.hps = 656,
	.hpe = 752,
	.hmax = 799,
	.hpol = 0,
	.vps = 490,
	.vpe = 492,
	.vmax = 524,
	.vpol = 0,
	.freq = 25.0
};
  1. attribute ((aligned(4)))用法
    1. 字节对齐n 表示几字节。该声明将强制编译器确保(尽它所能)变量分配空间时采用n字节对齐方式。

      struct S {
      
      short b[3];
      
      } __attribute__ ((aligned (8)));
      
      typedef int int32_t __attribute__ ((aligned (8)));
      int main()
      {
       int __attribute__((aligned(8))) a = 1;
       int __attribute__((aligned(4))) b = 2;
      
       printf("%d %d\n",a,b);
      
        return 0;
      }
      

2.1 HLS 设计流水灯实验【包括包括工程的创建,仿真,综合,封装,以及在硬件平台上的实现】

在这里插入图片描述
HLS就是用c或者c++完成verilog代码的转换。流程框图是这样的
在这里插入图片描述
在这里插入图片描述

  1. 打开 Vivado HLS 开发工具,单击 Creat New Project 创建一个新工程,设置好工程路径和工程名,一直点击Next
    在这里插入图片描述

  2. 选择芯片型号,zynq7010,点击next
    在这里插入图片描述
    在这里插入图片描述

  3. 右单击 Source,选择 New file,添加一个设计源文件。
    在这里插入图片描述

  4. 功能文件shift_led.cpp 一定要带上后缀

    #include "shift_led.h"
    
    void shift_led(led_t *led_o,led_t led_i)
    {
    		led_t tmp_led;
    	cnt32_t i;//for循环的延时变量
    	tmp_led = led_i;
    	for(i = 0;i < MAX_CNT;i++)
    	{
    		if(i==SHIFT_FLAG)
    		{
    			tmp_led = ((tmp_led>>3)&0x1) + ((tmp_led<<1)&0xE);//左移
    			*led_o = tmp_led;
    		}
    	}
    }
    
    
  5. 添加一个 shift_led.h 文件

    #ifndef _SHIFT_LED_H_
    #define _SHIFT_LED_H_
    
    //加入设置int自定义位宽的头文件
    #include "ap_int.h"
    //设置灯半秒动一次,开发板时钟频率是100M
    //#define MAX_CNT 1000/2 //仅用于仿真,不然时间较长
    
    #define MAX_CNT 100000000/2
    #define SHIFT_FLAG MAX_CNT-2
    typedef int led_t;
    typedef int cnt32_t;//计数器
    
    //typedef ap_fixed<4,4> led_t; //第一个4代表总位宽,第二个4代表整数部分的位宽是4,则小数部分位宽=4-4=0
    //typedef ap_fixed<32,32> cnt32_t;
    
    void shift_led(led_t *led_o,led_t led_i);
    #endif
    
    
  6. 单击 Test Bench,添加一个名为 Test_shift_led.cpp 的测试文件,并添加如下程序

    #include "shift_led.h"
    #include <stdio.h>
    using namespace std;
    int main()
    {
    led_t led_o;
    led_t led_i = 0xE;// 1110
    const int SHIFT_TIME = 4;
    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);;//&oxF是为了取led_o的4位,转化为二进制数出
    	if(i == 2)
    		fprintf(stdout,"shift_out= 0%s\n",string);//数据对齐,高位补零
    	else
    		fprintf(stdout,"shift_out= %s\n",string);
    }
    }
    

2.2代码综合

  1. :点击 Project -> Project Settings在 Synthesis 界面下选择综合的顶层函数名
    在这里插入图片描述
    在这里插入图片描述
  2. 因为当前工程中只存在一个 Solution(解决方案),我们选择 Solution –> Run C Synthesis–>Active Solutions 或者直接点击 进行综合,等待一段时间,在未经优化的情况下综合报告如图所示,我们可以看到 FF 和 LUT 使用情况
    在这里插入图片描述
    在这里插入图片描述
  3. 单击方框选中的地方点击选择打开分析报告
    在这里插入图片描述
  4. 在下图所示 1 的地方点击出现 2 所示的 shift_led,点击展开后可以看到 LED 输入和输出位宽均为 32 位,板载是 4 个 LED,那么该怎么去进行优化得到我们想要的结果呢?
    在这里插入图片描述

2.3代码优化

  1. 点击 Synthesis 切换到工作空间主界面
    在这里插入图片描述
    在这里插入图片描述
    另外再进行端口约束。约束方法如下,双击打开 shift_led.cpp,在需综合的 shift_led.cpp 文件中的 Directive目录下的 led_o 上右键选择 Insert Directive。在这里插入图片描述
    因为 led_o 是接口,所以 Directive 选择为 INTERFACE,Destination 选择为 Source File,那么有的会问了,这两个有什么区别吗?区别就是 Source File 是针对所有的 Solution 采用同一个优化手段,而 Directive File 是对当前的 Solution 有效,mode(optional)我们选为 ap_ovld,即输出使能。
    在这里插入图片描述
    在这里插入图片描述
    完成后重新综合,查看资源明显减少。

2.4程序仿真

仿真分为 C 代码仿真和 C/RTL 联合仿真。其中 C/RTL 联合仿真可以使用 Vivado 自带的仿真软件仿真,也可以使用第三方仿真软件 Modelsim 进行联合仿真。

C语言仿真

  1. 单击 Project 下的 Run C Simulation 或直接单击 开始 C 仿真
    在这里插入图片描述

  2. 勾选 Optimized Compile,加载编译仿真窗口
    在这里插入图片描述

  3. 等待一段时间,仿真结果如下,我们可以看到数据循环左移了一位,达到了我们想要的实验效果
    在这里插入图片描述

  4. 加载调试窗口,出现调试界面,可以添加断点观察调试信号数据
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    C/RTL 联合仿真
    vivado自带仿真工具

    1. 单击 Solution 下的 Run C/RTL cosimulation 运行协同仿真
      在这里插入图片描述

    2. 设置如下,点击 OK,开始仿真。Dump Trace 选择 all,可以查看到 RTL 仿真波形
      在这里插入图片描述

    3. 点击图标,打开波形窗口,添加观察信号
      在这里插入图片描述
      这个过程非常花时间需要耐心等待在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    这可是非常卡卡卡卡!
    在这里插入图片描述

  5. 波形文件位置
    在这里插入图片描述

使用 Modelsim 联合仿真

  1. 单击 Solution 下的 Run C/RTL cosimulation 运行协同仿真

  2. 运行协同仿真一段时间后,我们可以发现在 solution1 目录下多了一个 sim 文件夹,在其 verilog 文件夹下可以看到生成的波形文件 shift_led.wlf
    在这里插入图片描述

  3. 通过 modelsim 打开该文件,看关键接口的时序。首先打开 modelsim,然后单击 File 菜单下的 open命令
    在这里插入图片描述

  4. 在 objects 设置区,按住 ctrl 键选中要查看波形的信号, Add wave
    在这里插入图片描述

2.5HLS封装

HLS 只是把你的算法实现从 C 到 RTL的转化,而不能在硬件平台上进行测试,需要把 HLS 工程打包成一个 IP 以便于 Vivado 进行调用。

  1. 单击 Solution 菜单下的 Export RTL 或直接单击 导出 RTL 级

    在这里插入图片描述

  2. 点击 configuration 对一些参数进行补充
    在这里插入图片描述
    如果出现这种报错,把电脑时钟设置成2019年以前就能通过编译
    在这里插入图片描述

  3. 等待一段时间后在 solution1 目录下多了一个 impl 文件夹,并且在 ip 文件夹生成了一个压缩包,这就是打包好的 IP,在 Vivado 中进行使用
    在这里插入图片描述

2.6硬件平台

  1. 按照zynq新建工程

  2. 完成后,压缩包解压然后,选择 IP->Repository,进入添加 IP 设置区、
    在这里插入图片描述
    设置IP名字,在顶层中例化IP
    在这里插入图片描述

  3. 创建一个名为 shift_led 的 Verilog 文件

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 <= 4'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 [3 : 0] led_o_V
		  .led_o_V (led_o_V ) // input wire [3 : 0] led_i_V 
  );
 endmodule
 
 
  1. 引脚约束,下载调试
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值