【发布时间】:2019-03-28 09:04:15
【问题描述】:
我知道 always 块将在其敏感度列表中的任何元素发生更改时触发但是,我的问题是,如果在 always 块中的语句仍在执行时发生敏感度列表更改会发生什么(由于先前的触发器)。 always 块是在并行线程中再次开始执行还是触发阻塞,直到执行首先完成?
【问题讨论】:
标签: verilog system-verilog execution hdl
我知道 always 块将在其敏感度列表中的任何元素发生更改时触发但是,我的问题是,如果在 always 块中的语句仍在执行时发生敏感度列表更改会发生什么(由于先前的触发器)。 always 块是在并行线程中再次开始执行还是触发阻塞,直到执行首先完成?
【问题讨论】:
标签: verilog system-verilog execution hdl
很多人没有意识到@是一个语句修饰符,而不是自己构造的。它说延迟随后的声明,直到有事件发生。 @(A or B) 表示等到 A 或 B 的值发生变化(不要与 A|B 结果的变化混淆)。 @* 表示查看后面的语句,并构建一个隐含的信号敏感度列表以等待更改。
always @(A or B) C = A + B;
always begin
@(A or B) C = A + B;
end
always begin
@* C = A + B;
end
always_comb
begin
C = A + B;
end
这 4 个 always 块具有相同的行为,除了最后一个 always_comb 也在时间 0 触发,而不管 A 或 B 上的任何更改。
如果您将always 后面的代码视为执行语句的过程序列,则可能更容易将@ 构造视为该过程序列的一部分,并且更改必须在您执行时发生执行构造。只需添加另一个延迟就会显示这个概念(不可综合)
always @(A or B) begin
#10 C = A + B;
end
这表示“等待 A 或 B 的更改,然后再等待 10 个时间单位,然后使用 A + B 的当前值对 C 进行分配”。如果 A 或 B 在 10 个时间单位等待期间发生更改,则该更改将丢失。在这 10 个时间单位之后,您必须等待 A 或 B 的另一个变化。
【讨论】:
一旦触发了always块,就会从头到尾执行。 Verilog 是一个单线程模拟引擎,因此一次只能执行一个块。执行 always 块时不会发生任何其他事情,除非它包含延迟语句或等待事件。在后一种情况下,它只会产生 允许其他块被执行,然后继续。
如果一个 always 模块在执行结束时改变了它的输入,那么下一个模拟行为取决于模块的类型:
使用 v2k/v95 总是阻塞,如果您不小心,您最终可能会出现零延迟循环。换句话说,模拟可能会挂起。
使用 SystemVerilog 块,您可以获得一个有趣的 read-before-write 条件(当变量在写入同一块之前被读取)。这可能会造成模拟/综合失配。
【讨论】:
always_comb 和 always @* 之间的区别,它提到的关于多个 always 的唯一区别是允许在单独的块。
always 块,这不是 OP 所要求的。
每个 always 块都是一个线程(除非它包含 fork-join)。因此,如果它正在执行,如果敏感度列表中的某些内容发生更改,它将不会重新触发。 (如果它确实包含fork-join,那么一旦触发它就会分裂成多个线程,但不会再次触发)。
【讨论】: