user9906612
user9906612

Reputation: 77

SystemVerilog always_comb does not re-evaluate if the implied sensitivity list changes

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

Answers (1)

Serge
Serge

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

Related Questions