Reputation: 77
Here's a piece of code with 3 different always statement which should be synthesizable. The issues is with the following:
always_comb
begin
c_cntr1 = cntr1;
c_func_val1 = diff (0, c_cntr1);
if (read)
c_cntr1 = cntr1+1;
end
I expected the always_comb to be re-evaluated when c_cntr1 changes and call the function and re-evaluate c_func_val1 but it doesnt. Am I interpreting the LRM incorrectly?.
Here's a complete testcase that shows the wrong behavior and the other 2 always block produces the right result. I ran this with NC . I havent checked the other simulators or synthesis tools.
Complete test Case
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
Thanks for your help.
Upvotes: 0
Views: 2328
Reputation: 12354
This is one of the differences between always @*
and always_comb
. always_comb will not re-evaluate according to the standard (while always @* will).
You described a condition known as read before write
which means that inside the block you read a variable before you write into it.
always @*
can generate glitches in such a situation or hang in a zero-delay loop. always_comb will never loop.
The only way to check for it besides visual inspection is to run a linting tools with corresponding rules turned on.
Upvotes: 1