学习HLS最好的参考资料还是xilinx官方的ug871和ug902,但xilinx的教程实在太长了,我也只是挑着看,等空下来了一定要细品
一、HLS简介
Vivado HLS是Xilinx公司发布的面向新一代FPGA推出的高级综合工具,在HLS工具中,用户不用受传统HDL语言的限制,能够选择不同的高级语言(C、C++、system C)进行FPGA设计,经仿真、优化和综合等步骤后即可生成RTL(Register Transfer Level)级代码,大幅降低了产品的研发周期。HLS更注重系统级建模,是一种全新的设计方法,能够将设计效率大幅提高。
二、HLS加速opencv
HLS的C语言函数库提供了丰富的函数接口与数据结构,其中HLS Video Functions Library堪称FPGA的opencv,在ug902的第四章有这些接口函数的详细介绍。
在Zynq系列APSoC上使用opencv主要有以下四种方式:
这里我主要采用的是第四种。不依赖于Arm进行一些重复运算,而是把算法中诸如滤波之类的需要大量计算的部分用硬件来实现,充分利用FPGA的并行特性。
zynq系列是ARM与FPGA集成的SoC,ARM与FPGA之间共享DDR,二者之间的通信与数据交换基于AXI4流协议,基于该协议可以实现视频处理模块之间的像素级通信。在使用HLS开发opencv应用的过程中,需要将输入定义为Video Stream接口,视频函数库采用hls::Mat数据类型, 因此还需要AXI4 video stream 到 VivadoHLS 中 hls::Mat类型的转换。
// 输入数据类型
typedef hls::stream<ap_axiu > AXI_STREAM;
//注:后面两个尖括号之间要加空格
// Convert AXI4 Stream data to hls::mat format
hls::AXIvideo2Mat(INPUT_STREAM, img_0);
将video stream转换为hls mat数据类型后,就可以利用hls中的opencv函数愉快的进行一些基础的图像处理了,诸如sobel边缘检测、图像缩放、腐蚀、膨胀等等。
//参见ug902 p307
#include "hls_video.h"
typedef hls::stream > AXI_STREAM;
typedef hls::Scalar RGB_PIXEL;
typedef hls::Mat RGB_IMAGE;
void image_filter(AXI_STREAM& INPUT_STREAM, AXI_STREAM&OUTPUT_STREAM, int rows, int cols) {
//Create AXI streaming interfaces for the core
RGB_IMAGE img_0(rows, cols);
RGB_IMAGE img_1(rows, cols);
RGB_IMAGE img_2(rows, cols);
RGB_IMAGE img_3(rows, cols);
RGB_IMAGE img_4(rows, cols);
RGB_IMAGE img_5(rows, cols);
RGB_PIXEL pix(50, 50, 50);
// Convert AXI4 Stream data to hls::mat format
hls::AXIvideo2Mat(INPUT_STREAM, img_0);
// Execute the video pipelines
hls::Sobel(img_0, img_1);
hls::SubS(img_1, pix, img_2);
hls::Scale(img_2, img_3, 2, 0);
hls::Erode(img_3, img_4);
hls::Dilate(img_4, img_5);
// Convert the hls::mat format to AXI4 Stream format
hls::Mat2AXIvideo(img_5, OUTPUT_STREAM);
}
其他常用的opencv函数如下:
三、优化指令
#pragma 指令主要负责输入输出接口定义以及控制接口定义。
// An highlighted block
#pragma HLS INTERFACE axis port=INPUT_STREAM
#pragma HLS INTERFACE axis port=OUTPUT_STREAM
#pragma HLS RESOURCE variable=rows core=AXI_SLAVE metadata="-bus_bundle CONTROL_BUS"
#pragma HLS RESOURCE variable=cols core=AXI_SLAVE metadata="-bus_bundle CONTROL_BUS"
#pragma HLS RESOURCE variable=return core=AXI_SLAVE metadata="-bus_bundle CONTROL_BUS"
#pragma HLS INTERFACE ap_stable port=rows
#pragma HLS INTERFACE ap_stable port=cols
#pragma HLS DATAFLOW
将输入输出接口定义为axis接口,将控制接口定义为AXI_SLAVE接口,并指定rows和cols可通过AXI_SLAVE接口访问,以及启动DATAFLOW数据流优化,使得任务之间以流水方式进行。
编写test bench,执行C仿真后,进行C synthesis,export IP导出IP
最后封装好的IP核: