Verilog HDL 对过程语句的发生时间有两种显式时序控制。第一种是延迟(delay)控制,其中表达式指定了从最初遇到语句到语句实际执行之间的持续时间。延迟表达式可以是电路状态的一个动态函数,也可以是一个简单的数字,将语句的执行时间分开。延迟控制是指定激励波形描述的一项重要功能。
第二种时序控制是事件(event)表达式,它允许将语句执行延迟到与此过程同时执行的过程中发生某些模拟事件。模拟事件可以是网络net或变量variable上的值变化(隐式事件),也可以是从其他过程触发的显式命名事件(显式事件)的发生。最常见的事件控制是时钟信号上的正或负边沿。
时序控制可以通过以下三种方法表示:
- delay控制,由 # 符号引入
- event控制,由符号 @ 引入
- wait语句,其操作类似于event控制和 while 循环的组合
下表1描述了过程语句中的时序控制:
delay控制介绍
与没有延迟控制的过程语句相比,延迟控制后的过程语句应执行指定的延迟。如果延迟表达式求值为未知值或高阻抗值,则应解释为零延迟。如果延迟表达式求值为负值,则应解释为与time变量位宽相同的无符号整数。
例 1-下面的示例将任务的执行延迟了10个时间单位:
#10 rega = regb;
例 2-接下来的三个示例提供了使用延迟表达式的延迟过程赋值:
#d rega = regb; // d is defined as a parameter
#((d+e)/2) rega = regb; // delay is average of d and e
#regr regr = regr + 1; // delay is the value in regr
event控制介绍
过程语句的执行可与网络net或变量variable的值变化或已声明事件的发生同步。网络net或变量variable的值变化可用作触发语句执行的事件,这就是所谓的检测隐式事件。事件也可以基于变化的方向,即朝向值 1(posedge)或朝向值 0(negedge)。posedge 和 negedge 事件的行为如表1所示,可描述如下:
- 在从1到x、z或0,以及从x或z到0的转换过程中,应检测到negedge边沿
- 在从0到 x , z , 或1,以及从x或z到1的转换过程中,应检测到posedge边沿
表1:检测negedge和posedge边沿
event表达式的值发生任何变化时,都应检测到隐式事件。边沿事件只能在event表达式的最低有效位上检测到。event表达式中任何操作数的值发生变化而表达式的结果没有变化时,不应作为event事件进行检测。
例如以下示例展示了event边沿控制语句:
@r rega = regb; // controlled by any value change in the reg r
@( posedge clock) rega = regb; // controlled by posedge on clock
forever @( negedge clock) rega = regb; // controlled by negative edge
event “或”操作符介绍
在事件event敏感列表中,任意多个事件通过逻辑 “或”操作后,任何一个事件的发生都会触发后面过程语句的执行。关键字(or)或逗号字符(,)可用作事件逻辑“或”运算符。在同一个事件表达式中,可以组合使用这两种运算符。逗号(,)分隔的敏感列表与或(or)分隔的敏感列表同义。
例如下面两个例子分别显示了两个和三个event事件的逻辑“或”:
@(trig or enable) rega = regb; // controlled by trig or enable
@( posedge clk_a or posedge clk_b or trig) rega = regb;
下面的示例展示了逗号 ( , ) 作为事件逻辑“或”运算符的使用:
always @(a, b, c, d, e)
always @( posedge clk, negedge rstn)
always @(a or b, c, d or e)
隐式event表达式列表
event控制的事件表达式列表是寄存器传输级(RTL)仿真中常见的错误源。用户往往会忘记在事件表达式中添加在时序控制语句中读取的某些网络net或变量variable。隐式事件表达式 @* 是一种方便的速记方法,它可以将时序控制语句(可以是一个语句组)读取的所有网络net或变量variable添加到事件表达式中,从而消除这些问题。
语句中出现的网络net或变量variable标识符都将自动添加到事件表达式中,包括所有出现在赋值右侧、函数和任务调用、case和条件表达式、赋值左侧的索引变量或case项表达式的网络和变量。但以下情况除外:
- 仅出现在wait或event事件表达式中的标识符。
- 仅出现在赋值左侧变量的标识符。
下面举例说明:
例子1:
always @(*) // equivalent to @(a or b or c or d or f)
y = (a & b) | (c & d) | myfunction(f);
例子2:
always @* begin // equivalent to @(a or b or c or d or tmp1 or tmp2)
tmp1 = a & b;
tmp2 = c & d;
y = tmp1 | tmp2;
end
例子3:
always @* begin // equivalent to @(b)
@(i) kid = b; // i is not added to @*
end
例子4:
always @* begin // equivalent to @(a or b or c or d)
x = a ^ b;
@* // equivalent to @(c or d)
x = c ^ d;
end
例子5:
always @* begin // same as @(a or en)
y = 8'hff;
y[a] = !en;
end
例子6:
always @* begin // same as @(state or go or ws)
next = 4'b0;
case (1'b1)
state[IDLE]: if (go) next[READ] = 1'b1;
else next[IDLE] = 1'b1;
state[READ]: next[DLY ] = 1'b1;
state[DLY ]: if (!ws) next[DONE] = 1'b1;
else next[READ] = 1'b1;
state[DONE]: next[IDLE] = 1'b1;
endcase
end
电平敏感型wait事件控制
过程语句的执行也可以延迟,直到某个条件为真。这是使用wait语句实现的,它是事件控制的一种特殊形式。与基本事件控制(由 @ 字符指定)的边沿敏感性不同,wait语句的性质是电平敏感的。
wait语句执行时应评估一个条件;如果该条件为假,则wait语句之后的过程语句应保持阻塞状态,直到该条件变为真时才继续执行。wait语句的形式如表1所示:
表1:wait语法规则
例如下面的示例展示了如何使用 wait 语句完成对电平敏感型事件的控制:
begin
wait (!enable) #10 a = b;
#10 c = d;
end
如果进入过程块时使能值enable为 1,则wait 语句将停止下一条语句(#10 a = b; )的评估,直到使能值变为 0。如果在进入 begin-end 过程块时使能值已经为0,那么赋值 " a = b; " 将在延迟10个时间单位后立刻执行,不会再发生额外的等待。
点赞加关注博主(ID:FPGA小飞)的博文,咱们一起系统学习verilog最终标准IEEE Std 1364-2005吧!