Sunday 29 March 2015

Difference between pass by ref and pass by value?

Pass by value is the default method through which arguments are passed into functions and tasks. Each subroutine retains a local copy of the argument. If the arguments are changed within the subroutine declaration, the changes do not affect the caller.

In pass by reference functions and tasks directly access the specified variables passed as arguments.Its like passing pointer of the variable.

example:
task pass(int i)    //  task pass(var int i) pass by reference 
{
delay(10);
i = 1;
printf(" i is changed to %d at %d\n",i,get_time(LO) );
delay(10);
i = 2;
printf(" i is changed to %d at %d\n",i,get_time(LO) );
}





In verilog,method arguments takes as pass by value.The inputs are copyed when the method is called and the outputs are assigned to outputs when exiting the method.In SystemVerilog ,methods can have pass by reference.Arguments passed by reference are not copied into the subroutine area, rather, a reference to the original argument is passed to the subroutine. The subroutine can then access the argument data via the reference.

In the following example, variable a is changed at time 10,20 and 30. The method pass_by_val , copies only the value of the variable a, so the changes in variable a which are occurred after the task pass_by_val call, are not visible to pass_by_val. Method pass_by_ref is directly referring to the variable a. So the changes in variable a are visible inside pass_by_ref.


EXAMPLE:

program main();
  int a;

  initial begin
    #10 a = 10;
    #10 a = 20;
    #10 a = 30;
    #10 $finish;
  end

  task pass_by_val(int i);

    forever
      @i $display("pass_by_val: I is %0d",i);
  endtask


  task pass_by_ref(ref int i);
    forever begin
      @i $display("pass_by_ref: I is %0d",i);

    end
  endtask

  initial begin
    pass_by_val(a);

  end

  initial begin

    pass_by_ref(a);
  end

endprogram

RESULT:

pass_by_ref: I is 10
pass_by_ref: I is 20
pass_by_ref: I is 30



By default, SystemVerilog passes arrays by value, copying the entire array.
It is recommended to pass arrays by reference whenever possible for performance reasons.

If you want your function to modify the array, use ref.
If you want your function to read the array, use const ref.
Example:


module automatic test;
 
  initial run();
 
  function void run();
    // Create some SystemVerilog arrays and populate them
    int array[5];
    int queue[$];
    int assoc[int];
    for (int i = 0; i < 5; i++) begin
      array[i] = i;
      queue[i] = i;
      assoc[i] = i;
    end  
   
    pass_by_value(array, queue, assoc);
    $display("After pass by value:");
    for (int i = 0; i < 5; i++) begin
      $display("array[%0d]:%0d", i, array[i]);
      $display("queue[%0d]:%0d", i, queue[i]);
      $display("assoc[%0d]:%0d", i, assoc[i]);
    end  

    pass_by_ref(array, queue, assoc);
    $display("After pass by reference:");
    for (int i = 0; i < 5; i++) begin
      $display("array[%0d]:%0d", i, array[i]);
      $display("queue[%0d]:%0d", i, queue[i]);
      $display("assoc[%0d]:%0d", i, assoc[i]);
    end  
   
  endfunction

   // These functions try to modify the arrays.

   // Default.
   // A copy of the arrays is made in this function

   function void pass_by_value(int array[5], int queue[$], int assoc[int]);
    array[2] = 100;
    queue[2] = 100;
    assoc[2] = 100;
  endfunction


   // Original arrays are being referenced
   function void pass_by_ref(ref int array[5], ref int queue[$], ref int assoc[int]);
    array[3] = 100;
    queue[3] = 100;
    assoc[3] = 100;   
  endfunction
  


   // Original arrays are being referenced
   // And they can be read but cannot be modified in this function 

   function void pass_by_const_ref(const ref int array[5],
                                  const ref int queue[$],
                                  const ref int assoc[int]);
    // Arrays cannot be modified in this function
    // array[3] = 100;
    // queue[3] = 100;
    // assoc[3] = 100;   
  endfunction
 
endmodule

1 comment: