SystemVerilog' if'在always_comb'内部的陈述并非纯粹的组合逻辑'错误

时间:2015-09-29 18:40:49

标签: if-statement system-verilog

我很困惑!而且有点沮丧。我花了很多时间在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

当我将块更改为键入'始终' Modelsim会表现得很奇怪。它会破坏代码或者会与退出代码211一起崩溃。将类型更改回' always_comb'没有解决问题,所以我必须重新启动modelsim才能成功模拟HDL。

我有兴趣知道错误的来源是什么?

感谢您的帮助。

2 个答案:

答案 0 :(得分:4)

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

这是我认为你想要的:

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

答案 1 :(得分:1)

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不为零时,我们......错误...什么都不做,这意味着它需要保持它以前的价值。

我们所描述的是“锁存器”,并且锁存器不是组合的(它们保留信息),因此它们不能存在于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条件是否为真,都会为信号分配一些内容。这种风格通常更容易,因为有很多复杂的条件可以控制信号。