写在前面
本文对UG871提供的FIR滤波器进行简单的优化设计。
该工程的设计目标是: 创建具有最高吞吐量的此设计,最终设计应该能够处理输入有效信号提供的数据,产生伴随输出有效信号的输出数据。滤波器系数将存储在 FIR 设计外部的单端口 RAM 中。
创建工程并添加相关文件
FIR滤波器工程 ,添加introduction 的 Lab3中相关的C和H文件添加到工程。如图所示:
添加完成后,点击c synthesis,完成c综合可以得到综合后的设计报告。
分析综合报告
当前版本综合后的接口信息如下:
通过系统自动分析的y综合成了目标接口,而x没有综合成目标接口,并且没有实现预期的输出C对应的是单端口的RAM接口。实现的目标总结来说为:端口 C 必须具有单端口 RAM 访问权限。端口X 必须有输入数据有效信号。端口 Y 必须有输出数据有效信号。
IO优化
查看完成相关综合报告后,保留当前的综合结果,进行新建solution,点击工程按钮并新建solution。完成创建。他创建了 solution2 并将其设置为默认解决方案。 为了确认您可以验证当前活动的解决方案 2 在资源管理器窗格中以粗体突出显示。创建了 solution2 并将其设置为默认解决方案。 (默认解决方案字体会加粗显示)或者进行右击设置解决方案。
双击 fir.c 在信息窗格中打开文件。激活Auxiliary面板中的Directive选项卡。
Directives 选项卡列出了设计中所有可以优化的对象。 在指令选项卡中,您可以向设计添加优化指令。 选中要进行优化的对象,然后右键点击插入指令。
在指令编辑器中对x和y添加接口优化,优化为带有效信号的接口信号,也即优化为ap_vld类型。插入指令建议指令添加到优化的脚本文件中,方便对设计进行进一步优化处理对比。
对c进行优化为BRAM类型。
添加完成并执行进行c综合,分析综合报告。
此时接口已经实现目标要求的接口方式
查看设计
在综合完成后可以进行对整个代码的处理的过程进行查看,分析透视图以交互方式提供了更多详细信息,从而方便进行进一步的优化和处理。
点击Analysis 按钮进入到分析界面。
从界面显示可以看出,该设计主要的执行在loop中进行,所以点击loop进行查看处理过程。
从上图可以分析出代码的运行流程,设计从第一个状态开始,在端口 x 上进行读操作。在下一个状态,它开始执行由 for 循环 Shift_Accum_Loop 创建的逻辑。
在循环的第一个状态下,检查循环迭代计数器:加法、比较和潜在的循环退出。对由数组数据合成的块RAM 进行了两个周期的存储器读操作(一个周期生成地址,一个周期读取数据)。在 c 端口上有一个内存读取。乘法运算需要 1 个周期才能完成。 在该设计中for 循环执行了 11 次。
在最后一次迭代结束时,循环以状态 c1 退出,并发生对端口 y 的写操作。
还可以使用 Analysis 透视图来分析设计中使用的资源,单击 Resource 视图,查看每个部分的资源使用。
在端口 x 上有一个读操作,在 y 端口上有一个写操作。 端口 c 在内存部分报告,因为这也是内存访问(内存在设计之外)。设计中使用了一个流水线乘法器。并且有一个加法器正在被共享:一行中有两个加法器实例(图中的grp_fu_138)。
优化最高吞吐量(最低间隔)
在此设计中限制吞吐量的两个问题是:
- for 循环 :默认情况下循环保持滚动:循环体的一个副本被合成并在每次迭代中重新使用。 这确保循环的每次迭代都是按顺序执行的。 您可以展开 for 循环以允许所有操作并行发生。
- 用于 shift_reg 的块 RAM: 由于变量 shift_reg 在 C 源代码中是一个数组,因此默认情况下它是作为块 RAM 实现的。 然而,这阻止了它作为移位寄存器的实现。 因此,您应该将此块 RAM 划分为单独的寄存器。
首先实现对for循环的优化,最简单的优化方式对for循环进行完全展开。
在优化指令中对loop添加unroll。将指令窗口中的其他选项保留为未选中和空白,以确保循环完全展开。
然后添加对shift_reg的约束。使用指令将数组划分为单个元素。在指令选项卡中,选择数组 shift_reg,右键单击并选择插入指令。 从指令下拉菜单中选择 Array_Partition。指定类型为complete。
优化完成后进行C综合,并查看综合后的分析报告。
对比报告信息
可以添加优化的solution进行资源、吞吐量等部分的对比。点击比较报告,
进行添加要比较的solution,点击OK完成。
对比报告如下:
从对比报告中可以看出三种solution的资源延迟和时钟等情况信息。
Reference
- UG871