Sunday, 29 March 2015

Compilation switches vs Simulation switches in SystemVerilog

Compilation Switches:

Verilog has following conditional compiler directives. 
  • `ifdef
  • `else
  • `elsif
  • `endif
  • `ifndef
The `ifdef compiler directive checks for the definition of a text_macro_name. If the text_macro_name is defined, then the lines following the `ifdef directive are included. If the text_macro_name is not defined and an `else directive exists, then this source is compiled.

The `ifndef compiler directive checks for the definition of a text_macro_name. If the text_macro_name is not defined, then the lines following the `ifndef directive are included. If the text_macro_name is defined and an `else directive exists, then this source is compiled.

If the `elsif directive exists (instead of the `else) the compiler checks for the definition of the text_macro_name. If the name exists the lines following the `elsif directive are included. The `elsif directive is equivalent to the compiler directive sequence `else `ifdef ... `endif. This directive does not need a corresponding `endif directive. This directive must be preceded by an `ifdef or `ifndef directive.


The code written within the compilation flags are compiled at compilation period.
As a result, the executable file creates a snap-shot of that particular code written within the compile flag.
For example, please go through below code.
LINE 1 :                     module xyz ()
LINE 2 :                        `ifdef FIRST
LINE 3 :                           $display ("Inside FIRST");
LINE 4 :                        `elseif SECOND
LINE 5 :                           $display ("Inside SECOND");
LINE 6 :                        `elseif THIRD
LINE 7 :                           $display ("Inside THIRD");
LINE 8 :                        `else
LINE 9 :                           $display ("Inside ELSE");
LINE 10 :                     `endif
LINE 11 :                     $display ("Inside LAST");
LINE 12 :                   endmodule  : xyz

 
Now compile the code with define "+define+FIRST".

The executable file will contains snapshot of "LINE 3 & LINE 11"
Now simulating the executable file, output will be as:
Inside FIRST
Inside LAST

 
Now we re-simulate(without compiling again), and pass define "+define+SECOND" at run time, output will be as:
Inside FIRST
Inside LAST

 
Now we re-simulate(without compiling again), without passing any defines at run time, output will be as:
Inside FIRST
Inside LAST

 
If we required to display "LINE 5" we have to re-compile complete testbench with +define+SECOND at compile time
Now simulating the executable file, output will be as:
Inside SECOND
Inside LAST



Simulation Switches:


Variable ( int i  /  string abc ) are used as simulation flag
The complete testbench will be compiled at one-shot, and the executable file will contains snap-shot of complete codes.
For example, please go through below code.

LINE 1 :                     module xyz ();
LINE 2:                         reg [1:0] arg;
LINE 3 :                        if ($value$plusargs("argument=%0d",arg));
LINE 4 :                            if(arg == 1)
LINE 5 :                              $display ("Inside FIRST");
LINE 6 :                           else if(arg == 2)

LINE 7 :                              $display ("Inside SECOND");
LINE 6 :                           else if(arg == 3)
LINE 7 :                              $display ("Inside THIRD");
LINE 8 :                           else
LINE 9 :                              $display ("Inside ELSE");
LINE 10 :                      end
LINE 11 :                     $display ("Inside LAST");
LINE 12 :                   endmodule : xyz



Now compile the testbench without any arguments . The executable file contains snap-shot of all complete lines mention in module.
Now simulating the executable file, and we provide argument "+argument=1" at runtime  output will be as:
Inside FIRST
Inside LAST


Now we re-simulate(without compiling again), and we provide argument +argument=2, at runtime  output will be as:
Inside SECOND
Inside LAST

 
Now we re-simulate(without compiling again), and we provide argument +argument=3, at runtime  output will be as:
Inside THIRD
Inside LAST

 
Now we re-simulate(without compiling again) without any argument, at runtime  output will be as:
Inside LAST

 
As we saw, the benefits of "$values$plusargs" is:
One time compiling (creating executable file) and running multiple testcase on same executable file.


Now for environmental Modification, It is very necessary to reduce down the usage of (`ifdef / `elseif ) to very minimum and try to use simulation time arguments as much as possible. And at the same time we need to take care of single Test run but on other side it will be very much help full for (One time compilation with multisimulation) regression.

With the above style of programing,we can save recompilation times.

Difference between $test$plusargs and $value$plusargs:

There are two types of Simulation switches in systemverilog.

$value$plusargs:
We have seen example of $value$plusargs in above explaination. In $value$plusargs user need to pass value in argument and based on that value some decision will be taken.
We will go through another example:
module valuetest();
  integer i;
  real r;
  reg [11:0] v;
  reg [128:0] s;

  initial begin
    if($value$plusargs("STRING=%s", s))
      $display("GOT STRING");
    if($value$plusargs("INTG=%d", i))
      $display("GOT INTEGER");
    if($value$plusargs("REAL=%f", r))
      $display("GOT REAL");
    if($value$plusargs("VECTOR=%b", v))
      $display("GOT VECTOR");

    $display( "String is %s", s);
    $display("Integer is %d", i);
    $display("Realnum is %f", r);
    $display("Vector is %b", v);
  end
endmodule

Compilation:
command filename.sv
Simulation:
command +STRING=rrf  +INTG=123  +REAL=1.32  +VECTOR=10101

RESULTS:
GOT STRING
GOT INTEGER
GOT REAL
GOT VECTOR
String is rrf
Integer is 123
Realnum is 1.320000e+00
Vector is 000000010101 
$test$plusargs:
In $test$plusargs user don't need to give value in argument. If user provides simulation argument in simulation command then if condition will be executed otherwise else part (if exists) will be executed.
Example:
module switches();
  initial begin

    if($test$plusargs("TYPE_1"))
      $display("TYPE_1 message");
    else
      if($test$plusargs("TYPE_2"))

        $display("TYPE_2 message");
  end
endmodule
 
No need to give +define+TYPE_1 or +define+TYPE_2 during compilation

Simulate with +TYPE_1
RESULT:
TYPE_1 message

Simulate with +TYPE_2
Then simulate,result is
RESULT:
TYPE_2 message



Benefits & disadvantage of Compilation/Simulation Switches:

If we use Compilation switches:

  1. For Single Test run:
    1. Compilation and simulation time reduces. because the very small amount of code will be exercised. 
  2. For Regression: 
    1. If their are defines for each test case / test command we have to COMPILE & SIMULATE each testcase.

If we use Simulation switches:

  1. For Single Test run: 
    1. Compilation time increases (because complete code is getting exercised) and simulation time remains same.
  2. For Regression: 
    1. We have to compile one time, and we can use same executable file for all the test cases / test commands.

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

Difference between Dynamic Array and Assosicate Array in SystemVerilog

With a regular array, you must specify its size when you declare it

bit my_array[10];
With a dynamic array you can allocate the size of the array during runtime (hence the term "dynamic").
bit my_dynamic_array[];  // Note size is not specified
...
my_dynamic_array = new[size];  // size is determined at run-time


Also, the array can be "re-sized" at a later point:
my_dynamic_array = new[new_size](my_dynamic_array);

In this case, new memory is allocated, and the old array values are copied into the new memory, giving the effect of resizing the array.

The main characteristic of an associative array is that the index type can be any type - you are not restricted to just integer values. For example, you can use a string as the index to look up an "associated" value.

bit my_assoc_array[string];  // Array stores bits, using a string as an index
...
my_assoc_array["testname"] = 1;  //Stores a 1 into the array element indexed by the value "testname"
$display(my_assoc_array["testname"]); // Displays 1

An associative array is also "dynamic", in the sense that it does not have a pre-determined size. However, you do not have to allocate the size - it grows as you add more elements into it.


Another answer is:

    Dynamic arrays are useful for dealing with contiguous collections of variables whose number changes dynamically.
    e.g.            int array[];
    When the size of the collection is unknown or the data space is sparse (scattered-throw in various random directions.), an associative array is a better option. In associative array, it uses the transaction names as the keys in associative array.
   e.g.            int array[string];

Different types of Arrays in SystemVerilog

Dynamic Array: 
  • We use dynamic array when we have no idea about the size of the array during compile time and we have to allocate its size for storage during run time.
  • We basically use this array when we have to store a contiguous or Sequential collection of data.
  • The array indexing should be always integer type.
  • To allocate size of a dynamic array, we have to use new[] operator.
            Example: 
               int my_array [];
               initial
                   begin
                         my_array = new[4];                              //Allocated 4 elements 
                    end 
  • To resize a dynamic array, we have to do as follows:
             Example:               
               initial 
                  begin 
                       my_array = new[18](my_array);     //Resize the Array and Copy 
                  end 

  • To know the size of the array, we have to use size() operator.
             Example: 
              my_array.size();                    //Returns the current size of the array, my_array as an integer. 

  • To delete an element from a dynamic array, we have to use delete() operator.
             Example: 
              initial 
                  begin 
                       my_array.delete();    //All the elements of array, my_array will be deleted. 
                   end


Associative Array: 
  • It is also allocated during run time.
  • This is the array, where data stored in random fashion.
  • It is used when we don’t have to allocate contiguous collection of data, or data in a proper sequence or index.
  • In associative array, the index itself associates the data. So it is called so.
  • Indexing is not regular, can be accessed using indexing like integer or string type or any scalar. 
Example: 
my_array ["name"];           // “name”, Index type is a string
my_array[address];           // address, Index type is an integer (here address is an integer).
my_array[my_class];       // my_class, Index type is a class.
my_array[s_array];          // s_array, Index type is an array.
  • It is better to use associative array, when size of the array is unknown & data space is random or irregular or sparse.
  • Following are the methods associated with Associative array. 
          num()  returns the number of entries in the Associative array 
Eg: my_array.num() 
first()  assigns the value of the first index in the Associative array to the given index variable Eg:my_array.first(i); 
last()  assigns the value of the last index in the Associative array to the given index variable Eg:my_array.last(i); 
next() — assigns the value of the next index in the Associative array to the given index variable Eg:my_array.next(i); 
prev()  assigns the value of the previous index in the Associative array to the given index variable Eg:my_array.prev(i); 
delete()  removes all the elements in the Associative array. 
Eg: my_array.delete(i); If the index is specified, then the element at the specified index “i”is deleted 
exists()  checks if element exists at the specified index “i” in the Associative arrayEg:my_array.exists(i);



 Queue: 
  • Queue is a variable size, ordered collection of Homogenous Data.
  • It is flexible, as it is variable in size and analogous to an 1-dimensional Unpacked array that can shrink & grow automatically and can be of size zero.
  • The main advantage of queue over dynamic array is that, we don’t need new[] operatorto allocate storage space for a queue.
  • The other advantages of queue over dynamic array is that we can manipulate the queue using various queue methods like: push, pop, delete, insert, size.
Example: 
module test_example ; 
int my_queue[$] = { 1, 2, 3 }; 
string s_queue [$] = {"first","second","third","fourth"}; 
string store;
initial 
begin
// Use of the size() method/operator 
$display("\n size() operator used"); 
for (int i = 0 ; i < my_queue.size(); i++ ) 
$display (my_queue[i]); 
$display("\n\n Elements of s_queue is :"); 
for (int i = 0; i < s_queue.size; i++) 
$write(s_queue[i]," "); 
// Use of insert() method/operator 
s_queue.insert(1,"next"); // Previous element 1 is now turned to element 2. 
s_queue.insert(2,"somewhere"); 
$display("\n\n insert() operator used"); 
for (int i = 0; i < s_queue.size; i++) 
$write(s_queue[i]," "); 
// Use of delete() method/operator 
s_queue.delete(1); // delete the element 1 
s_queue.delete(3); // delete the element 3 
$display("\n\n delete() operator used"); 
for (int i = 0; i < s_queue.size; i++) 
$write(string_queue[i]," "); 
// Use of pop_front() method/operator (it deletes the front of the queue) 
store = s_queue.pop_front(); 
$display("\n\n pop_front() operator used"); 
$display(" %s",store); 
for (int i = 0; i < s_queue.size; i++) 
$write(s_queue[i]," "); 
// Use of pop_back() method/operator (it deletes the back of the queue) 
store= s_queue.pop_back(); 
$display("\n\n pop_back() operator used"); 
$display(" %s",store); 
for (int i = 0; i < s_queue.size; i++) 
$write(s_queue[i]," "); 
// Use of push_front() and push_back() method/operator 
s_queue.push_front("in-front"); 
s_queue.push_back("in-back"); 
$display("\n\n push_front() and push_back() operator used"); 
for (int i = 0; i < s_queue.size; i++) 
$write(s_queue[i]," \n "); 
end 
endmodule
 
Result: 
size() operator used 
1 
2 
3 
 
Elements of s_queue[$] is: 
first second third fourth 
 
insert() operator used 
first next somewhere second third fourth 
 
delete() operator used 
first somewhere second fourth 
 
pop_front() operator used 
first 
somewhere second fourth 
 
pop_back() operator used 
fourth 
somewhere second 
 
push_front() and push_back() operator used 
in-front 
somewhere 
second 
in-back