📜  Verilog始终阻止

📅  最后修改于: 2021-01-11 14:43:53             🧑  作者: Mango

Verilog始终阻止

在Verilog中,always块是过程块之一。 always块中的语句按顺序执行。

Always块始终执行,与初始块不同,初始块在模拟开始时仅执行一次。 Always块应具有敏感列表或与之相关的延迟

敏感列表是告诉always块何时执行代码块的列表。

句法

Verilog始终阻止以下语法

always @ (event)
    [statement]

always @ (event) begin
    [multiple statements]
end

例子

保留字always之后的符号@,表示将在符号@后面括号中的条件下触发该块。

always  @ (x or y or sel)
begin
     m = 0;
  if (sel == 0) begin
     m = x;
   end else begin
     m = y;
   end
end

在上面的示例中,我们描述了一个2:1多路复用器,输入x和y。 sel是选择输入, m是复用输出。

在任何组合逻辑中,只要输入发生变化,输出就会发生变化。如果将此理论应用于始终块,则只要输入或输出变量发生变化,始终块中的代码就需要执行。

注意:它可以驱动reg和integer数据类型,但不能驱动线数据类型。

Verilog中有两种类型的敏感列表,例如:

  • 电平敏感(用于组合电路)。
  • 边沿敏感(用于触发器)。

下面的代码是相同的2:1多路复用器,但是输出m现在是触发器输出。

always  @ (posedge clk )
if (reset == 0) begin
     m <= 0;
end 
     else if (sel == 0) begin
     m <= x;
    end 
 else begin
     m <= y;
end

注意:Always块在某些特定事件上执行。敏感度列表定义事件。

灵敏度表

敏感性列表是一个表达式,它定义了何时执行always块,并在括号()中的@运算符之后指定。该列表可以包含一个或一组信号,其值更改将执行always块。

在下面显示的代码中,每当信号x或y的值更改时,始终执行块中的所有语句。

// execute always block whenever value of "x" or "y" change
always @ (x or y) begin
    [statements]
end

需要敏感性清单

在整个模拟过程中,始终块将连续重复。灵敏度列表带来某种定时感,即,只要灵敏度列表中的任何信号发生变化,便会触发始终块。

如果始终块中没有时序控制语句,则由于零延迟无限循环,模拟将挂起。

例如,始终阻止尝试反转信号clk的值。该语句每隔0次执行一次。因此,由于语句中没有延迟,因此它将永远执行。

// always block 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 and it continues
// in a loop and simulation will hang 
   
   always clk = ~clk;

如果灵敏度列表为空,则应该有其他形式的时间延迟。通过始终构造中的延迟语句可以提高仿真时间。

always #10 clk = ~clk;

现在,每10次单位完成一次时钟反转。这就是为什么真正的Verilog设计代码始终需要敏感度列表的原因。

注意:显式延迟不能合成为逻辑门。

Always Block的使用

Always模块可用于实现组合或顺序元素。诸如触发器之类的顺序元素在提供时钟并复位后会变为活动状态。

类似地,当一个组合块的输入值之一改变时,该组合块将变为活动状态。这些硬件模块都彼此独立地并发工作。两者之间的联系决定了数据流。

常态块是一个连续过程,当敏感度列表中的信号变为活动状态时,将触发该块并执行某些操作。

在以下示例中,始终块中的所有语句在信号clk的每个上升沿执行

// execute always block at the positive edge of signal "clk" 
always @ (posedge clk) begin
    [statements]
end

顺序元素设计

以下代码定义了一个名为tff的模块,该模块接受数据输入,时钟和低电平有效复位。在这里,Always块在clk的上升沿或rstn的下降沿触发。

1.时钟的上升沿

以下事件在时钟的上升沿发生,并在时钟的所有上升沿重复发生。

步骤1:首先,if语句检查低电平有效复位rstn的值。

  • 如果rstn为零,则应将输出q重置为默认值0。
  • 如果rstn为1,则表示不应用复位,并且应遵循默认行为。

步骤2:如果上一步为假,则

  • 检查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

2.复位的负沿

以下事件发生在rstn的负边缘。

步骤1:首先,if语句检查低电平有效复位rstn的值。在信号的下降沿,其值为0。

  • 如果rstn的值为0,则意味着应用了reset,并且应该将输出重置为默认值0。
  • 并且如果rstn的值为1,则不会考虑,因为当前事件是rstn的负沿。

组合元素设计

Always块也可以用于组合块的设计中。

例如,下面的数字电路代表三个不同的逻辑门,它们在信号o处提供特定的输出。

下面显示的代码是具有四个输入端口和一个称为o的单个输出端口的模块。每当敏感度列表中的任何信号的值发生变化时,便会始终触发块。

因为在程序块中使用了输出信号,所以在模块端口列表中将其声明为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为假时,o变为0。