前言:
延时处理在工程中应用很多,很多时候,不知道如何用verilog来描述,这里来探讨一下,或许能对设计有所帮助。
FPGA设计中的延时电路的产生:在日常的电路设计中,有时候我们需要对信号进行延时处理来适应对外接口的时序关系,最经常也是最典型的情况是不同模块间有时会有时钟差异,以及在做时序控制时,有时候需要等待或多或少个个时钟周期。
那么遇到这种情况该如何处理呢?首先在FPGA中要产生延时,信号必须经过一定的物理资源。在硬件描述语言中有关键词Wait for xx ns,需要说明的是该语法是仅仅用于仿真而不能用于综合的。
可综合的延时方法有:
使信号经过逻辑门得到延时(如非门);
使用器件提供的延时单元(如Altera公司的LCELL);注意:当使用多级非门的时候综合器往往会将其优化掉,因为综合器会认为一个信号非两次还是它。虽然不同的厂家的芯片宏单元的结构不同,但概括而言都是由一些组合逻辑外加一或二个触发器而构成。在实际应用中,当一个模块内的组合逻辑被使用了那么与其对应的触发器也就不能用了;同样如果触发器单元被用了那么组合逻辑单元也就废了。这就是有时候(特别是使用CPLD)虽然设计使用的资源并不多但布局布线器却报告资源不够使用的原因。
当需要对某一信号作一段延时时,入门的新手(比如我这一类的)往往在此信号后串接一些非门或其它门电路,此方法在分离电路中是可行的。但在FPGA中,开发软件在综合设计时会将这些门当作冗余逻辑去掉,达不到延时的效果。用ALTERA公司的Quartus
II开发FPGA时,可以通过插入一些LCELL原语来产生一定的延时,但这样形成的延时在FPGA芯片中并不稳定,会随温度等外部环境的改变而改变,因此并不提倡这样做。在此,可以用高频时钟来驱动一移位寄存器,待延时信号作数据输入,按所需延时正确设置移位寄存器的级数,移位寄存器的输出即为延时后的信号。此方法产生的延时信号与原信号比有误差,误差大小由高频时钟的周期来决定。对于数据信号的延时,在输出端用数据时钟对延时后信号重新采样,就可以消除误差。
这里说的误差,值得探讨一下。暂时先不做深入了解。下面一一实现。
实现方法
1、1利用DSP Builder 来实现一个64时钟的延时
如图所示,是一个延时64个时钟周期的模型。经过仿真结果是正确的。
首先来看一下消耗资源,memory资源消耗了496个。
接着看RTL图,RTL即register transfer level,寄存器传输级。在下图中可以看出使用的多是D触发器,以及一些组合电路,如数据选择权、串并转换、并串转换。
1.2
利用移位寄存器可以实现64时钟延时
利用Quartus自带的LPM(Library of parameter model)的shiftregsiter,也可以实现一个精准的延时。这里面有两个参数选项,一个是taps,另一个是distance between taps,分别设置的是8,这样总的延时就是64。经过仿真的结果也显示延时为64个时钟。
这个IP核还有很多东西需要深入了解。Tap之间的间距有什么作用,可以从下图解释,并与仿真对比,可以验证。
TAP即分成几段数据,Distance表示每段数据里面有几个数据。Taps的高八位代表的就是shiftout[7..0]的数据。这样就一目了然了。
RTL示意图
总结:比较这两种方法,使用移位寄存器消耗的资源更少一些,而且不需要通过第三方工具那么麻烦。另外从RTL上看,使用移位寄存器更容易懂一些,使用DSP
Builder不那么容易理解。可以看出LPM中的器件都是经过优化得到的结果,能使用LPM的器件,尽量使用,会使工程设计资源最优化以及warning更少。
但是有一点很重要,当我们需要实现任意时钟的延时是,移位寄存器不一定能够满足,这时候就要用DSP
Builder来实现了。
需要做的一个工作就是如何用硬件语言来描述延时,在硬件上直接实现这一功能。也很快想到了办法。这样实现简单的延时就没必要大动干戈要东调西调了。
1.3、Verilog实现---实现4个时钟周期的延时
通过添加几个寄存器,暂时存储数据就可以实现了。这里要用非阻塞赋值才能实现。这里给出一个通用的延时模块,以后就可以直接用了。
module
shiftreg4(clk,reset_n,shiftin,shiftout);
input
clk;
input
reset_n;
input [7:0] shiftin;
output
[7:0] shiftout;
reg
[7:0] state_0,state_1,state_2,state_3;
reg
[7:0] shiftout;
always@(posedge
clk)
begin
if(reset_n)
begin
shiftout<=0;
state_0<=0;
state_1<=0;
state_2<=0;
state_3<=0;
end
else
begin //实现延时,使用四个触发器存储数据。
state_0<=shiftin;
state_1<=state_0;
state_2<=state_1;
state_3<=state_2;
shiftout=state_3;
end
end
endmodule
经过测试可以使用:
从上面可以看出,verilog对于小的延时是比较方便的,而对于大的延时则需要很多语句,倒不如dsp builder来得方便。另外verilog的描述RTL电路显得比较简单,很容易看明白。
Attachment:
网上资源,仅仅做参考,还是自己总结的要紧。
FPGA实现信号延时的方法汇总:
1、门延时数量级的延时(几个ns),可用逻辑门来完成,但告诉综合器不要将其优化掉(不精确,误差大,常常不被推荐)。比如用两个非门(用constraint
来告诉synthesizer 不要综合掉这些逻辑)。
2、使用delay cell,lcell。
3、采用更快的时钟,通过计数器来实现,对于比较小的延时,用两个DFF 级联就可以。
4、用fifo 或ram 实现。
5、通过移位寄存器实现,延迟的时间和移位寄存器的位数有关。
6、使用负时钟驱动DFF来获得半个时钟周期的延时(negedge clock)。
7、使用合适的buffer甚至用几个buffer的串联。
8、在综合时将忽略所有的延时语句。
网友总结
观点1
异步电路产生延时的一般方法是插入一个Buffer、两级非门等,这种延时调整手段是不适用于同步时序设计思想的。首先要明确一点HDL语言中的延时控制语法,例如:
#5 a<=4'b0101;其中的延时5个时间单位,是行为级代码描述,常用于仿真测试激励,但是在电路综合是会被忽略,并不能启动延时作用。同步时序电路的延时一般是通过时序控制完成的。换句话说,同步时序电路的延时被当作一个电路逻辑来设计。对于比较大的和特殊定时要求的延时,一般用高速时钟产生一个计数器,根据计数器的计数,控制延时;对于比较小的延时,可以用D触发器打一下,这种做法不仅仅使信号延时了一个时钟周期,而且完成了信号与时钟的初次同步,在输入信号采样和增加时序约束余量中使用。
点评:这是最常用的方法,但是当延时过多的话,用verilog来写显得很冗长,建议用dsp builder模块
观点2
altera 的一个lcell 的延时并不是固定的,而是要看你将lcell 的位置放在那里,两个lcell 的距离越远,延时就越大,不同的类型芯片,不同的级别,不同的温度都是不一样的,这些是要考虑到的。两个lcell 的延时可以从1 个多的ns 都10 多个ns 都可以做到的,要是对于环境条件要求不是很严格的时候,可以考虑这种方法,否则就要考虑其他的方案,或者做一些折中了。
点评:这是下下策,对于要求不严格的可以用这个,不建议使用。
网络资源对本文有贡献,在此一并谢过。
用户377235 2013-1-3 16:11