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_latch
或 always
块中。
使用 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
条件是否为真,信号都被分配了一些东西。这种风格通常更容易,因为有很多控制信号的复杂条件。
我很困惑!有点沮丧。我花了很多时间在 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_latch
或 always
块中。
使用 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
条件是否为真,信号都被分配了一些东西。这种风格通常更容易,因为有很多控制信号的复杂条件。