这是一段代码,带有3个不同的always语句,应该是可合成的。问题如下:
always_comb
begin
c_cntr1 = cntr1;
c_func_val1 = diff (0, c_cntr1);
if (read)
c_cntr1 = cntr1+1;
end
我期望在c_cntr1更改时重新评估always_comb,并调用该函数并重新评估c_func_val1,但它没有。我是否错误地解释了LRM?
这是一个完整的测试用例,显示错误的行为,另外2个始终阻止产生正确的结果。我用NC跑了这个。我没有检查过其他模拟器或综合工具。
完整的测试案例
module test_always_comb();
reg clk, resetn, read;
initial
begin
clk = 0;
resetn = 0;
forever #5 clk = ~clk;
end
initial
begin
resetn = 0;
read = 0;
@(posedge clk);
@(posedge clk);
resetn = 1;
for (int i = 0; i < 10; i++)
begin
@(posedge clk);
if (i%2 == 0)
read= 1;
else
read= 0;
end
$finish;
end
always@(posedge clk)
if (resetn)
begin
$display("Value of c_func_val1 is %d, cntr is %d, c_cntr is %d\n", c_func_val1, cntr1, c_cntr1);
$display("Value of c_func_val2 is %d, cntr is %d, c_cntr is %d\n", c_func_val2, cntr2, c_cntr2);
$display("Value of c_func_val3 is %d, cntr is %d, c_cntr is %d\n", c_func_val3, cntr3, c_cntr3);
end
// Synesizable Design Code
function automatic [4:0] diff
(
input [4:0] num1,
input [4:0] num2
);
return num2;
endfunction // diff
logic [4:0] c_cntr1, c_cntr2, c_cntr3, c_func_val1, c_func_val2, c_func_val3;
reg [4:0] cntr1, cntr2, cntr3;
always_comb
begin
c_cntr1 = cntr1;
c_func_val1 = diff (0, c_cntr1);
if (read)
c_cntr1 = cntr1+1;
end
always_comb
begin
c_cntr2 = cntr2;
if (read)
c_cntr2 = cntr2+1;
c_func_val2 = diff (0, c_cntr2);
end
always @(*)
begin
c_cntr3 = cntr3;
if (read)
c_cntr3 = cntr3+1;
c_func_val3 = diff (0, c_cntr3);
end
always_ff @(posedge clk or negedge resetn)
begin
if (~resetn)
begin
cntr1 <= 0;
cntr2 <= 0;
cntr3 <= 0;
end
else
begin
cntr1 <= c_cntr1;
cntr2 <= c_cntr2;
cntr3 <= c_cntr3;
end
end
endmodule
谢谢你的帮助。
这是always @*
和always_comb
之间的差异之一。 always_comb不会根据标准重新评估(总是@ *会)。
您描述了一种称为read before write
的条件,这意味着在您写入变量之前,您会在块内部读取变量。
always @*
可以在这种情况下产生毛刺或挂在零延迟循环中。 always_comb永远不会循环。
除了目视检查之外,检查它的唯一方法是运行打开相应规则的linting工具。