【转】时序优化一例
【转载文章用于学习】
学习时序也有一段时间了,一直也没分享什么学习笔记。这次以时序优化为例,检验一下这阶段的学习成果。
关于时序方面的东西也看了、学了很多,就是练得很少,在平常自己的设计中很难找到非常针对的设计来练习,只能在今后的学习中慢慢发掘了。最近在整一个设计,在要求的指标下时序是满足的,但是为了拿它练手,故意将它的时钟约束提高一倍:
create_clock -name {sysclk} -period 4.000 -waveform { 2.000 4.000 } [get_ports {clk}]
图1
约束到250M了,发现建立时间不满足,如图1所示为10条违规路径,可以发现主要都是From Node:DC_Off模块到To Node:estimator模块的路径,在此设计中不涉及input、output的分析,因此时序模型主要是针对reg-to-reg,一般此情况下的时序违规主要是data_path中的组合逻辑过长或者高扇出导致的。下面通过TimeQuest Timing Analyzer分析一下:
图2
时序波形图如图2所示,建立时间余量是通过Data Required Time减去Data Arrival Time得到的,由于Data Path的时延过大,有4.906ns,导致setup slack为负。
图3
由图3可以发现时序违规的关键路径上的Logic Levels达到13,这主要是在代码中逻辑过于复杂和多层的if…else…、case导致的。通过Locate Path到Technology Map Viewer可以清晰得查看关键路径上的逻辑,如图4所示,与开始的分析相符,主要是DC_Off模块和estimator模块之间的路径,其中包含大量的加法器逻辑,导致时延过大。
图4(看不清可另存查看)
一般解决关键路径过长问题达到时序收敛的方法,针对逻辑复杂的问题可以加入流水线级分割逻辑;而针对多层的if…else… 、case则需要优化代码避免不必要的优先级编码,这需要的工作量稍大,在验证阶段一般的程序猿也没心思去仔细得抠代码了,因此相比于此方法,加入pipeline还是性价比高的解决办法。在此设计中,修改代码,在DC_Off模块和estimator模块间加入了一级流水线寄存器,如图5所示。
图5
可以发现图5路径中的逻辑是图4路径中逻辑的一部分,加入流水线级后逻辑果然被分割了,然后看一下该路径时序波形图,如图6所示,通过逻辑分割后这条路径Data Path的时延减小到了2.887ns,已达到时序收敛了。
图6
解决了原先的关键路径,再次check一下timing,发现还是没有收敛,如图7所示,setup slack还是负的,不过-0.381还是比原先的-1.070提高不少了,但是关键路径不是原先那条了,而是主要集中在Div模块内部。
图7
Div模块只是例化了一个除法器IP核,难道官方提供的IP核有问题,翻阅了一下除法器的手册,找到了它的性能指标,如图8所示,在我的设计中Device Family为Stratix IV,Input Data Width为32,Output Delay为16,估计fmax达到250M还真是够呛啊。
图8
在这个例子中,现阶段时序虽还未收敛,但是还是优化了不少。从中自己也收获不少,学会了通过TimeQuest Timing Analyzer分析,并且进行有针对性的优化,不会再像以前那样遇到时序问题时那么盲目,不知从何下手。下一阶段,再试试用其它方法优化这个设计,不达到时序收敛誓不罢休!
//*********************************************************************************************************************************
//*********************************************************************************************************************************
在《时序优化一例(一)》中采用修改代码的方法优化了一实例,通过加入一级流水线寄存器分割组合逻辑达到该路径时序收敛,但是重新check一下timing发现还有时序不满足,而且还是除法器IP核的时序未收敛,对于这官方提供的IP核那就没办法通过修改代码进行优化了。查了些资料,发现还可以通过物理综合优化,在没有使能物理综合前,QuartusII软件只进行逻辑综合,逻辑综合中的时序仅限于综合后的门级电路或者器件内部的逻辑单元的时延信息,并没有包含布线时延信息,也就是说Synthesis与fitter并没有交互操作;而物理综合则在综合时考虑具体的布线时延信息,使获得不错的综合结果。
QuartusII提供了几个选项,可以通过Settings->Compilation Processing Settings->Physical Synthesis Optimization打开,如图1所示。
图1
其中主要分为两部分:
1. Optimize for Performance:主要用于优化性能
2. Optimize for fitting:主要用于优化fitter
与时序相关的就是第1部分(Optimize for Performance)了,翻阅了官方手册,找到了对应各选项的解释。
Perform physical synthesis for combinational logic:通过交换LEs中LUT port来减少关键路径的逻辑层数目,同时还会通过复制LUT解决扇出过大的问题,此选项只影响combinational logic,并不对register进行优化;
Perform register retiming:关于register retiming的概念,主要是为了解决关键路径逻辑过长的问题,通过在combinational logic中移动register,利用宽松路径的余量来补偿关键路径进行优化;
Perform automatic asynchronous signal pipeline:该选项是在fitter时自动加入针对异步clear或load信号的流水线级来优化性能,特别是在recovery和removal slack未达到时序要求时可以使能这一选项;
Perform register duplication:自动复制register优化高扇出的问题。
图2
针对设计,通过查看关键路径,如图2所示,发现逻辑级数达到33,这与第一个选项:Perform physical synthesis for combinational logic所能解决的问题比较匹配,使能第一个选项,看一下优化结果:
图3 优化前
如图3所示为优化前的时序波形图,时序未收敛,关键路径上Data Delay过大,达到4.335ns。
图4 优化后
如图4所示为经过优化后原先关键路径的时序波形图,发现该路径已达到收敛,Data Path的时延仅3.464ns,留给建立时间0.126ns的余量。因此选项:Perform physical synthesis for combinational logic确实达到了优化的目的,下面来查看一下软件是如何自动优化的:
图5 优化后
如图5所示优化后的Technology Map图,发现逻辑级数还是很多,查看TimeQuest Timing Analyzer中的统计,logic lever还是有32级,相比于优化前仅少了1级,估计这1级也不是使路径时序收敛的关键,还需继续深入探究。
图6 优化前Data Path
图7 优化后Data Path
如图6、7所示,通过比较优化前和优化后的Data Path,根据上面分析,优化前Data Path总时延为4.335ns,而优化后仅为3.464ns,相差0.841ns,这足够使路径达到时序收敛。仔细比较优化前后的Data Path,发现共有两处差别:
1. 在逻辑中少了1级,原先连接这级逻辑的路径时延发生了变化
(a)优化前
(b)优化后
图8
通过图8中优化前后的对比,优化后少了Div_0|LPM_DIVIDE_component|auto_generat
ed|divider|divider|add_sub_16|op_1~9|这一级,减少了布线延时,时延方面从0.310+0.801+0.440+0.000+0.055=1.606ns减少到0.310+0.239+0.733=1.282ns,
(a)优化前
(b)优化后
图9
2. 如图9所示为第二处差别,此处具有相同的路径,节点的扇出也相同,就是时延发生了变化,节点Div_0|LPM_DIVIDE_component|auto_generated|divider|divider|add_sub
_16|op_1~73|sumout到节点Div_0|LPM_DIVIDE_component|auto_generated|divider|divi
der|DFFStage[142]|sload的时延从0.483ns减少到了0.114ns,这就很奇怪啊,查看Technology Map肯定看不出什么区别了,因为它们路径两端的节点是相同的,那只能通过Chip Planner查看底层是如何布线的了。
(a)优化前
(b)优化后
图10
通过对比图10中(a)和(b),发现优化前这一小段路径横跨了好几个LAB,导致时延比较大,而优化后该段路径在一个LAB就内部消化了,软件自动对关键路径的布线进行了优化。
图11
经过以上优化和分析,原先的关键路径时序收敛了,那整个设计的时序是否收敛了呢?那就重新check一下timing吧,很遗憾,还是不满足,如图11所示,不过庆幸的是setup slack提高了些,到-0.240ns了,不然这优化算是白费了。
总结:此次优化是通过软件自动进行的,通过查找问题使能了对应选项,这种针对性的优化效果还是很明显的。在我尝试其它选项进行优化后发现几乎没有什么效果,甚至使问题更加恶化了,因此采用软件自动优化时不能太盲目,认为将所有优化选项都使能就是最佳的,必须根据设计本身的问题采取针对性的优化方案。
革命尚未结束,咱还需继续努力!
//*********************************************************************************************************************************
//*********************************************************************************************************************************
在使用两种方法(《时序优化一例(一)》,《时序优化一例(二)》)对设计进行时序优化后,设计的建立时间余量从-1.070优化到-0.240,但是时序还未达到收敛,继而尝试了许多其它方法:
(一)局部优化
在《时序优化一例(二)》中的物理综合优化是全局的,可能对关键路径的优化还不够彻底。翻阅了一些资料,发现可以针对一个模块或者节点进行局部优化,因此可以直接对关键路径进行直接优化。方法是在QuartusII软件中,打开Assignments->Assignment Editor,如图1所示,可以在其中加入需要优化的节点或者模块,优化选项与全局优化选项类似,如图2所示,在Assignment Name下拉菜单中可选择不同的优化策略。
图1
图2
但是遗憾的是采用局部优化后,时序还是没有收敛!
(二)LogicLock
使用Logiclock可以创建一个floorplan,用于将设计中的部分模块逻辑的布局布线限制在模块区域中。但是其主要用于增量编译中,与design partition配合使用,将一个设计分区的布局布线限定在一个Logiclock区域中,如果分区的布局布线已达到要求,可以设置保留该分区布局的布局布线信息,那下次编译时可以跳过对该设计的布局布线过程,减少了编译时间。
但是使用Logiclock对时序性能并没有什么好处,反而可能会起到反效果。因为fitter并不对Logiclock区域之间的布线进行优化,而如果Logiclock区域划分不合理,关键路径正好处于跨区域中,那在之前对关键路径所作的时序优化算是白费了。
在我的设计中,现阶段关键路径处于除法器IP内部,也没别的什么办法去优化这个IP了,可能是其它模块的布局布线对除法器模块产生了影响,那就“瞎猫碰死耗子”一把,试一试,万一有小惊喜呢!使用Logiclock将除法器布局布线与其它模块的布局布线隔离,将此除法器模块单独建立分区和创建Logiclock区域。分区如图3所示,可以看到Div模块因为分区被单独分离出来;Logiclock如图4所示,div模块的逻辑被限定在单独的一个Logiclock区域中布局布线。
图3
图4
然后来check一下timing,值得欣慰的是,时序好了一些,如图5所示,建立时间余量减小到-0.224ns了,关键路径还在除法器内部。通过分区逻辑隔离、创建Logiclock区域进行布局布线隔离还是起到了意想不到的效果,尽管这效果很小。
图5