FPGA经验谈系列文章——时序不过怎么办

本文转载自:十年老鸟的CSDN博客

前言
跟FPGA打交道这么多年,多多少少总会碰到一些时序问题。时钟越来越高,资源利用率越来越多,到了一定时候,免不了时序报表会爆红。

总结下来大概有如下原因:

1、 时钟频率过高
2、 资源利用率过大
3、 逻辑级数过大
4、 扇出过大
5、 资源拥塞

等这些情况。

下面大概写一些我之前碰到过的一些场景,以及解决的办法

如果设计验证和测试已经接近尾声,偶尔进行小改可能出现几条时序违例的情况

这个时候就不建议通过修改代码来进行优化了,首先在设计验证和测试几乎完成的情况下,证明你这套逻辑已经经过了层层考验,不会出什么问题。如果这个时候还通过改功能模块来优化时序有可能引入新的不确定因素,还得花很多时间来验证才行。

在这个时候一般的做法是多开几个策略来进行综合或者布局布线。举个简单的例子,因为只是偶尔会出现时序不过的情况,假设概率为0.3。那么如果有3个策略同时编译,则3个都不过的概率就变成0.027了。这样只要哪个策略时序通过了我们就用哪个策略生成的结果即可。

逻辑级数过大引起的某些路径经常性违例
有时候几乎每把编译都是那几个路径爆红,很有可能就是那几条路径组合逻辑级数实在是太多了,有时候组合逻辑的逻辑级数甚至到了十几级,这个时候就最好优化一下了。在组合逻辑中间插入一下触发器来降低整体逻辑级数一般就能解决这个问题。

扇出过大
首先这个最有可能出现的就是复位信号了,因为大部分童鞋都喜欢用
Always @(posedge i_clk or negedge i_rst_n)

这种写法了。甭管什么逻辑,实现啥功能,都先来一个这样的帽子。

这样就引出了一个问题,i_rst_n是整个工程扇出最大的信号了。这个特别是资源用的比较多得时候就会暴雷了,每次时序违例都是一大堆跟i_rst_n有关的。但绝大多数时候我们的功能是不需要i_rst_n复位的。因此在这里还是强烈推荐大家不用在FPGA设计中使用复位,可以参考我之前的博文。在资源用的很多的时候这个问题会更加明显。

那这是复位信号可以删掉,如果是其他功能信号呢。

如果是无法忽略的信号,那要么就做
(1) 逻辑复制,以增加资源来减少扇出。
(2) 或者某些情况下我们了解其信号特性,并不需要下一个时钟周期就做出响应的话,可以使用multicycle约束。这样,触发器之间的时延就可以成倍增加了,大大缓解了其布线压力

资源拥塞
某一块的逻辑功能特别大,组合逻辑也多,但又不太容易优化,只能说我们在设计的时候不要引入太多不必要的一些控制信号,这里有一个控制集的概念:

触发器中的Flip-flops和flip-flop/latches有着相同的控制信号,CLK,SR, CE等等。那么对用户来说最重要的事情就是尝试着减少用户设计中的控制信号的数量。用户需要加强对控制信号的行为的理解:所有Flip-flops和flip-flop/latches共享所有这些控制信号,这些控制信号主要是时钟,置位和复位。如果一个组中的一个flip-flop用了时钟使能信号,那么所有其他的Flip-Flop必须使用相同的时钟使能或者不用时钟使能。如果一个组中的一个flip-flop用了置位或者复位信号,那么所有其他的Flip-Flop必须使用相同的置位或者复位信号。

这也是经常会出现的资源使用过多得时候,编译不过时vivado会提示的一个错误,但实际上FF和LUT的资源利用率又没有这么高,因此在设计的心里就要有这个意识,尽量减少控制集,例如都不用复位,而不是有些用有些又不用之类的。

例如我之前看到一篇文章,里面有一个这样的题目:
1) 以下这些案例能不能把这两个寄存器放在同一个slice里面?
注:所有控制信号都是直接驱动触发器的控制信号。
– 案例 1
• FF1: Clock, CE, Set
• FF2: CLK, CE, Set
– 案例 2
• FF1: CLK, CE, Reset
• FF2: CLK, Reset
– 案例3
• FF1: CLK, CE, Reset
• FF2: CLK, CE, not Reset
– 案例 4
• FF1: CLK, CE, Reset
• FF2: CLK, CE, Reset
案例1:不能。触发器有不同的时钟,所以它们有不同的控制组的。
案例2:不能。FF2具有时钟使能,所以它们有不同的控制组的。
案例3:不能。FF2无法提供翻转逻辑,所以它们有不同的控制组的。
案例4:能。两个触发器具有完全相同的控制信号,所以它们是相同的控制组的成员。可以被放在同一个Slice里面。

vivado版本过低
赶紧把你的vivado升级到最新的,实际上还有一个最大的变量就是,你的时序还跟vivado软件的布局布线的内部算法有很大的关系。每次更新版本有可能在这方面做一些改进,有可能之前版本解决不了的时序问题,到了后面的版本就没有了,这点其实也是经常有的事。

大范围时序违例,时序违例路径成百上千。用了上述的一些方法不管用
碰到这种情况是比较头痛的了,这意味着你的设计有可能无法达到既定要求。当前的时钟和资源利用率已经超出了片子的承受范围。这种情况下无法通过小修小补就能让时序收敛,只能从整个方案设计来看是否有妥协的办法。

(1) 最直接的办法只能是降时钟频率了,头痛医头脚痛医脚嘛,时序不过,说明目前设计时钟频率过高。但大部分情况下是不能这么降系统时钟的,降系统时钟很有可能意味着整体性能的下降,很可能出现无法达成既定指标的情况。

(2) 审视所有功能模块,看看所有模块的数据吞吐量是否有不同的情况。例如我之前弄过FPGA暴力破解算法。A模块是接口模块和路由通路,B模块是解密核心算法。B模块的时钟快慢决定性能的好坏,因此B模块时钟越快越好。但B模块运算时间较长,因此不要A模块这么快的速度传递数据。因此A模块时钟可以用更慢的时钟。

这样比A/B模块都用一个时钟对于时序的压力会减轻。当然这只是一个例子,每个不同的功能都要进行具体的分析,有些是可以优化的,有些的实在没办法就只能从性能上进行取舍了。

总结
时序和资源就是一个矛盾体。当资源利用率不高的时候,可能啥问题都没有。一旦资源利用率上来了,各种问题就暴露了。因此需要在设计的时候就注意上述提到的点,例如扇出、逻辑级数等,再后面就很可能能减少这类时序问题。

因为这类经验还是需要自己去经历,去感悟。只要实际经历过并且去解决了问题才会更深刻的理解。因为我也经历也不一定算多,可能写的也不全面,同时其他大佬可能也有其他更好的办法或者遇到过不同的案例也欢迎指导。

最新文章

最新文章