本文档系列是我在实践将神经网络实现到Xilinx 的zynq的FPGA上遇到的问题和解决方法。
目标:本文档重点探讨vivado HLS软件的使用,描述如何将相应的c程序用HLS转换为硬件可以实现的IPcore。
完成本过程可以参阅的文档有:
UG902:Vivado Design Suite User Guide: High-Level Synthesis
该文档主要涉及vivado HLS的理解,vivado HLS软件的初步使用,以及相应的HLS相关的c语言库等,我们主要关注该文档的第一章:用vivado HLS软件实现HLS(高层综合High-level Synthesis)
UG871:Vivado Desigh Suite Tutoril:High-level Synthesis
该文档主要涉及vivado HLS软件的具体操作过程,包括HLS的介绍、c的验证、管脚综合、任意精度数、设计分析、优化分析、RTL验证、用HLS生成集成IP、在Zynq的AP Soc设计中用HLS生成的IP、这个文档是操作的重点。文档中有较多设计实例可以参考。
一、二、三为软件用法和具体操作步骤,四、为我们实现我们的代码需要完成的工作。
目录
一、打开及创建工程
二、进行相应的synthesis
三、输出RTL为IPcore
四、实现cnn主程序编译为IPcore
打开软件,creat project这些基础的操作就不讲了。我们的版本是vivado HLS 2016.4
相应的LeNet-5的源码去github上下载,注意需要是c或者c++版本的代码。运行前务必看懂其中的代码,至少知道每个函数的意思和调用关系,这样后面操作才会顺畅。(HLS只可以synthesis部分的c和c++程序,所以有部分源码不可用,这个是后面讨论的内容。)
1.1. 下面我们就打开软件,create new project,输入相应的工程名和工程位置。
1.2. 把相应的文件添加到对应位置。注意一个加入的是source file,意思是用于进行HLS综合的源c代码,另一个加入的是testbench,就是用于测试和后续验证的c语言代码和相应的数据。
top function意思是进行synthesis的c的最高级别的函数。
1.3. 创建solution,period是时钟周期,默认10ns,旁边uncertainty为时钟不确定性,点part selection
因为我们用的是Xilinx zynq 7z035和7z020的测试板,为具体的每个板子的型号。点击finish就进入下面界面。
把面板中各个部分和相应的按钮熟悉一下。一会会在操作中用到这里的按钮,不要找不到对应的命令按钮。
可以按照UG902文档中Chapter1的流程把相应的例程运行一遍。该例子按顺序实现了管理端口接口、优化设计、进行RTL验证、输出RTL设计。为c到RTL语言的全部流程。
这里我们只运用涉及我们项目进行到的操作。synthesis步骤之中只需要进行一步,就是加入derective优化之后进行c synthesis,其他步骤只是为了验证和debug程序用的。
2.1. 将程序添加到相应的目录
注意source中为子程序,test bench中为测试的程序和需要读入的东西。
2.2. 我们先进行相应的仿真验证,上面图1-8中的operation中的点击c simulation,进行c语言的仿真,会发现程序正常运行。
2.3. 但是在进行C/RTL cosimulation(非必要步骤)的时候,出现了一定的问题
ERROR: [SYNCHK 200-61] src/top.cpp:49: unsupported memory access on variable 'sample' which is (or contains) an array with unknown size at compile time.
ERROR: [HLS 200-70] Synthesizability check failed.
command 'ap_source' returned error code
while executing
我们可以发现问题的所在,用于c与RTL协同synthesis中的top.cpp中的neural中的一个sample的指针,在c编译的时候可以用指针,但是vivado HLS并不知道这个sample的大小,因此不知道如何在板子中给sample分配内存,因此synthesis失败了。同时,另一个问题可能与ap_source有关。
我们所以要解决这个问题,必须搞明白数组是如何在FPGA中存储的。同时搞明白ap_source是个什么。
2.4. 在进行搞明白相应的存储以及ap_source之前,我们尝试在程序中下手解决这个问题,首先在top.h中把top.h中加入#define N 480,然后把1830行的声明去掉nerual(float *sample, unsigned int *result),top.cpp中也去掉输入的参数int N。
程序synthesis了很久,没有像第一次那样快速的报错。
为了避免重复的操作耗费时间,我们将程序中的sample加入axi4总线。然后在几个主要的底层的for循环之中运用PIPELINE。(不知这个步骤对于缩减运行时间而言有用与否。并且具体的优化比较繁杂,后面再看)
终于完成了c的synthesis。完成synthesis之后,会生成一个相应的报告,大致涉及运用的资源以及时钟周期,我们先不管报告内容,那是后面优化所需要做的内容(优化相关知识在UG902 中的Optimizing the design中)。我们先继续往下运行,把流程先跑通。
2.5. 点击C/RTL cosimulation(非必要步骤),进行c与RTL的协同综合(UG902中Verifying the RTL)。运行依然非常慢。(但是此步骤可以略过,完成输出RTL此步骤并非必须的)
运行一晚上之后进展缓慢,我们可以重新开始一下试一下。
第一次勾选的是VHDL,并且没有勾选optimizing compile选项,运行一整晚卡在一个地方。现在我们运行verilog,并且勾选Optimizing compile选项。
以下选项含义(UG902 Using C/RTL co-simulation):
这次没有像上次一样卡在一个地方不动,但是RTL仿真时十分慢,运行了两天左右达到了这个进度,并且进度大于100%,为了解决这个问题我们需要查阅文档找出原因。
在运行了三天之后,我们停止了此过程,此时已经可以进行export RTL,(其实在进行synthesis之后就能export RTL了)
点击export RTL,输出RTL成功表明生成IP core成功,我们在后续的工作中可以通过vivado验证这一点。
在进行完这些步骤后,我们大致可以认为已经可以将c语言通过vivado HLS转化为相应的硬件RTL语言,下面我们就开始进行相应的系统设计。
1.创建工程,添加源码这些就不说了,我们需要给两个参数加入相应Interface的axi总线协议,这样才能通过单片机与相应的IPcore实现传递数据。
要给相应的输入输出流加axis总线协议。这样生成的IPcore的才有两个接口,不然生成的IPcore接口有很多。例如下图为一个典型的错误的IPcore
2.点击c synthesis,之后点击export RTL,就把相应的IPcore保存在了对应的solution目录里面了。
生成的IP为XCI文件,能被加入到project之中。
后续步骤:
实践教程(一)用HLS生成IPcore
实践教程(二)连接片上ARM
实践教程(三)系统搭建与烧录
实践教程(四)片上ARM运行程序
实践教程(五)PS用MIG调用DDR
FPGA基础知识(一)UG998相关硬件知识
FPGA基础知识(二)HLS相关知识
FPGA基础知识(三)UG902 接口综合
FPGA基础知识(四)UG902 RTL simulation and export
FPGA基础知识(五)系统集成知识
FPGA基础知识(六)UG586 Mermoy Interface Solutions
FPGA基础知识(七)片上单片机
FPGA基础知识(八)vivado设计流程中的知识
FPGA基础知识(九)SDK相关知识
FPGA基础知识(十)DMA与AXI4总线
尝试用IPcore调用DDR3及相关知识
vivado HLS硬件化指令(一)HLS针对循环的硬件优化
vivado HLS硬件化指令(二)HLS针对数组的硬件优化
vivado HLS硬件化指令(三)HLS增大运算吞吐量的硬件优化
vivado HLS硬件化指令(四)卷积相关的指令优化
卷积操作的HLS优化
FPGA实践教程(一)用HLS将c程序生成IPcore
FPGA实践教程(二)连接片上ARM
FPGA实践教程(三)系统搭建与烧录
FPGA实践教程(四)片上ARM运行程序
FPGA实践教程(五)PS用MIG调用DDR
FPGA实践教程(六)AXI-Lite实现PS与PL通信
FPGA实践教程(八)PS与PL共享DDR
FPGA vivado系统集成操作
DMA在linux下PS端c语言相关内容
数据流输入输出IPcore时c语言相关内容
调通DMA系统集成中遇到的问题
ARM用MIG调用DDR3的c程序解析
MIZ7035上的AXI接口的MIG测试
MIZ7035交叉编译单片机程序运行