Verilog 添加意外地导致 x
Verilog addition unexpectedly results in x
此可执行文件的输出为 x,直到您从 c 赋值中删除 d。输出为 x x x x。当 d 从分配中删除时,输出如预期的那样“2 3 4 5”。
module test();
logic [1:0] a, b, d;
logic [2:0] c;
assign c = a+b+d;
initial begin
d = 0;
a = 1;
b = 1;
$display(c);
a = 2;
b = 1;
$display(c);
a = 2;
b = 2;
$display(c);
a = 2;
b = 3;
d = 3;
$display(c);
end
endmodule
你的问题在于理解verilog仿真。它是一个事件驱动的流程。
在您的情况下,当 assign 语句的任何输入更改时,就会发生对 'c' 的赋值。
但是只有当您的初始块中的非定时块执行完成时,才会检测到更改。这个块以最后一条语句结束。
因此,您所有的 $display(c) 都将显示 'c' 的值,因为它在初始块开始执行之前就已存在。为了看到更新,您需要让代码等待更改有机会传播。一个简单的例子如下:
initial begin
d = 0;
a = 1;
b = 1;
#1 $display(c);
a = 2;
b = 1;
#1 $display(c);
a = 2;
b = 2;
#1 $display(c);
a = 2;
b = 3;
d = 3;
#1 $display(c);
end
在每个 $display 之前添加 #1 将使更改传播并显示预期结果。
像您这样的代码在解释时存在灰色地带。请注意,初始块具有 a、b 和 d 作为输出。在没有时序控制结构的顺序代码中,它只是重新分配这些输出的值。对于模拟语义,只有最后分配的值才重要并且应该触发事件。但是,看起来某些模拟器可能会以不同的方式解释它并在值更改时触发事件。在这种情况下,这取决于模拟器的实现。例如,正如我所注意到的,VCS 确实会为每次更改触发事件,但仅限于某些情况。 NC 不会触发这些事件。
我想您可以将此类代码的模拟行为解释为 undefined
。要使其具有确定性,请使用正确的时间控制,如上例所示。
两个输出都有效,你有一个竞争条件。
一个连续的assign
语句是一个并发过程,它等待RHS上的信号发生变化,然后计算表达式并进行赋值。
initial
块是另一个并发进程。当您按程序对每个信号进行分配时,调度程序可以自由跳转到另一个进程并执行它,......或者它可以继续执行语句直到遇到阻塞延迟,或者它终止。
事实上,许多工具 内联 连续赋值作为一种优化,仅在引用 lhs 时才执行它们。当您从 rhs 中删除 d 时,这可能就是这里发生的情况。
此可执行文件的输出为 x,直到您从 c 赋值中删除 d。输出为 x x x x。当 d 从分配中删除时,输出如预期的那样“2 3 4 5”。
module test();
logic [1:0] a, b, d;
logic [2:0] c;
assign c = a+b+d;
initial begin
d = 0;
a = 1;
b = 1;
$display(c);
a = 2;
b = 1;
$display(c);
a = 2;
b = 2;
$display(c);
a = 2;
b = 3;
d = 3;
$display(c);
end
endmodule
你的问题在于理解verilog仿真。它是一个事件驱动的流程。
在您的情况下,当 assign 语句的任何输入更改时,就会发生对 'c' 的赋值。 但是只有当您的初始块中的非定时块执行完成时,才会检测到更改。这个块以最后一条语句结束。
因此,您所有的 $display(c) 都将显示 'c' 的值,因为它在初始块开始执行之前就已存在。为了看到更新,您需要让代码等待更改有机会传播。一个简单的例子如下:
initial begin
d = 0;
a = 1;
b = 1;
#1 $display(c);
a = 2;
b = 1;
#1 $display(c);
a = 2;
b = 2;
#1 $display(c);
a = 2;
b = 3;
d = 3;
#1 $display(c);
end
在每个 $display 之前添加 #1 将使更改传播并显示预期结果。
像您这样的代码在解释时存在灰色地带。请注意,初始块具有 a、b 和 d 作为输出。在没有时序控制结构的顺序代码中,它只是重新分配这些输出的值。对于模拟语义,只有最后分配的值才重要并且应该触发事件。但是,看起来某些模拟器可能会以不同的方式解释它并在值更改时触发事件。在这种情况下,这取决于模拟器的实现。例如,正如我所注意到的,VCS 确实会为每次更改触发事件,但仅限于某些情况。 NC 不会触发这些事件。
我想您可以将此类代码的模拟行为解释为 undefined
。要使其具有确定性,请使用正确的时间控制,如上例所示。
两个输出都有效,你有一个竞争条件。
一个连续的assign
语句是一个并发过程,它等待RHS上的信号发生变化,然后计算表达式并进行赋值。
initial
块是另一个并发进程。当您按程序对每个信号进行分配时,调度程序可以自由跳转到另一个进程并执行它,......或者它可以继续执行语句直到遇到阻塞延迟,或者它终止。
事实上,许多工具 内联 连续赋值作为一种优化,仅在引用 lhs 时才执行它们。当您从 rhs 中删除 d 时,这可能就是这里发生的情况。