Tuesday 12 May 2015

Automatic Variable in fork...join_none


My intention was to start several parallel threads inside a for loop and pass loop variable as an input. I assumed the following code would do the job:

module top;
  initial begin
    for (int i = 0; i < 3; i++)
      fork
        some_task(i);
      join_none
  end
  task some_task(int i);
    $display("i = %d", i);
  endtask
endmodule


Do you see the problem with this code?
If not, don't worry as I didn't at first either. Here is the output if you run it:

//Output:
//i =           3
//i =           3
//i =           3


It seems that the for loop executed completely and only then did the spawned processes start, but they were given the latest value of i.

After digging around on the Internet I discovered the answer. The SystemVerilog LRM mentions that "spawned processes do not start executing until the parent thread executes a blocking statement". This explains why the for loop finished executing and why by the time the processes were spawned i had already reached the value '3'.

The LRM also shows exactly how to fix our problem: "Automatic variables declared in the scope of the fork...join block shall be initialized to the initialization value whenever execution enters their scope, and before any processes are spawned". Applying this to our code yields:

module top;
  initial begin
    for (int i = 0; i < 3; i++) begin

      automatic int j = i;
      fork

        begin
          some_task(j);

          //
        end
      join_none

    end
  end
  task some_task(int i);
    $display("i = %d", i);
  endtask

endmodule

Now, for every loop iteration a new variable is allocated, which is then passed to the respective task. Running this example does indeed give the desired result:

//Output:
//i =           2
//i =           1
//i =           0

6 comments:

  1. Hello,
    I think output should be {0,1,2} . Please correct if i am wrong ??

    ReplyDelete
    Replies
    1. Hi,

      Output is Tool specific,
      VCS J-2014.12-SP1-1 is giving output {0, 1, 2},
      Incisive 15.20 is giving output {2, 1, 0}.

      Delete
  2. You have tried this inside a module, if try this inside a class, then still the behaviour would the same. If so WHY?? ..

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. if i add a random delay before display statement its behaving as in the first case.. taking the last value? Any specific reason for that?

    ReplyDelete