学习高手的FPGA编程程序,发现他写的程序怎么这么冗余呢?怀着疑问,直到第二次阅读另一高手的FPGA程序,才开始怀疑是自己错了,原来使用时钟使能而不直接使用分频时钟是原因的。查阅相关资料整理了一下,分享给大家吧。——高手应该是这样做时钟信号的。
禁止用计数器分频后的信号做其它模块的时钟,而要用改成时钟使能的方式。否则这种时钟满天飞的方式对设计的可靠性极为不利,也大大增加了静态时序分析的复杂性。
时钟使能电路是同步设计的重要基本电路,在很多设计中,虽然内部不同模块的处理速度不同,但是由于这些时钟是同源的,可以将它们转化为单一的时钟电路处理。在FPGA的设计中,分频时钟和源时钟的skew不容易控制,难以保证分频时钟和源时钟同相。故此推荐采用使用时钟使能的方法。
不要这样做:
always (posedge clk1x or negedge rst_n)
begin
...
end
而要这样做:
always (posedge clk or negedge rst_n)
begin
...
else if (clk1x_en == 1'b1 ) %使用使能的方式。
...
End
时钟如图所示,clk1x是CLK的四分频后产生的时钟,clk1x_en是与clk1x同频的时钟使能信号。
采用时钟使能的方式,还必须保证程序实现的功能与源目标一致。即需要程序是在clk1x上升沿使才执行的模块里的内容。如果程序中使用clk1x作为时钟使能,那么程序模块将进行两次运算与目标背离。如图3所示,当采用clk1x_en作为使能信号时,可以达到与图2相同的逻辑,但这却避免了分频时钟(门控时钟)的不稳定性,有效避免了门控时钟产生的毛刺。
这样的时钟处理方法在FPGA中出现是非常必要的,之前看见别人的程序这样使用时钟很不解,为何要把时钟复杂话呢?直接使用图2的方式驱动一个模块不是简单、容易吗?为何非得采用时钟使能的方式,还得保证其在上升沿时模块才执行,这样不是多事一举么?最近又看一个高手的程序,也是这样使用时钟使能,才发现自己的见解可能错误了,这样处理了的确很有必要。
时钟的产生:两次阅读高手的程序,两种处理方法。第一种处理方法是在分频模式下进行的,因为分频后的时钟占空比是50%,在用此分频信号作时钟使能驱动时,通过逻辑判段信号的前后状态,判断出是否时钟使能信号为上升沿,然后在逻辑上升沿下运行程序模块。当时看见这样的处理,完全就是认为简单的问题复杂话,直接使用分频后的时钟驱动模块不就可以直接在上升沿时处理程序嘛。
第二种处理方法,就是用计数器产生分频时钟时,仅在某一确定的数值对时钟使能置位,可以使时钟使能的高电平仅保持一个CLK周期,这样就能保证程序运行在时钟使能上升沿上了。再看这样时钟使能使能时驱动时,不知道有此设计思想,则在直接阅读程序模块时,造成了些困惑。
程序采用的是基于DDS的原理产生分频信号,由于DDS产生的信号也是占空比为50%的信号。所以程序中使用了多个寄存器来缓存上一时钟的状态,然后对比此刻的状态,判断出上升沿。当时疑惑的是为何不直接输出寄存器状态,缓存有必要吗?
4分频程序所示:
always @ (posedge clk,negedge rst_n)
begin
if(!rst_n)
clk1x_en <= 1'b0; cnt=2'b00;
else
begin
cnt <= cnt +1'b1;
if(cnt ==2'b01)
clk1x_en <= 1'b1;
else
clk1x_en <= 1'b0;
end
end