SystemVerilog 'if' 语句里面 always_comb 'not purely combinational logic' 错误

SystemVerilog 'if' statement inside always_comb 'not purely combinational logic' error

我很困惑!有点沮丧。我花了很多时间在 Modelsim 中处理一些 SystemVerilog。我已经到了可以在我的硬件上测试它的某个阶段,但是在 Quartus 中编译是不成功的。我确实知道这可能会发生,但在这种情况下,我的错误似乎没有意义。

下面的代码在 always_comb 块中。编译时出现以下错误:

Error (10166): SystemVerilog RTL Coding error at fifo_interface.sv(80): always_comb construct does not infer purely combinational logic.

我真的不明白这个。这是代码,它只是一个多路复用器。

always_comb
    if(fifo_select == 0)
    begin
        fifo0_data_in = data_in;
        fifo0_in_clk = in_clk;
        fifo0_in_dn = in_dn;
        in_rdy = fifo0_in_rdy;

        fifo1_in_clk = 0;   //Prevent 'in_clk' entering fifo1
    end

    else
    begin
        if(fifo_select == 1)
        begin
            fifo1_data_in = data_in;
            fifo1_in_dn = in_dn;
            fifo1_in_clk = in_clk;
            in_rdy = fifo1_in_rdy;

            fifo0_in_clk = 0;   //Prevent 'in_clk' entering fifo0
        end 
    end
end

当我将块更改为类型时 'always' Modelsim 会出现异常行为。它会破坏代码或与退出代码 211 一起崩溃。将类型改回 'always_comb' 不能解决问题,因此我必须重新启动 modelsim 才能成功模拟 HDL。

我想知道错误的来源是什么?

感谢您的帮助。

您没有在多路复用器的所有分支中分配所有输出。例如,如果 fifo_select == 0,则会分配 fifo0_data_in。但是如果 fifo_select == 1 那么它就没有价值。这意味着如果 fifo_select 发生变化,fifo0_data_in 需要记住它的值。因此,综合将推断出该输出的锁存器。

这是我认为你想要的:

always_comb
    if(fifo_select == 0)
    begin
        fifo0_data_in = data_in;
        fifo1_data_in = '0;
        fifo0_in_clk = in_clk;
        fifo1_in_clk = '0;
        fifo0_in_dn = in_dn;
        fifo1_in_dn = '0;
        in_rdy = fifo0_in_rdy;
    end

    else
    begin
        fifo1_data_in = data_in;
        fifo0_data_in = '0;
        fifo1_in_clk = in_clk;
        fifo0_in_clk = '0;
        fifo1_in_dn = in_dn;
        fifo0_in_dn = '0;
        in_rdy = fifo1_in_rdy;
    end
end

并且,由于您似乎将时钟门控到未使用的 FIFO,您可以进一步简化,如下所示:

assign fifo0_data_in = data_in;
assign fifo1_data_in = data_in;
assign fifo0_in_dn = in_dn;
assign fifo1_in_dn = in_dn;

always_comb
    if(fifo_select == 0)
    begin
        fifo0_in_clk = in_clk;
        fifo1_in_clk = '0;
        in_rdy = fifo0_in_rdy;
    end

    else
    begin
        fifo0_in_clk = '0;
        fifo1_in_clk = in_clk;
        in_rdy = fifo1_in_rdy;
    end
end

nguthrie 的回答是正确的,但是你被一些非常重要的理解绊倒了,所以我想写一个更明确的版本。

如果我们采用您的代码并对其进行简化,那么我们只查看对 fifo0_data_in 的分配,这样讨论起来会更容易。

always_comb
begin
    if(fifo_select == 0)
    begin
        fifo0_data_in = data_in;
    end
end

所以,当 fifo_select 为零时,我们分配给 fifo0_data_in,当 fifo_select 不为零时,我们......错误......什么都不做,这意味着它需要保持以前的值。

我们描述的是 "latch",锁存器不是组合的(它们保留信息)因此它们不能存在于 always_comb 中。他们必须在 always_latchalways 块中。

使用 always 块时,意外闩锁是一个非常常见的错误,通常您永远不需要它们。 SystemVerilog 添加了 always_comb,这样当设计人员忘记在代码路径中定义信号值时(在您的例子中,当 fifo_select 不为零时),这样的错误会告诉设计人员。

解决这个问题的另一种方法,也是一种值得熟悉的风格,是:

always_comb
begin
    fifo0_data_in = '0;  // Default value

    if(fifo_select == 0)
    begin
        fifo0_data_in = data_in;
    end
end

这里我们在开始时分配了一个默认值,因此无论 if 条件是否为真,信号都被分配了一些东西。这种风格通常更容易,因为有很多控制信号的复杂条件。