我已经阅读了有关调度语义的章节,并且可以理解标准的内容。正如标准所说,模拟器可以暂停即将到来的活动事件以执行另一个活动事件,因此显示的值是不确定的。
但我很快想到了下面的代码,如果敏感列表中的信号同时变化,这将导致不确定性。
module test;
reg [1 : 0]c, d;
reg a, b;
initial #5 begin
a = 0;
b = 0;
end
always@(*)begin
d = {a ,b};
c = {a, b};
end
endmodule
据我了解,A信号的变化将导致进入always块。不确定是执行下面的b赋值还是执行always块。如果执行always块,则执行第一条语句后d的值为{0x}。这时候控制流可能会执行b的赋值,@不会再次被触发,因为always块没有执行完,导致结果是{0,0}不是我想象的{0,0} ,但是{0x},(虽然仿真给出的结果是{0,0})always block的这种行为应该很常见,就是多个敏感信号同时变化。我认为模拟器的行为应该是确定性的,因为它很常见,但我的分析告诉我,这是由模拟器决定的不确定行为,我的分析是错误的吗?
您的分析在技术上是正确的,但您永远不会看到模拟器有这样的行为。通常,进程创建的任何事件都会进入队列,并且每个进程在检索队列中的下一个事件之前都必须挂起。这种不确定性的目的是通过将模拟器合并为一个来允许模拟器交错进程作为优化。
一个更好的例子是
always @(*) x1 = y1 + z;
always @(*) x2 = y2 + z;
always @(*) begin
z = a * b;
y1 = a + b;
w = b + d;
y2 = w + a;
end
作为一种优化,模拟器可能会将这三个
always
进程合并为一个。
always @(*) begin
z = a * b;
y1 = a + b;
x1 = y1 + z;
w = b + d;
y2 = w + a;
x2 = y2 + z;
end
这大大减少了事件处理量。
顺便说一句,IEEE 1800-2017 SystemVerilog LRM 是当前的。