首页 > 其他分享 >FPGA学习笔记#6 Vitis HLS For循环的优化(2)

FPGA学习笔记#6 Vitis HLS For循环的优化(2)

时间:2024-11-10 22:16:43浏览次数:6  
标签:perfect PIPELINE FPGA HLS 循环 Vitis 优化 loop

本笔记使用的Vitis HLS版本为2022.2,在windows11下运行,仿真part为xcku15p_CIV-ffva1156-2LV-e,主要根据教程:跟Xilinx SAE 学HLS系列视频讲座-高亚军进行学习

目录


1.DATAFLOW

1.1.DATAFLOW的使用场景

当循环之间、函数之间、线程之间有顺序数据依赖,可以考虑使用DATAFLOW优化,考虑以下情况:

可以很明显地看出,B依赖A计算得到的x[i],C依赖B计算得到的y[i],三个任务形成了如图所示的关系:

此时我们可以考虑使用DATAFLOW,作用于循环所在函数,对应配置为#pragma HLS DATAFLOW:

优化后,三个循环间的关系如图所示,循环之间使用管道、FIFO、寄存器等进行数据传输,每个Loop只需要每轮完成计算后将结果送入数据通道,即可开始下一轮计算,后一个Loop等待到通道传来数据就可以开始计算。

与PIPELINE的不同:

PIPELINE:对于一个循环内多个循环次数之间的优化
	例如一个循环中每次循环涉及读-计算-写三步,则在操作间无依赖时可以进行流水线,让三个步骤都各自连续执行
DATAFLOW:对于循环间/函数间/线程间的优化
	例如上方的Loop A-B-C,下一个Loop的输入是上一个Loop的输出,则DATAFLOW可以让三个循环都各自连续执行

1.2.DATAFLOW编程约定

1.2.1.Single-producer-consumer Model

一个输出(write)对应一个输入(read),多个consumer依赖同一个producer时,DATAFLOW不成立,以如下代码为例,loop2和loop3同时使用了temp1的数据,如果是图中的情况,那么硬件层面上会产生读冲突,如果使用FIFO,那么temp1只能被读取一次。

此时如果想启用DATAFLOW,那就需要添加一个中间件,其读取一个输入,并写到两个输出,如下图中的loop_copy循环:


1.2.2.Bypassing Tasks Model

Loop1输出temp1和temp2,Loop2读取temp1,输出temp3,Loop3读取temp2和temp3,这样也是不能启用DATAFLOW的:

启用思路:在Loop2将Bypass的数据读取并复制一份。


2.嵌套For循环

2.1.嵌套For循环的优化逻辑

对于嵌套For循环,首先我们要确定什么样的For循环更适合被优化。

首先如下图所示,内外循环的循环上限均为固定值的循环为perfect loop,这是嵌套优化的最理想状况;内部上限为固定值,而外部为变量的为semi-perfect loop,这种情况也是可以优化的。

对于不理想的嵌套循环有两种,第一种是内外部上限均为固定值,但有语句写在循环之间的,如下图中的LOOP_BODY所处位置;第二种是内部上限为变量,外部为固定值的。这两种情况被称为imperfect loop。

那么我们优化的流程就很明显了:perfect/semi-perfect loop就直接优化,imperfect loop就先尝试转变为perfect/semi-perfect loop,如果不能,再考虑直接对imperfect loop进行优化。


2.2.perfect/semi-perfect loop优化

对于可优化的嵌套循环,我们可以考虑对For循环进行PIPELINE优化,如下图为一个perfect loop

对嵌套循环的不同层进行PIPELINE优化存在差异,如下图是默认情况、给内层添加PIPELINE、给外层添加PIPELINE的结果。

给内层添加PIPELINE时,会进行FLATTEN操作,将外部循环2次执行4次内部循环展平为执行8次循环。
给外层添加PIPELINE时,会将内部所有循环进行UNROLL,然后统一进行PIPELINE,可以看到给外层添加PIPELINE时,乘法器使用了4个,共执行2次循环。


2.3.imperfect loop优化

如果想要优化的循环是任意一种形式的imperfect loop,那么我们最好先考虑将其转化为perfect/semi-perfect loop,如果无法转化,那么我们要知道直接优化会带来怎样的结果。

以下图所示的imperfect loop为例,在Col循环和Product循环之间多了一个res[i][j]=0的重置操作,这使得Col->Product是imperfect的。


2.3.1.最内层PIPELINE

首先,在最内层的Product打上PIPELINE。从debug信息,我们可以看到HLS会将外层Row展平,但因为Col->Product是imperfect的,所以Col无法执行Flatten。

最终可以看到Flatten之后,Row和Col展平为9次循环,然后每次循环执行Product循环:


2.3.2.中间层PIPELINE

然后,对Col层打PIPELINE。通过debug信息,可以看到HLS将内部所有循环做UNROLL,然后对本次与外层进行FLATTEN。

最终得到的结果是执行一个9次的循环,每次循环将Product的操作一轮执行完。


2.3.3.最外层PIPELINE

最后,对Row层打PIPELINE。通过debug信息,可以看到HLS将Row内部所有子循环都进行了UNROLL操作。

最终,函数会执行Row的三次循环,内部会将Col和Product的操作一次性执行完毕,消耗的乘法器变为9个。


2.3.4.对函数进PIPELINE

根据上面三次优化,很自然的可以想到再进一步将Row循环也UNROLL可以换取更高的效率,那么我们直接对其所在函数打PIPELINE,得到的DEBUG信息如下,三个循环都被UNROLL了:


2.3.5.优化结果

通过对比四次优化的结果,很明显PIPELINE越往外性能越高,但同时资源消耗也成倍上涨,对于任意循环打PIPELINE时,HLS会对其子循环进行UNROLL,对其外层非imperfect loop进行FLATTEN。


3.其他For优化

3.1.函数多次实例化

对于一个函数内多次调用另一个函数的情况,如下图,HLS默认会分时复用该函数,即串行执行。

我们可以使用ALLOCATION约束,这个约束会增加函数的实例化数量,对loop_sequential添加directive如下,其中limit是最多实例化个数。

#pragma HLS ALLOCATION instances=Accumulator limit=2 function

在生成信息中,我们可以看到HLS为该函数生成了两个实例。


3.2.循环之间的间隔

如下图,多次调用同一个函数,并且该函数只有一个循环时,循环之间会产生间隔,此时可以使用PIPELINE中的rewind参数:

#pragma HLS PIPELINE rewind

便可以将循环之间的间隔消除:

注意,一个函数包含多个Loop的情况下不能进行rewind优化


3.3.自动PIPELINE

在config_compile中配置,只要一个for循环的循环边界小于等于pipeline_loops配置的值,那么编译时就会HLS就会自动进行PIPELINE。

在启用自动PIPELINE时,如果某些符合条件但不想PIPELINE的,可以配置:

#pragma HLS PIPELINE off

3.3.Latency的确定

当循环边界是变量时,Vivado无法确定latency,设计的性能未知

此时可以采取以下方案:

1.使用trip count directive,不做优化,只用于报告的显示和比较

#pragma HLS LOOPTRIPCOUNT min=4 max=8 avg=6

2.定义循环边界为ap_int<>或ap_uint<>(在自减时要注意无符号)

3.使用断言assert

#include <assert.h>
assert(width < 5)

标签:perfect,PIPELINE,FPGA,HLS,循环,Vitis,优化,loop
From: https://blog.csdn.net/qq_38876396/article/details/143662824

相关文章

  • FPGA实现串口升级及MultiBoot(六)ICAPE2原语实例讲解
    本文目录索引一个指令和三种方式通过ICAPE2原语添加ICAPE2IP构建Golden位流工程MultiBoot位流工程验证example2总结代码缩略词索引:K7:Kintex7V7:Vertex7A7:Artix7MB:MicroBlaze上一篇文章种总结了MultiBoot关键技术,分为:一个指令、二种......
  • FPGA实例——数码管(下)
    前言:上一篇文章的话是介绍了关于数码管的基础知识和静态数码管的verilog代码,那本章的话将去介绍如何实现动态数码管以及它的verilog代码和展示动态数码管:简易计数器:这里的话主要去介绍一个简易的计数器,由按键控制开始和结束,每秒自加1,从0计到9999,计满后清零动态数码管显示......
  • FPGA 第二讲 初始FPGA
    时间:2024.11.4-11.5一、学习内容1.FPGA是什么1.1名词解释:FPGA(FieldProgrammableGateArray,简称FPGA),现场可编程门阵列,一种以数字电路为主的集成芯片,属于可编程逻辑器件PLD(ProgrammableLogicDevice)的一种。 1.2发展历程集成电路:我们常说的IC,就是把一定数量的常用的......
  • Lattice、Xilinx FPGA reg初始化赋值问题
    一、起因最近在开发Lattice的一款低功耗FPGA时,遇到了reg初始化复位问题,经过在网上搜寻相关资料整理如下;二、FPGA中reg的初始化方式在定义时初始化,例如:regr_test=1'b1;在复位语句中,对reg进行赋值,例如:regr_test;always@(posedgesys_clk)beginif(~sys_rst_n)beg......
  • fpga LCD屏幕显示
    目录matlab生成coe文件150x150的JPG转化为coe文件 ROMip核配置​编辑LCD显示驱动代码 原理和vga一致。 vga_parameter_cfg,v gen_data vga_driver vga_toptop_pin_xdc上板验证matlab生成coe文件150x150的JPG转化为coe文件%实现将图片的格式转换为数据处......
  • 海康私有化视频平台EasyCVR视频分析设备平台流媒体协议RTMP、HTTP-FLV、HLS的简单对比
    在当今的数字化世界中,视频流协议的选择对于确保流畅、高效的视频传输至关重要。随着互联网技术的快速发展,直播和视频点播服务已经成为人们日常生活中不可或缺的一部分。无论是安防监控、在线教育、远程会议还是娱乐直播,用户对于视频流的实时性、稳定性和兼容性都有着极高的要求。......
  • 基于Zynq FPGA对雷龙SD NAND的测试
    一、SDNAND特征1.1SD卡简介雷龙的SDNAND有很多型号,在测试中使用的是CSNP4GCR01-AMW与CSNP32GCR01-AOW。芯片是基于NANDFLASH和SD控制器实现的SD卡。具有强大的坏块管理和纠错功能,并且在意外掉电的情况下同样能保证数据的安全。其特点如下:接口支持SD2......
  • FPGA实现复杂状态机的跳转-判断标准数据帧
    填补之前的状态机跳转挖的坑;数据源对比标准帧:第一步:ROM当做数据源:使能开启,使用地址addr控制其输出。(使用状态机写入RAM时的控制选用addr)RAM作为标准帧的缓存,使用addr_ram作为RAM的写入地址。此时ROM的地址比RAM的地址延迟了一个节拍;(addr_ram<=addr;)第二步:RAM缓存写满之......
  • vitis2024.1创建Linux应用
    环境安装软件下载路径环境vitis2024.1ubutnu22.04简介一般使用pretalinux编译后的文件,制作为文件系统后,在/usr/bin/找到编译后的可执行程序。首先我的开发板已经使用petalinux2024.1制作好了系统,硬件层面也使用vivado2024.1做好了配置,网络连接没有问题,后续的程......
  • 基于FPGA的可控分频器设计与应用
    ###标题:基于FPGA的可控分频器设计与应用---####正文:可控分频器在数字电路中扮演着重要角色,尤其是在频率合成和时钟管理方面。基于FPGA的实现不仅灵活且易于修改,本文将详细介绍如何设计和实现一个可控分频器,并展示其应用实例。---###一、可控分频器的基本概念可控分频......