HLS学习入门(流水灯)
通过流水灯示例来说明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;
}
}
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 不听话的兔子君!