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. 


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

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

    my_crc ^= data[j];



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];



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. 


ASIC With Ankit

ASIC With Ankit on AMIQ and's recommended list of blogs

Thank you AMIQ  and for having ASIC With Ankit on recommended list of blogs.

Learning is Sharing and Sharing is Learning too! Lets all keep sharing and keep learning!


System Verilog Array Randomization

System Verilog has different types of arrays that you can randomize to generate interesting scenario for the test bench you are working on. In SV we mainly have static array ,dynamic array and also queues that you can randomize, Lets deep dive in to each one of them to understand how you can use it with system Verilog:

Static Arrays:

class my_static_array;

   rand bit [3.0] my_array [8];


module my_testbench;

  my_static_array my_static_array_obj;

  initial begin

     my_static_array_obj = new ();


     $display (“my randomize value =%p”, my_static_array_obj.my_array);



In above example, we have my_array declared as static array which is declared as rand so that you array will be randomize when you do class object.randomize in your module to generate random value for our static array, You can play around with this example by changing different seed to how it changes the random value w.r.t to different seed.


Dynamic Array:

As we know, Dynamic arrays are the array for which size will not be pre-determined during the declaration. Dynamic array declaration will have square bracket [ ]. Lest deep dive in to example to better understand its declaration and how you can randomize it:


class my_dynamic_array;

rand bit [7:0] my_array [] //dynamic array

//Adding some constraint to this array so we can constraint array during randomization

constraint c1 {my_array.size >2 ; my_array_size <=10;}


//Constraint each array index value to be equal to index+1

constraint c2 {foreach (my_array[i])

                          my_array[i] = i+1;


function void print_value ();

  foreach (my_array[i])

     $display(“my array value my_array[%0d] = 0x%0h”, i, my_array[i] );



module my_testbench;

my_dynamic_array my_dynamic_array_obj;

initial begin

   my_dynamic_array_obj = new();  //create a memory for the class object

   my_dynamic_array_obj.randomize();  //randomize class with constraint provided

   my_dynamic_array_obj.print_value (); //calling function from class to print array value




Try this example and play around by changing constraint for index value, array size and seed to see how it changes the value to create corner scenario.

Queue randomization

We can have a queue declared as rand and then later in test bench you can randomize the queue to create a random value generate from the queue elements, We can constraint and limit the queue size in the constraints. Lets deep dive in to the example to better understand declaration of the queue, how you can limit and constraint the size of the queue and how you can randomize the queue to generate random behavior for your test bench:

class my_queue_c;

rand bit [3:0] my_queue [$] // Queue declaration with rand to randomize it later

//constraint to limit the size of the queue

constraint c1 {my_queue.size() == 5;}



module my_testbench;

my_queue_c  my_queue_c_obj;

initial begin

   my_queue_c_obj = new ();

    my_queue_c_obj.randomize ();

   //Print values

  $display(“my queue value =%p”,   my_queue_c_obj.my_queue);



Try this example and play around by changing constraint to change size of the queue and seed to see how it changes the value to create corner scenario.

Hope, this is useful simple example to understand randomization of arrays. Stay tuned for more simple but exciting post to learn System Verilog.

Keep reading and keep learning, stay tuned for more simple but exciting learning posts