无法理解 simulation/module 行为

Trouble understanding simulation/module behavior

我实现了一个非常简单的具有预设功能的计数器(下面复制了代码)。

module counter
#(
    parameter mod = 4
) (
    input wire clk,
    input wire rst,
    input wire pst,
    input wire en,
    input wire [mod - 1:0] data,
    output reg [mod - 1:0] out,
    output reg rco
);

    parameter max = (2 ** mod) - 1;

    always @* begin
        if(out == max) begin
            rco = 1;
        end else begin
            rco = 0;
        end
    end

    always @(posedge clk) begin
        if(rst) begin
            out <= 0;
        end else if(pst) begin
            out <= data;
        end else if(en) begin
            out <= out + 1;
        end else begin
            out <= out;
        end
    end

endmodule

我无法理解以下模拟结果。 pst 断言并且 data 在时钟上升沿设置为 7,计数器的 out 设置为 data,正如预期的那样(下面的第一张图片。out是最后一个信号,data 是正上方的信号,再上方是 pst。)。在下一个上升沿,我保持预设断言并将 data 设置为 0。但是,这次 out 没有跟随 data。这种行为的原因是什么?

我的想法

在我将 data 设置为 0 的时钟上升沿,我注意到 out 保持在 7,并没有增加到 8。所以我相信计数器正在预设,但值为 7,而不是 0。如果我及时将 data 转换从 7 向上移动到 0,out 将按预期设置为 0(下图)。我遇到了竞争条件吗?

测试平台

我生成第一张图片的初始测试平台代码复制如下。我将我为获得连贯结果所做的更改显示为评论。

parameter mod = 4;
// ...
reg pst;
reg [mod - 1:0] data;
// ...
@(posedge clk); // ==> @(negedge clk)
data = 7;
pst = 1;
@(posedge clk); // ==> @(negedge clk)
data 0;
pst = 1;
@(posedge clk); // ==> @(negedge clk)
pst = 0;
@(posedge clk);
// ...

如果我修改我的测试台以仅在时钟下降沿而不是时钟上升沿(无论如何都应该如此)修改我的计数器的输入信号,我就能获得正确的、可预测的行为。我对为什么会出现上述行为的最佳猜测是,在计数器模块被编程为对其输入进行采样的同时更改输入信号会导致未定义的模拟器行为。

你有一个竞争条件测试台。允许 Verilog 调度程序以其选择的任何顺序评估在时间步长中触发的任何 @。 granted @ 之后的所有代码都将执行,直到遇到另一个时间阻塞语句。在您的波形中,来自测试台的 datapst 有时在设计采样之前分配,有时在之后分配。

解决方法很简单,使用非阻塞赋值(<=)。参考

@(posedge clk);
data <= 7;
pst <= 1;
@(posedge clk);
data <= 0;
pst <= 1;
@(posedge clk);
pst <= 0;
@(posedge clk);