Showing posts with label automatic. Show all posts
Showing posts with label automatic. Show all posts

Sunday, 28 January 2018

Automatic/Static Variables and Function/Task with Automatic Lifetime in SystemVerilog

Before going into static and automatic variable let’s first go through 2 important terminology and then will go through automatic and static.

Scope:
Scope is the region or section of code where a variable can be accessed.
Variables declared inside a module, interface, program, or checker, but outside a task, process, or function, are local in scope.

Lifetime:
Lifetime is the time duration where an object/variable is in a valid state.
Variables declared outside a module, program, interface, checker, task, or function are local to the
compilation unit and have a static lifetime (exist for the whole simulation).
Variables declared inside a static task, function, or block are local in scope and default to a static lifetime.

Specific variables within a static task, function, or block can be explicitly declared as automatic. Such
variables have the lifetime of the call or block and are initialized on each entry to the call or block.
---------------------------------------------------------------------
---------------------------------------------------------------------
Result:
---------------------------------------------------------------------
---------------------------------------------------------------------


Automatic Function/Task (Function/Task with Automatic Lifetime):
In Verilog default lifetime of all the task/function is static.
Tasks and functions may be declared as automatic. Variables declared in an automatic task, function, or block are local in scope, default to the lifetime of the call or block, and are initialized on each entry to the call or block.

In other word, Automatic task/function variables cannot be accessed by hierarchical references. Automatic variables are automatically destroyed once the scope (task, function, block) in which they are created ends and regenerated when again enters into scope (task, function, block).
---------------------------------------------------------------------
---------------------------------------------------------------------


Class methods has Automatic lifetime by default:
Because of backward compatibility reason, SystemVerilog could not change the default lifetime qualifier to ‘automatic’ but since class methods were new, it changed the lifetime of all methods to be automatic.
---------------------------------------------------------------------
---------------------------------------------------------------------


The keyword ‘static’ is overloaded. There is a semantic difference between the meaning of ‘static’ used to the left of a function/task keyword and ‘static’ used to the right of the function/task keyword.

When used to the left of the function or task, ‘static’ is a class qualifier and has the same as on any static method in C++/Java. It is a method of the class type, not of an instance of a class object. Other class qualifiers are ‘local’ and ‘protected’ and along with ‘static’ are only allowed in front of methods of a class. There is no corresponding ‘automatic’ class qualifier.

When used to the right of a function or task, ‘static’ is a lifetime qualifier, with ‘automatic’ being the corresponding qualifier.

For more details refer this link.

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