Verilog 时序控制

17 Mar 2025 | 6 分钟阅读

在仿真中,需要使用时序控制语句来推进时间。程序语句的执行时间应使用时序控制来指定。

Verilog 中,有以下类型的时序控制:

  • 延迟控制
  • 边沿敏感事件控制
  • 电平敏感事件控制
  • 命名事件

延迟控制是一种在仿真器遇到语句和执行语句之间添加延迟的方法。

事件表达式允许语句延迟到发生某些仿真事件为止,该事件可以是网络或变量上的值更改,或者是在另一个过程中显式命名的事件触发。

可以通过以下方法之一推进仿真时间。网络和门已经建模为具有内部延迟,也可以推进仿真时间。

延迟控制

延迟控制是通过指定遇到语句时执行的等待时间来实现的。符号 # 用于指定延迟。

我们可以通过三种方式指定基于延迟的时序控制

  1. 常规延迟控制:它将被指定为程序赋值左侧的非零数字。
  2. 内部赋值延迟控制:在这种情况下,延迟将在赋值运算符的右侧指定。右侧表达式将在当前时间计算,并且赋值仅在延迟之后发生。
  3. 零延迟控制:零延迟控制语句将零延迟值指定给程序赋值的左侧。此方法用于确保语句在仿真时间结束时执行。这意味着,零延迟控制语句在执行该仿真时间中的所有其他语句之后执行。

事件控制

事件控制语句或语句块的执行。变量和网络上的值更改可以用作同步事件,以触发其他程序语句的执行,这是一个隐式事件。

事件基于变化的方向,如向 0 变化,使其成为negedge,而向 1 变化使其成为posedge

  • negedge 是从 1 到 X、Z 或 0 的转换,以及从 X 或 Z 到 0 的转换
  • posedge 是从 0 到 X、Z 或 1 的转换,以及从 X 或 Z 到 1 的转换

从相同状态到相同状态的转换不应被视为边沿。边沿事件只能在向量信号或变量的 LSB 上检测到。

如果表达式的计算结果相同,则不能将其视为事件。存在不同类型的基于事件的控制。

1. 常规事件控制:语句的执行将在信号更改或信号的正向或负向转换时发生。例如,时钟的 posedge 和复位的 negedge 等。

2. 命名事件控制:事件关键字可用于声明可以显式触发的命名事件。

事件不能保存任何数据,没有时间长度,并且可以在任何特定时间发生。

命名事件通过在命名事件句柄之前加上 -> 运算符来触发。可以通过 @ 运算符等待命名事件。

命名事件用于同步两个或多个并发运行的进程。事件可以声明为数组。

例如,always 块和第二个 initial 块通过 a_event 同步。事件可以声明为数组,例如 b_event 的情况,它是大小为 5 的数组,索引 3 用于触发和等待目的。

3. 事件 OR 控制:信号或事件的转换可以触发语句的执行,如下所示。

or 运算符可以等待直到表达式中列出的任何一个事件被触发。逗号 (,) 可以代替 or 运算符使用。

边沿敏感事件控制

在 Verilog 中,@ 字符指定一个边沿敏感事件控制,该控制会阻塞,直到事件的标识符之一的值发生转换(一个边沿)。

边沿事件被排队,然后由 @(...) 守护程序处理,而不是 @(?) 成为等待边沿事件的守护程序,阻塞直到发生边沿事件。

对 @(...) 守护程序来说,唯一重要的边沿事件是那些在它等待时发生的事件。在到达守护程序之前发生的边沿事件与守护程序无关。

电平敏感事件控制

程序语句的执行可以延迟到条件变为真为止,这可以通过 wait 关键字完成。它是一种电平敏感控制。

wait 语句评估一个条件,如果为假,则程序语句保持阻塞,直到条件变为真。

完成执行后,它会产生以下输出

隐式事件表达式列表

事件表达式列表或敏感列表通常是 RTL 中许多功能错误的一个常见原因,因为用户可能忘记在程序块中引入新信号后更新敏感列表。

现在执行上面的代码,我们将得到以下输出

ncsim> run
T=0 a=0 b=0 c=0 d=0 x=0 y=0
T=10 a=0 b=1 c=0 d=0 x=1 y=0
T=20 a=0 b=0 c=0 d=1 x=0 y=1
T=30 a=1 b=0 c=0 d=1 x=1 y=1
ncsim: *W,RNQUIE: Simulation is complete.

如果用户决定添加新信号 e 并捕获反转到 z 中,则必须特别注意将 e 也添加到敏感列表中。

输出如下所示

ncsim> run
T=0 a=0 b=0 c=0 d=0 e=0 x=0 y=0 z=1
T=10 a=0 b=0 c=1 d=0 e=0 x=0 y=1 z=1
T=20 a=0 b=0 c=0 d=0 e=1 x=0 y=0 z=0
T=30 a=0 b=1 c=0 d=0 e=1 x=1 y=0 z=0
ncsim: *W,RNQUIE: Simulation is complete.

Verilog 允许用 * 替换敏感列表,这是一个方便的简写,通过添加语句读取的所有网络和变量来消除这些问题,如下面的代码所示。

输出如下所示

ncsim> run
T=0 a=0 b=0 c=0 d=0 e=0 x=0 y=0 z=1
T=10 a=0 b=0 c=1 d=0 e=0 x=0 y=1 z=1
T=20 a=0 b=0 c=0 d=0 e=1 x=0 y=0 z=0
T=30 a=0 b=1 c=0 d=0 e=1 x=1 y=0 z=0
ncsim: *W,RNQUIE: Simulation is complete.