Verilog 总是阻塞
一个always
块是程序之一 Verilog 中的块。 always 块中的语句是按顺序执行的。
语法
always @ (event)
[statement]
always @ (event) begin
[multiple statements]
end
always
块在某些特定事件中执行。该事件由敏感度列表定义。
什么是敏感列表?
一个敏感性 list 是定义何时执行 always 块的表达式,在 @
之后指定 括号内的运算符 ( )
.此列表可能包含一个或一组信号,其值更改将执行 always 块。
在如下所示的代码中,always
内的所有语句 只要信号 a 或 b 的值发生变化,就会执行块。
// Execute always block whenever value of "a" or "b" change
always @ (a or b) begin
[statements]
end
always 块是做什么用的?
一个 always
块可用于实现组合或顺序元素。当提供时钟并复位时,触发器等时序元件将变为活动状态。类似地,组合块在其输入值之一改变时变为活动状态。这些硬件块都相互独立地同时工作。两者之间的联系决定了数据的流动。为了模拟这种行为,一个 always
块是一个连续的过程,当敏感度列表中的信号变为活动状态时,它会被触发并执行一些操作。
在以下示例中,always 块中的所有语句都会在信号 clk 的每个上升沿执行。
// Execute always block at positive edge of signal "clk"
always @ (posedge clk) begin
[statements]
end
如果没有敏感度列表会怎样?
always
块在整个模拟过程中不断重复。敏感列表带来了一定的时间感,即每当敏感列表中的任何信号发生变化时,都会触发always块。如果always块中没有时序控制语句,仿真会因为零延迟无限循环而挂起!
示例
下面显示的示例是一个 always 块,它尝试反转信号 clk 的值。该语句在每 0 个时间单位后执行。因此,由于语句中没有延迟,它会永远执行。
// always block is started at time 0 units
// But when is it supposed to be repeated ?
// There is no time control, and hence it will stay and
// be repeated at 0 time units only. This continues
// in a loop and simulation will hang !
always clk = ~clk;
即使敏感列表是空的,也应该有其他形式的时间延迟。 always
中的延迟语句可以提前模拟时间 构造如下图。现在,每 10 个时间单位进行一次时钟倒转。
always #10 clk = ~clk;
注意: 显式延迟不能合成到逻辑门中!
因此,真正的 Verilog 设计代码总是需要一个敏感度列表。
顺序元素设计示例
下面显示的代码定义了一个名为 tff 的模块,它接受数据输入、时钟和低电平有效复位。只要在时钟的上升沿发现 d 为 1,输出就会反转。这里,always
块在 clk 的上升沿或 rstn 的下降沿触发。
时钟上升沿会发生什么?
以下事件发生在时钟的上升沿,并在所有时钟上升沿重复。
- 第一个
if
块检查低电平有效复位 rstn 的值 - 如果 rstn 为零,则输出 q 应重置为默认值 0
- 如果 rstn 为 1,则表示未应用重置,应遵循默认行为
- 如果上一步为假:
- 检查d的值,如果是1,则取反q的值
- 如果d为0,则保持q的值
module tff (input d,
clk,
rstn,
output reg q);
always @ (posedge clk or negedge rstn) begin
if (!rstn)
q <= 0;
else
if (d)
q <= ~q;
else
q <= q;
end
endmodule
在复位的下降沿会发生什么?
以下事件发生在 rstn 的下降沿,并在所有此类事件中发生。
- 第一个
if
块检查低电平有效复位 rstn 的值。在信号的下降沿,其值为 0。 - 如果 rstn 的值为 0,则表示应用了复位,输出应复位为默认值 0
- 不考虑rstn值为1的情况,因为当前事件是负边缘 第一个
组合元素设计实例
一个 always
块也可用于组合块的设计。例如,下面的数字电路代表了三个不同逻辑门的组合,它们在信号 o 处提供一定的输出。

下面显示的代码是一个module
具有四个输入端口和一个称为 o 的输出端口。 always
每当敏感度列表中的任何信号值发生变化时,都会触发块。输出信号被声明为类型 reg
在模块端口列表中,因为它在程序块中使用。程序块中使用的所有信号都应声明为类型 reg
.
module combo ( input a,
input b,
input c,
input d,
output reg o);
always @ (a or b or c or d) begin
o <= ~((a & b) | (c^d));
end
endmodule
看到只要 RHS 上的组合表达式为真,信号 o 就变为 1。同样,当 RHS 为 false 时,o 变为 0。
模拟输出单击此处查看带有模拟示例的幻灯片!
Verilog