System Verilog "ref" is a nice reference instead of "value"



Pass by reference is an interesting and very useful feature in system verilog. Very useful and importatn topic to understand and you might hit this as interview question in your next verification interview. This one is one of the very commonly asked interview question. Lets understand...

To begin, lets understand basic concept for pass by value vs pass by reference. In verilog, method arguments takes as pass by value (this is default). The inputs are copied when the method is called and the outputs are assigned  to relevant outputs when exiting the method. 

In system verilog, methods can also have "pass by reference". In this case, arguments passed by reference are not copied into subroutine area instead, a reference to the original arguments are passed to subroutine. In this case subroutines can access the arguments data via reference.  

This is very efficient way of passing arguments like class objects or arrays of objects. Scenario like these where you are dealing with class  objects and arrays of objects, if you use pass by value it would create a consume lot of memory on the stack because it has to copy the values and then use it for subroutine. Another advantage of using pass by reference is, since the caller and the function/tasks shares the same reference, any change done inside function using reference would also be visible to the caller. 

Example:

function automatic int my_crc (ref byte data [10:1]);

  for (int j =1; j<=10; j++) begin

    my_crc ^= data[j];

  end

endfunction

In this example, you can see data is declared with "ref" meaning, each call to CRC in for loop, my_crc function does to need to create a copy of the data on stack memory. Memory would have been consumed more if you would not use "ref" and use it as pass by value (because in that case as mentioned, every time my_crc function calls, it would need to create a copy on stack memory)

Now, an obvious question!

What if user wants to make sure that the ref argument is not modified by the function?

Answer to this question is "const ref"!! We need to use const key word if you want to make sure that ref argument is not modified by the function. 

For same example:

Same function "my_crc" the argument can be declared as "const ref" to make sure the original data contents are not modified accidently by my_crc function. Very very useful feature to understand in the case where you want to make sure engineers don't modified original content accidently. 

function automatic int my_crc (const ref byte data [10:1]);

  for (int j =1; j<=10; j++) begin

    my_crc ^= data[j];

  end

endfunction


Now another obvious question!

Do we need to declare each arguments as "ref" if you have more than one argument in your task/function.

Answer is "NO". 

For example:

task my_task (ref int data[10], bit a, b)

In declaration like this, one needs to clearly understand each arguments to function/task can have direction which can be input, output or inout or ref. If no direction specified the default value of inputs are selected. If one argument is specifies the direction then all following arguments hold on to the same direction unless explicitly changed.

In above example, my_task, first argument is specifies "ref" direction and following variables does not explicitly specifies direction, a and b would be considered as pass by reference.

Hope this clears out some basic understanding of pass by value vs reference. 

Thanks,

ASIC With Ankit