如何在书写代码时进行速度优化
设计的优化最好交给代码自身来完成,不到万不得已千万不要使用工具来对设计进行优化。
在逻辑设计业内,前辈设计师给这些后来者早就总结了三大设计原则,即速度面积互换、并行以及同步设计原则。
根据逻辑设计的内涵,基本可以给逻辑设计速度定义三个有关的概念,即**设计吞吐量、设计延时以及设计时序。**这里的速度优化将主要针对时序优化而言。
吞吐量是指每个时钟周期能够处理的数据量,常见的吞吐量单位如比特每秒(b/s)。
设计延时是指输入数据和数据被处理后输出之间的时间间隔,它的典型单位是普通时间单位(s,ms等)或者是系统时钟周期数。
吞吐量和设计延时好比工业控制中的流水线,吞吐量只关心流水线末端下线产品数量,延时关心的是某个单一产品在流水线上流程的的时间。
设计时序是指该设计的时钟速度,一个设计中任何两个时序单元之间的最大延时将最终决定这个设计的最大时钟速度。时序优化的目的就是要使得设计满足设计时序的要求,从而达到设计时序收敛。
编写时序收敛代码的总体规则:
1、在进行代码设计之前一定要进行良好的计划和规划。设计更改的代价一般都很大。并且合理的层次结构划分有利于使用增量编译;使逻辑设计更利于优化布局;一旦需要修改代码,修改某一个模块总比修改整个设计要简单。
2、在代码编写过程中,要时刻记得所编写的代码具体实现的电路到底是什么,不要停留在行为级,要深入到数据路径、寄存器等。
3、设计出来的代码需要和目标器件相匹配,当然首先是需要根据设计需求选择合适的器件。其次是分析出你的设计将会需要哪些资源,并且各需要多少。
废话不多说,看时序优化例子:
一、通过减少关键路径上的组合逻辑单元数来优化时序
FPGA逻辑设计中时序路径上的组合逻辑都会给路径增加延时,而影响设计性能的往往只是那几条关键路径而已,所以可以通过减少关键路径上的组合逻辑单元数来减少该路径上的延时,从而达到优化时序的目的。
如下图示,b信号是关键信号,其延时较长,可以通过修改代码修改关键信号的路径。
这种技巧也被称为关键路径重组,多用于关键路径由多个路径组合而成的场合,而且这些被组合的路径之间又可以重组相互之间的先后顺序。通过这种简单的顺序重组,可以使得寄存器之间的关键路径被拉得更近。
二、适当进行逻辑复制以优化设计速度
逻辑复制是指当某个信号的扇出比较大时,会造成该信号到各个目的逻辑节点的路径变得过长,从而成为设计中的关键路径,为了解决这个问题,可以通过在书写代码的时候对该信号进行复制,以达到“分担”信号扇出过多的目的。其原理如下图所示,左图为逻辑复制前,右图为逻辑复制后:
逻辑复制具体可分为组合逻辑复制和寄存器复制,下面对此依次举例介绍:
组合逻辑复制:
如上设计中有两个输出,必然需要至少两个查找表,而temp信号到达两个查找表的路径可能不同。
通过组合逻辑复制得到如下结果,如此可以使得两个寄存器获得独立的输入,使得寄存器输入路径得到改善。
寄存器复制:
由于髙扇出信号会增加布局难度,减缓布线速度,可以通过寄存器 复制解决两个问题:减少扇出,缩短布线延时;复制后每个寄存器可以驱动芯片的不同区域,有利于布局布线。
如下即为寄存器复制例子,寄存器tri_end驱动了 24个输出,这样高扇出信号会带来很多不稳定性,如驱动能力不够,延迟太大等。右边为布线后结果,可以看到密密麻麻一片。
现在对此设计进行修改,使用两个寄存器,分别驱动12个输出,可以减小寄存器高扇出情况。将修改后的代码编译以后得到如下图所示。可以看到,两个寄存器分别驱动了 12个输出。
三、在组合逻辑中插入寄存器优化时序
现代逻辑设计大部分是同步设计,所以很多时候设计节点都是参考时钟沿,那么如果寄存器和寄存器之间的逻辑路径过长,就会成为拖累设计的关键路径,这时就可以考虑在该路径上插入额外的寄存器。这种插人寄存器的方法,也被称为插入流水线。
**Tips:**插入额外的寄存器是一种会增加设计延时,不改变吞吐量,但可以使得系统时钟速度提高的方法。
下图形象的表达了插入寄存器改善时序的方法:
下面给出插入寄存器优化时序的具体例子:
如下图所示,代码综合成了三个乘法器,并分为两级,而两级乘法器之间并无寄存器,一般这种乘法都要求在一个时钟周期之内完成。这样很有可能使得此处某条线路成为整个设计的关键路径。
因此可以在两个乘法器之间插入一级寄存器,插入后的结果如下图,同时可以查看报告,可以使得系统最大时钟速率得到提高。
四、通过寄存器平衡优化时序
首先介绍另一种平衡:操作符平衡,这种平衡就是通过合理 使用括号来对逻辑进行分组,通过这种技术可以增加设计性能,平衡所有输入到输出的延时,而整个设计的功能并不会改变。如下图所示,通过合理使用括号,平衡乘法操作符,使得输入到输出的延时从三级乘法操作减少到两级。
现介绍寄存器平衡。将原先的设计进行稍微改动,中间插入一些寄存器,如下图示:
可以发现,此设计的关键路径是输入c或d或e到输出寄存器那条路径,此路径在一个时钟周期内要实现三次乘法,要求较高,其实可以在此处插入寄存器,但是加入不允许插入寄存器(插入寄存器意味着增加一个时钟周期的延时),此时可以通过寄存器平衡的方法,来达优化速度的目的,即将第二个乘法器移动到前面。其修改后结果如下图示:
由此可以得出,寄存器平衡从概念上来讲,是将任意两个寄存器之间的逻辑重新平均分配,以达到最小化这两个寄存器之间的最大延时的目的。这个技巧通常用于关键路径和其相邻路径之间的逻辑分布髙度不平衡的情况。其原理如下图所示:
五、使用并行结构优化时序
使用并行结构可以优化关键路径上的延时,其实前面的操作符平衡已经给出了这样一个例子。其实质就是通过重组组合逻辑达到提升设计性能的目的。类似的例子如:
Outl<=Il + I2 + I3 + I4;
修改为
Out2<= (II + I2) + (I3 + I4);
从结构上看,第一种描述中并没有使用括号,电路结构为3层,加法一级一级地进行。它的特点是4个输入到达加法器的路径不相等;第二种描述中使用了括号,就是之前介绍的所谓的操作符平衡,电路结构分为两层,显然它的特点是4个输入信号到达加法器的路径是相等的。不管是速度优化还是面积优化,使用括号来平衡操作符都能达到意想不到的效果。
六、通过消除代码中的优先级优化速度
逻辑设计中经常使用if-else语句,if-else嵌套长度不宜过多,此处不讨论此问题,而是讨论如何通过消除代码中 的优先级来优化设计的速度。所谓消除优先级,就是说设计功能可以通过无优先级方式来实现,对于那些对优先级有要求的功能模块无法使用这个技巧。
如下图是一个带有优先级的if-else语句综合出来的电路,
可以看到优先级最低输人到输出要经过最长的逻辑延时路径。假如设计中可以不在意各个输入的优先级,那么可以对代码进行修改,将if-else语句改为case语句,得到的电路如下图所示:
这样进程中顺序执行的语句都改成了并行执行,各个条件入口之间并无优先级差别。修改后输入到输出只经过了一级组合逻辑,而修改之前需要经历4级逻辑。
这种消除代码中的优先级的策略也称为代码结构平坦化技术。
总结:速度优化方法有6:
一、通过减少关键路径上的组合逻辑单元数来优化时序
二、适当进行逻辑复制以优化设计速度
三、在组合逻辑中插入寄存器优化时序
四、通过寄存器平衡优化时序
五、使用并行结构优化时序
六、通过消除代码中的优先级优化速度
注:本文参考了FPGA设计实战演练(高级技巧篇)作者:王敏志