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' 的值将是 0
或 B
,具体取决于 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
.
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' 的值将是 0
或 B
,具体取决于 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
.