你想写出可以跑出700M以上的代码吗,直逼FPGA内部PLL的极限。
你想写出时序裕量足够的代码吗,让你的代码不会出现时序违例。
你想在时序违例时能轻松应对吗?让代码轻松越过时序这道门槛。
这篇文章就是一步步向你解释,如何理解代码中的时序,以及如何解决代码中的时序违例问题。
之前的文章中提到过,工程中ISP算法模块轻松跑到了762.5M的频率,整个ISP链路没有优化的情况下跑到400M的时钟频率(xilinx的us+系列)。
这篇文章将逐步解开HDL代码中的时序之谜,并且让你轻松应对FPGA中的时序问题。我将从实际工程的ISP算法模块出发,从设计到时序违例的查找,一步步提高代码的时序性能。
在第一个ISP模块DPC中,我使用了一个在3x3的矩阵中查找中值的模块,也就是大家常用的中值滤波器。是不是很多人都设计过,先不着急觉得是否简单,而是看如何把算法移植和时序的思想灌入到这个模块之中。
首先假设你已经得到了一个3x3的矩阵,简单看看设计思想:
在3x3 窗口中获取9 个数据,对9 这个数据值进行排序,排序步骤如下
A)窗内的每行数据找到最大值、中间值和最小值;
B)把三列的最小值相比较,取其中的最大值;
C)把三列的最大值相比较,取其中的最小值;
D)把三列的中间值相比较,再取一次中间值;
E) 再把B,C,D 中得到的三个值再排序,获取中值。
有了设计思想就有了灵魂,剩下的是如何构建一个有血有肉的躯体了。经过思考不难发现,9个数的中值滤波变成了3次在3个数中找最大值,最小值,中值。
第一次:执行步骤A。
第二次:执行步骤B,C,D .
第三次:执行E 。
第一次三行D1,D2,D3并行,第二次三列Dxmax,Dxmed,Dxmin并行,第三次在剩下的三个数里面找到中值,运算完毕。所以9个数据的中值查找的设计,变成了一个只需要解决三个数据里面找到max,med,min的设计。
是不是觉得这太简单了。别急,听我继续分析:
既然是在三个数据里面排序,那就需要两两比较,于是就是需要比较3次。A 与B ,B与C,A与C。现在假设A
好,此时另一个误区可能就要出现了。因为flag可能为0也可能为1,那么你得到了三个flag,一共有多少种情况呢?可能有人不假思索地回答8种,因为3bit数据,2^3= 8 ,所以就是8 种。其实不是,用概率与统计的知识,三个数据的排序应该是有C31* C21 * C11 = 6 种。真值表如下
A |
B
A |
|
|
0 | 0 | 0 | max=A,min = C |
0 | 0 | 1 | 不存在 |
0 | 1 | 0 | max=A,min = B |
0 | 1 | 1 | max=C,min = B |
1 | 0 | 0 | max=B,min = C |
1 | 0 | 1 | max=B,min = A |
1 | 1 | 0 | 不存在 |
1 | 1 | 1 | max=C,min = A |
算法分析完毕,剩下的就是代码设计了。首先你需要进行三次比较。
针对上述代码,画出对应的数字威廉希尔官方网站 示意图,(mux的三个输入端省略了datx_reg)
我假设FPGA内部按照上图所示的方式进行布局布线,那么最长数据路径应该是dat2_reg→comp_12 → mux3. (或者说是dat2_reg→ comp_23 → mux1)这条路径也就被称之为最长路径或者关键路径。时序分析工具干的事情就是,分析这条最长路径(当然其他路径也分析)上的时序是否满足条件。
单独把这条路径抠出来,它就是这样子的。于是,STA静态时序分析的模型就出来了,计算reg到reg之间的延迟,两个reg之间,经历了一个比较器和一个多路选择器这两个组合逻辑。
如果上述的路径因为走线(linelatency)延迟,或者是因为逻辑延迟(logiclatency)过大导致了时序违例,那么我们就应该在两个组合逻辑之间插入reg。从威廉希尔官方网站 上,应该如下图所示。
那么从代码的角度,应该这样修改,就可以达到上图的效果:
好了,有了这个参考模板,再去看其他的中值滤波代码,你就知道要从哪里去优化了。
为了让大家更好的理解时序,我在网上找了两个用相同的算法思路设计的开源的代码。 看他们的设计方法
三方代码 1
三方代码 2
可以看到数据比较的时候,逻辑明显有冗余,EDA工具不一定能自动优化。
然后我将两个三方的代码,以及我自己的代码放入同一工程中进行编译,故意加大时钟频率,让它们出现时序违例,从而找出关键路径。
三方的两个模块我例化成 median_filter_3x3 ,和 medfilter3by3 ,用vivado2022.1进行编译。得到时序违例报告
再进一步分析关联路径1,得到了如下图所示的路径示意图
可以看到在两个 reg之间有4个逻辑块,然后再去代码中找到相应的位置。然后再追究到代码内部。
可以看到,代码中多次出现重复性的数据比较,这都是数据优化的方向。具体的位置就是 33-37行, 最后vivado推测出第37行,需要经过4级组合逻辑才能将dat3 赋值给 mid_dat 。
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !