通过流水灯示例来说明HLS工程创建、综合、优化、仿真的流程,以及使用hls工具生成的IP核。

一、工作流程

1.创建工程

  (1)选择路径,添加source、test文件(暂不添加)
图片描述
  (2)选择芯片,这里选择xc78020c1g484-1xc78020c1g484-1(随便选的)
图片描述

2.添加source以及test文件

图片描述

3.添加顶层函数

图片描述

4.综合

图片描述

5.查看分析报告

图片描述

6.优化

  点击directive选择加入优化,可以看到几个优化选项,在官方文档:ug902-vivado-high-level-synthesis中可以查看相应的说明:
图片描述
  destination选择source file则会对当前目录所有solution都作同样优化;选directive file只对当前solution作优化:
图片描述
  可以看到程序中已经生成了一条优化的指令:ap_ovld意义同样可以在官方文档中找到,这里不放贴图了。

#pragma HLS INTERFACE ap_ovld port=led_o

7.再次综合

  可以在综合结果中查看资源的使用情况来看优化的效果:
图片描述

8.仿真

  执行c仿真:
图片描述
  仿真结果:
图片描述

9.modelsim协同仿真

  执行协同仿真:
图片描述
  耗时非常久。。。。。
  仿真结果,用modelsim打开,将信号add wave
图片描述

10.导出IP

图片描述
  这里如果报错,可能是因为官方的原因,需要把时间调到2021以前,或者官网有补丁:https://support.xilinx.com/s/article/76960?language=en_US
  导出IP位置
图片描述

11.在vivado中使用IP

图片描述

二、代码分析

  头文件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

//int 类型默认位宽32位,显然在板子上是不合适的,改用ap_int.h库中数据类型
//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

  在官方文档:ug902-vivado-high-level-synthesis中可以查看对数据类型ap_fixed的说明:
图片描述
  c文件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;
	cnt32_t i;//for循环的延时变量
	tmp_led = led_i;
	for(i = 0;i < MAX_CNT;i++)
	{
		if(i==SHIFT_FLAG)
		{
			//假设传入是0xe(1110)
			//右移3位:1110 => 0001
			//和0001相与:0001&0001 => 0001
			//左移1位:1110 => 1100
			//和1110相与:1100&1110 => 1100
			//两者相加: 0001+1100 => 1101
			tmp_led = ((tmp_led>>3)&0x1) + ((tmp_led<<1)&0xE);//左移
			*led_o = tmp_led;
		}
	}
}