理解Vitis HLS默认行为
相比于Vivado HLS,Vitis HLS更加智能化,这体现在Vitis HLS可以自动探测C/C++代码中可并行执行地部分而无需人工干预添加pragma。另一方面Vitis HLS也会根据用户添加的pragma来判断是否需要额外配置其他pragma以使用户pragma生效。为便于说明,我们来看一个简单的案例。
如下图所示代码,函数array_mult用于计算两个一维数组对应元素差的平方。数组长度为N,故通过N次for循环可完成此操作(这里N为8)。
如果我们不添加任何pragma,从C综合后的报告来看,工具会自动对for循环添加PIPELINE,如下图所示。同时,工具会将数组映射为单端口RAM(因为数组是顶层函数的形参,故只生成单端口RAM需要的端口信号),这样匹配了DSP48的接口需求(两个输入数据一个输出数据)。从C/RTL Cosim的波形可以看到输入/输出数据流关系。
如果我们对for循环施加UNROLL,理论上分析可知工具应将for循环展开(复制8份),这样会消耗8个DSP48,如下图所示。这就需要能同时有16个数据提供给这8个DSP48,但此时工具只是将数组映射为双端口RAM。这显然造成了数据通路的不匹配。这其实造成了DSP48的浪费。这里,因为数组是顶层函数,故工具并没有对其施加ARRAY_PARTITION,但如果是子函数的形参,工具就会自动对数组施加ARRAY_PARTITION,以确保数据通路的匹配。
因此,我们换个思路,既然工具至多会将数组映射为双端口RAM,那么我们就将for循环复制两份,从而实现数据通路的匹配。这可通过UNROLL的选项factor设置为2。从C综合报告来看,消耗了2个DSP48,同时工具对for循环自动设置了PIPELINE。
当然,我们也可以对整个函数施加PIPELINE,这样工具会将for循环自动UNROLL,但这同样会造成DSP48的浪费,因为工具不会对顶层函数的形参数组自动进行ARRAY_PARTITION。于是,我们考虑手工添加ARRAY_PARTITION,同时对函数添加PIPELINE,从而使得数据通路完美匹配。
我们对这些Solution进行对比,如下图所示。solution1消耗资源最少,但Latency最大;solution5消耗资源最多,但Latency最小。
solution1:仅对for循环施加pipeline。
solution2:仅对for循环施加UNROLL。
solution3:仅对for循环施加UNROLL并将factor设置为2。
solution4:仅对函数施加PIPELINE。
solution5:对函数施加PIPELINE,对输入/输出数组施加ARRAY_PARTITION(Complete)。
Copyright @ FPGA技术驿站
转载事宜请私信 | 获得授权后方可转载
相关文章
- 说说你对Vue的keep-alive的理解
- 一个经典例子让你彻彻底底理解java回调机制是什么_java实现回调函数
- 《深入理解Java虚拟机》读书笔记(一)
- 简单的理解synchronized锁升级
- 深入理解Java虚拟机 – 类加载机制详解编程语言
- Linux运维的真正含义:一种技术实践(linux运维的理解)
- 深入理解Linux系统的默认目录权限(linux默认目录权限)
- Oracle所有对象:全面掌握和深入理解(oracle所有对象)
- 深入理解Linux中的进程堆栈(linux查看进程堆栈)
- 探索Redis连接状态一次理解即可(查看redis 连接状态)
- 深入理解Redis默认连接超时的影响(redis 默认连接超时)
- 深入理解Redis默认的淘汰策略(redis默认的淘汰策略)
- 深入理解Redis默认存储目录(redis默认存储目录)
- 运算深入理解Oracle SQL中的取模运算(oracle sql取模)
- 深入理解Javascript动态方法调用与参数修改的问题