Verilog:寄存器的使用:实际更新值的时间?

Verilog: Use of register: When are the values actually updated?

Verilog 中 always-block 中的变量究竟何时更新? 例如。如果 reg C 在 always-block 中多次更改:它的值是否总是更改?或者值只是 "physically written" 到 always-block 末尾的 reg?

使用仅在 always-block 末尾实现的额外中间寄存器会更好吗?会有什么不同吗?

reg C;

always @(*)
C = 0;
C = A;
C = 1;
C = B;
end

其他例子: 如果我有一个带有如下 always 块的模块,输出的多个赋值是否会出现某种故障,输出在获得 B 的值之前迅速变为 0?如果我使用阻塞 (=) 或非阻塞 (<=) 赋值会有什么不同吗?

module example1 (output C, input A, input B);

always @(*)
begin
 C = 1’b0;
 if (A==1)
   C = B ;
end
endmodule

带有中间寄存器的示例,以避免不必要的输出更改。

module example1 (output C, input A, input B);

reg intermediateReg;

always @(*)
begin
 intermediateReg = 1’b0;
 if (A==1)
   intermediateReg = B ;
end
   C <= intermediateReg;
endmodule

如果您想知道标准 Verilog 中的阻塞和非阻塞赋值的作用(就像您在模拟中所做的那样),您可以轻松地进行查找。

如果您谈论的是硬件,您获得的硬件类型将取决于敏感度列表中的内容,而不是您使用的分配类型。分配的类型将影响从您的代码合成的组合逻辑。假设您没有做任何不可综合的事情,您得到的逻辑应该等同于 Verilog 标准指定的内容,但不会是代码的 1:1 直接映射。

所以,不,添加中间体不一定有助于解决硬件故障。会有其他代码和时序规范等来处理这样的事情。

在您提供的示例中,代码的行为与 'c' 代码相同。该变量被重新分配新值,最后一个获胜。在 verilog 中,这适用于阻塞 (=) 或非阻塞 (<=) 赋值,但不适用于它们的混合。

与'c'一样,这取决于编译器优化技术。它可以消除不需要的分配,因此只有最后一个是相关的。

在您的第一个示例中,'C' 的值在块的末尾将是 'B'。第二个例子中 'C' 的值将是 0B,具体取决于 A.

现在,为了解释简单,阻塞和非阻塞分配的混合将导致最后的 'non-blocking' 分配获胜。原因是所有 nba 都在块完成后执行。

always @(*) begin
   C <= A;
   C = B;
end

C 的值在模拟周期结束时将是 A

关于使用中间值的问题,没有区别。您可以根据需要使用它们。模拟编译器或综合将在任何情况下优化您的代码。最后一个例子是绝对正常的,只是它根本没有改变任何东西。它的行为方式与此相同,在我看来更明确、更易读。唯一的问题是您错误地使用了 nba assignments int 组合逻辑(我已修复)。

always @(*)
begin
 if (A==1)
   C = B ;
 else
   C = 1'b0;

我猜你的 post 中还有一个无声的问题,中间值是否会导致 'C' 上的事件,本例中的答案是 . always 块在完成执行之前不会产生任何事件(或者直到遇到延迟或开始等待事件)。因此,只有最后一个值是相关的。

在测试平台代码中你可以看到这样的情况:

always @* begin
   C = A;
   C = B;
   #5 C = D;
end

在上面的例子中C的值会变成B。 always 块的执行将停止 #5 个延迟。在此期间,其他块将看到值 B。在#5 个刻度内,该值将更改为 D.