《Verilog HDL与数字系统设计简明教程》吴戈 人民邮电出版社 p34~35
1、时延的概念
连续赋值语句中经常出现时延,时延就是给出一个值,程序执行到此处就会暂停下来,等待这个值规定的若干个单位时间(单位时间的大小是默认值或由预处理指令timescale定义),然后再继续执行后面的语句。定义时延的形式是使用符号“#”,如#3就表示在此等待3个单位时间。
时延可以单独作为一句,如“#3;”就是程序中的一条语句。时延也可以内嵌在连续赋值语句中,跟在关键词assign之后。如果在连续赋值语句中没有定义时延,则默认时延值为0,右端表达式的值会立刻赋值给左端线网。如果在连续赋值语句中定义了时延值,例如:
assign #6 Ask = Quiet || Late;
那么右边表达式的计算结果要经过6个单位时间的时延之后才能赋给等号左端的线网目标。如下图中1所示,例如在时刻5,Late的值发生变化,则计算等号右端的表达式,并且在时刻11(从时刻5开始延时6个单位时间)时把结果值赋给Ask。
在整个时延过程中,如果等号右端表达式的值再次发生变化,那么时延结束时应把最新的值赋给等号左侧的线网。例如:
assign #4 Cab = Drm;
如下图2中所示,在时刻5,Drm从0变为1,那么根据连续赋值语句中的时延定义,应该在时刻9把新的值1赋给Cab,但是因为Drm在时刻8又变为0,所以到时刻9,赋给Cab的是Drm的最新值0。同样,因为值变化快于时间间隔,Drm在时刻18的值变化也无法反映在Cab上。
上面例子中的时延值只出现了一个,事实上这只是一个“上升时延”,连续赋值语句中的时延可以指定三类时延值:上升时延、下降时延和关闭时延(值变为x的时延)。这是一种更加精细的时延定义方式,其语法形式如下:
assign # (rise,fall,turn-off) LHS_target=RHS_target;
其中rise是上升时延,fall是下降时延,turn-off是关闭时延。其具体含义可以根据下面的例子看出来:
assign Bus=MemAddr[7:4]; //没有定义时延,则所有时延都是0
assign #4 Ask = Quiet || Late; //只有一个时延值,表示上升时延、下降时延和关闭时延都是4
assign #(4,8) Ask = Quiet; //有两个时延值,表示上升时延是4,下降时延是8,关闭时延是4和8之中的较小值,即4
assign #(4,8,6) Arb=&DataBus; //有3个时延值,表示上升时延是4,下降时延是8,关闭时延是6
2、线网时延
时延可以单独成句,可以放在连续赋值语句中,而且还可以放在线网声明中,例如:
wire #5 Arb; //时延位于线网声明中
对于上例中的线网Arb,用下面的连续赋值语句为其赋值:
assign #2 Arb=Bod⋒
其执行过程如下图中3所示。假定在时刻10,Bod的值发生变化,计算右端表达式。若计算结果与原来的值不同,则应该在2个单位时间的时延后(即时刻12)把新值赋给Arb,但是因为定义了线网时延,实际对Arb的赋值发生在17(10+2+5)。同样,在时刻40,Cap的值变化要等到时刻47时才能赋给Arb。
下图中4所示描述了用连续赋值语句为线网时延时的操作过程:首先进行赋值时延(assign时延),然后进行线网时延,然后把值赋给线网目标。
注意:如果时延在线网声明赋值中出现,那么这个时延不是线网时延,而是赋值时延。例如:
assign #2 A=B-C; //#2是赋值时延
上例是A的线网说明赋值语句,#2是赋值时延,而不是线网时延。
3、仿真时钟单位换算
1Ghz=103MHz=109Hz
T=1/f=10-9s=1ns
1000MHz的clk cycle为1ns,1200MHz的clk cycle为0.832ns。
4、不管是cb块内的延时采样,还是对信号进行延时处理,最后数字后直接带上时间单位,以防平台timescale不一致出现问题。