Tuesday, August 11, 2020

Structure in System Verilog

 Hi Everyone !!!

In this blog we are going to see the concepts of Structure in System Verilog.

  • Structure is a collection of variables and/or constants under a single name. The entire collection can be referenced, using the name of the structure. Each member within the structure also has a name, which is used to select it from the structure.
  • Structure can be accessed as whole or separately.
Syntax:
<structure_name>.<variable_name>
                struct {
                            int a, b;      // 32-bit variables
                            data_t data; // user-defined type
                            logic [23:0] addr; // 24-bit variable
                            bit flag; // 1-bit 2-state var.
                           } struct_ex;

Structure allows all type of variables except net types(wire/tri) or var type variables in inside structure. It leads to compilation error. By using struct as wire/tri/var we can access. We will discuss about in structure accessing.

Structure Declaration Methods:
  • Wire Structure
 In General Net type is not allowed in inside of structure. So we go far wire/tri structure
module TB;
    struct {
     logic a;
     bit d;
     wire e;    // In structure net is used it leads to compilation error
     logic b;} my_data;
endmodule

The above compilation can be overcome by using wire/tri

module TB;
    wire struct {  // Here all the variables will act as wire only irrespective of declaration
     logic a;
     bit d;
     logic e;    
     logic b;} my_data;
     assign my_data.a=1'b1;
     initial begin
      my_data.b=1'b1;   / /Here "b" act as wire irrespective of declaration. It leads to compilation 
//error because we are used in procedural block
      my_data.d=1'b1;   /Here "d" act as wire irrespective of declaration. It leads to compilation 
//error because we are used in procedural block
      $display(" A =%0d B=%0d", my_data.a,my_data.b);
     end
   endmodule

From this we conclude that net not allowed inside the structure. By using wire/tri struct we can access the variable as wire/tri irrespective of declaration. Inside the wire struct all the variables treated as net variables. So we must follow the net variables code rules to access wire struct variables. similarly we can use var struct also. 
  • Typed and anonymous Structure 
    A typedef declaration lets you define your own identifiers that can be used in place of type specifiers such as int, byte, real. 
    Declaring structure as typedef does not allocate any storage. When a structure is declared without typedef then the structure is called as anonymous structure.
      If there is a need to create multiple structure variables with the same constituents,it will be better to create user defined structure.

module TB;
    typedef struct {
     int a;
     bit d;
     logic b;} my_data;
    my_data examp;   // structure instantiation which is allowed in typedef only
    my_data examp1;  // structure instantiation which is allowed in typedef only
      initial begin
         examp.a=10;  //  Here 10 is assigned for a
         examp1.a=15;  //  Here 15 is assigned for a
// The same variable accessed with different handle name which is allowed in typedef only
         $display(" A =%0d A1=%0d", examp.a,examp1.a);
      end
endmodule

 OUTPUT:
 A=10 A1=15
  • Packed Structure
         By default structure is unpacked. A packed structure is a mechanism for subdividing a vector into subfields, which can be conveniently accessed as a member. packed structure is packed without any memory gap. 
        A packed structure stores all members of the structure as contiguous bits, in a specified order. A packed structure is stored as a vector, with the first member of the structure being the left-most field of the vector. The right-most bit of the last member in the structure is the least-significant bit of the vector, and is numbered as bit 0.
        All members of a packed structure must be integral values. An integral value is a value that can be represented as a vector, such as byte, int and vectors created using bit or logic types. A structure cannot be packed if any of the members of the structure cannot be represented as a vector. This means a packed structure cannot contain real or shortreal variables, unpacked structures, unpacked unions, or unpacked arrays   .
        Packed structure can be accessed by using structure name or bitwidth.
  
  module TB;
     struct packed {  
     logic[8:0] a;
     bit[5:0] b;
     logic c} my_data;
     initial begin
      my_data.a=9'd9;   //Here I am accessing strucure by name
      my_data.[6:1]=6'd6;  //Here I am accessing strucure by bitwidth 
      my_data.[0]=1;    //Here I am accessing strucure by bitwidth
      $display(" ENTIRE STRUCTURE =%p A=%0d B=%0d  C=%0d", my_data, my_data.a,my_data.b,my_data.c);  /Here I am printing value by structure name
     end
   endmodule

OUTPUT:

ENTIRE STRUCTURE '{a:'h9, b:'h6, c:'h1} A=9 B=6 C=1

  • Signed Packed Structure
Packed structures can be declared with the signed or unsigned keywords. These modifiers affect how the entire structure is perceived when used as a vector in mathematical or relational operations.They do not affect how members of the structure are perceived. Each member of the structure is considered signed or unsigned, based on the type declaration of that member. A part select of a packed structure is always unsigned, the same as part selects of vectors in Verilog.

EX:
module TB;
   typedef struct packed unsigned//here unsigned so it doesn't care about MSB bits values.  It consider the whole value as positive only
     logic [1:0] a;
     logic[1:0] b;
      bit c;} my_data;
      my_data A,B;  // structure handles
    initial begin
     // Assigning different values to structure handles
     A=8;  // binary form is 01000
     B=17; //  binary form is 10001 
    if(A>B) begin   // Comparing two different handles of structures
      $display("A is greater than B");
    end else begin
      $display("B is greater than A");
    end
  end
endmodule

OUTPUT:
B is greater than A

The same code can be tried for signed it will produce a different results.
module TB;
   typedef struct packed signed {  //here signed so MSB bit is considered for negative sign indication
     logic [1:0] a;
     logic[1:0] b;
      bit c;} my_data;
      my_data A,B;  // structure handles
    initial begin
     // Assigning different values to structure handles
     A=8;  // binary form is 01000
     B=17; //  binary form is 10001 -> here MSB bit is set its is negative value
    if(A>B) begin   // Comparing two different handles of structures
      $display("A is greater than B");
    end else begin
      $display("B is greater than A");
    end
  end
endmodule

OUTPUT:
A is greater than B

Note :
Based on our use case we can select signed or unsigned structure. Inside structure signed/unsigned not into the part.

IMPORTANT KEY POINTS:
  • The signing of unpacked structures is not allowed. The following declaration would be considered illegal:
                typedef struct signed {
                  int f1 ;
                  logic f2 ;
                } my_daya; // illegal declaration
  • If all data types within a packed structure are 2-state, the structure as a whole is treated as a 2-state vector.
  • If any data type within a packed structure is 4-state, the structure as a whole is treated as a 4-state vector. If there are also 2-state members in the structure, there is an implicit conversion from 4-state to 2-state when reading those members and from 2-state to 4-state when writing them.
  • Only packed structures should be an integral type only.
  • A packed structure can be used with a typedef.
ASSIGNING TO STRUCTURES:
  •  A structure can be assigned as a whole and passed to or from a subroutine as a whole.
  • Members of a structure data type can be assigned individual default member values by using an initial assignment with the declaration of each member. The assigned expression shall be a constant expression.
  • An example of initializing members of a structure type is as follows:
            typedef struct {
                int addr = 1 + constant;
                int crc;
                byte data [4] = '{4{1}};
            } my_data;
The structure can then be instantiated.
my_data pi; // initialization defined by the typedef.
if an explicit initial value expression is used with the declaration of a variable, the initial assignment
expression within the structure data type shall be ignored. For example:
my_data pi = '{1,2,'{2,3,4,5}};
  • my_data pi= '{default:0}; // set all members of my_data to 0 (allowed)
  • my_data pi = '{addr:0,crc:16,data:1} // (allowed-list by name)
  • my_data pi = '{5,10,1}  // (allowed-list by order)
  • my_data pi ='{addr:6,1,0} // not allowed (illegal to mix listing by name and orger-leads to compilation error)
ADDITIONAL POINTS:
  • Structures can be passed as an argument to task and functions.
  • Both unpacked and packed structures are synthesizable. Synthesis supports passing structures through module ports, and in/out of tasks and functions.
  • Because a packed structure is stored as a vector, operations on the complete structure are treated as vector operations. Therefore, math operations, logical operations, and any other operation that can be performed on vectors can also be performed on packed structures
  •   EX:  
      typedef struct{ logic a;
                              logic[7:0] b;
                              logic[31:0] c;} my_data;
                  my_data pin,pout;
                  initial begin
                     pot=pin<<2;
                  end

      Difference between array and structure?

  • Structure differs from an array, in that an array is a collection of elements that are all the same type and size, where as a structure is a collection of variables and or constants that can be different types and different sizes.
  • Another difference is that array elements can be accessed by using array index where as in structure elements are accessed by using structure name.

Hope this logic's will be useful to everyone !!!
Giving feedback is more precious than writing an article!!! 😊😊😊😊😊
Always welcome both positive and negative feedback's !!!
Feel free to post any queries related SV and UVM  

“Let the improvement of yourself keep you so busy that you have no time to criticize others.”
                                           
― Roy T. Bennett,

Sunday, August 9, 2020

Applications of Scope Resolution Operator in System Verilog

 Hi Everyone!!!

In this blog We are going to the Applications of  Scope Resolution Operator in System Verilog.

 Scope Resolution operator is denoted as ::  It is used to refer an identifier within the scope of the class. Left side of an scope resolution operator must be class type name, package name, coverage name, typedef name or cover point name and right hand side should be like variable name of any method name(task/function).

Applications:

  • Defining Extern Function
  • Accessing Static methods
  • Using Package parameter accessing without importing in module
  • To avoid Name Space Collision

Examples:

1) Defining Extern Function

Extern task and methods can be accessed by using ::

//class
class scope;
  int data;
  extern function void display(); //Here display function is declared as extern
endclass

//Here display function (extern function) is accessed outside of class by using ::
function void scope :: display();
      $display("data = %0d", data);
 endfunction
module tb;
  initial begin
    scope p;
    = new();
    p.data = 20;
    p.display;
  end
endmodule

OUTPUT

data = 20

2) Accessing Static Methods

Static member of the class is accessed outside of the class by using ::

//class
class scope;
  int a;
  static int b;
   function display(int a,b);
    $display("Values are A=%0d B=%0d",a,b);
  endfunction
endclass
 
module tb;
  initial begin
    scope p;
    = new();
    p.a=10; // non static member is accessed by class handle(p)
    scope::b = 20;  // static member is accessed by class name with ::
    p.display(p.a,scope::b);
  end
endmodule

OUTPUT:

Values are A=10 B=20

3) Using Package parameter accessing without import in module

Here in package variable "a"is declared. Note that the package has to be included in compilation wherever we use. But not necessarily "imported". This can be achieved by using ::

//package
package scope;
  int a=10;
endpackage
 
module tb;  
  int b;
  initial begin
    b=scope::a;  // without importing variable(a) is accessed here by using ::
    $display(" VALUE %0d",b);
  end
endmodule



OUTPUT:
VALUE 10

4) To avoid name Space Collision

//package
package scope;
  int a=10;
endpackage
 
module tb;  
  int a=15,b,c;
    initial begin
    b=scope::a;  // From package "a" value is assigned to b  (explicitly we mentioned)
    c=a;  // current scope of "a" value is assigned to c
    $display(" VALUE B=%0d C=%0d",b,c);
  end
endmodule

OUPUT:
               VALUE B=10 C=15

Hope this logic's will be useful to everyone !!!
Giving feedback is more precious than writing an article!!! 😊😊😊😊😊
Always welcome both positive and negative feedback's !!!
Feel free to post any queries related SV and UVM  

“Success is getting what you want, happiness is wanting what you get” 
                                            ― W. P. Kinsella






Array Slicing in System Verilog

 Hi Everyone !!! 

   In this blog we are going to see concepts of Array Slicing.

   In System Verilog, by using part select we can select one part of an array elements and assigned to another array.

   Slice is a selection of one or more contiguous elements of an array, whereas part select is a selection of one or more contiguous bits of an element.

what is the difference between an array slice and part select?

As mentioned above part select operates on bits of an element, whereas slice operates on elements of an array. Part select and Slice is explained below.
Array part select
SystemVerilog uses the term part select to refer to a selection of one or more contiguous bits of a single dimension packed array.
bit [31:0] array1;
bit [07:0] array2[4];
 
array2[0] = array1[07:0];
array2[1] = array1[15:8];
array2[2] = array1[23:16];
array2[3] = array1[31:24];
The above example refers to copying 32-bit array1 to array2. this is done with the part selection of array1 variables.
program array_slice_TB;
  bit [31:0] array1;
  byte  array2[4];
 
  initial begin
    std::randomize(array1);
     
    $display("Value of array1 is %h",array1);
    $display("Before Part select");
    foreach(array2[i])
      $display("\t array2[%0d] = %h",i,array2[i]);  
    array2[0] = array1[07:0];
    array2[1] = array1[15:8];
    array2[2] = array1[23:16];
    array3[3] = array1[31:24];
     
    $display("After the array part select,");
    foreach(array2[i])
      $display("\t array2[%0d] = %h",i,array2[i]);  
  end
endprogram

Simulator Output

Values of array1 is 05e23536
 Before Part select
array2[0] = 00 
array2[1] = 00 
array2[2] = 00 
array2[3] = 00
 After the array part select, 
array2[0] = 36 
array2[1] = 35
array2[2] = e2 
array2[3] = 05

array slice
SystemVerilog uses the term slice to refer to a selection of one or more contiguous elements of an array.
  bit [31:0] array1 [7:0]//array of 8 elements of width 32bit
  bit [31:0] array2 [1:0]//array of 2 elements of width 32bit
   array2 = array1[5:4]//assigning 2 elements of array array1  to array2
program array_slice;
  bit [31:0] array1 [7:0];
  bit [31:0] array2 [1:0];
 
  initial begin
    std::randomize(array1);
     
    $display("Value of array1 are %p",array1);
     
    $display("Before the array part select,");
    $display("\tValues of array2 are %p",array2);
     
    array2 = array1[5:4];
     
    $display("After the array part select,");
    $display("\tValues of array2 are %p",array2);  
  end
endprogram

Simulator Output

Value of array1 are '{'h2b5c2c6e, 'h815f8d74, 'hcf578554, 'h7bb6d188, 'hfad5c89b, 'h401079a, 'hcf21010, 'h471cef5f} 
Before the array part select,
Values of array2 are '{'h0, 'h0}
After the array part select,
Values of array2 are '{'hcf578554, 'h7bb6d188}
HOW TO WRITE GENERIC LOGIC FOR BIT SELECTION?
Using +: and -: Notation part selection generic logic can be written.

+: NOTATION

array2 array1 [j +: k];
j -> bit start position
k -> Number of bits up from j’th position 

+: example:
array2 = array1 [j +: k];
0 -> Starting point
8 -> 8 elements up from 0 , so end point is 7.
array2 = array1 [7:0];

The above 32-bit data copying to byte array can be re-written with + notation as below.

foreach(array1[i]) array2[i] = array1[8*i +: 8];
Above code can be expanded as below,
array2[0] = array1[8*0 +: 8]//array1[7:0]
array2[1] = array1[8*1 +: 8]//array1[15:8]
array2[2] = array1[8*2 +: 8]//array1[23:16]
array2[3] = array1[8*3 +: 8]//array1[31:24]
program array_slice;
  bit [31:0] array1;
  byte       array2[4];
 
  initial begin
    std::randomize(array1);
     
    $display("Value of array1 is %h",array1);
     
    $display("Before the assignement,");
    foreach(array2[i])
      $display("\t array2[%0d] = %h",i,array2[i]);  
     
    foreach(array2[i]) array2[i] = array1[8*i +: 8];
     
    $display("After the array part select,");
    foreach(array2[i])
      $display("\t array2[%0d] = %h",i,array2[i]);  
  end
endprogram

Simulator Output

Value of array1 is 05e23536
Before the assignement,
array2[0] = 00
array2[1] = 00
array2[2] = 00
array2[3] = 00
After the array part select,
array2[0] = 36
array2[1] = 35
array2[2] = e2
array2[2] = 05
Array slicing Example for ( -:)
program array_slice;
  bit [31:0] array1;
  byte       array2[4];
 
  initial begin
    std::randomize(array1);
    $display("Value of array1 is %h",array1);
     for( int i=3;i>=0;i--) begin
         array2[i]=array1[8*(i+1)-1-:8];
        $display("\t array2 %p [%0d]",array2,i);  
        end
  end
endprogram

Simulator Output

Value of array1 is 2b5c2c6e
array2 '{0, 0, 0, 43} [3]
array2 '{0, 0, 92, 43} [2]
array2 '{0, 44, 92, 43} [1]
array2 '{110, 44, 92, 43} [0]

The above code is written by using (+:) notation also.
Array slicing Example for ( +:)
program array_slice;
  bit [31:0] array1;
  byte       array2[4];
 
  initial begin
    std::randomize(array1);
    $display("Value of array1 is %h",array1);
     forint i=0;i<=3;i++) begin
         array2[i]=array1[(8*i)+:8];
        $display("\t array2 %p [%0d]",array2,i);  
        end
  end
endprogram

Simulator Output

Value of array1 is 2b5c2c6e
array2 '{110, 0, 0, 0} [0]
array2 '{110, 44, 0, 0} [1]
array2 '{110, 44, 92, 0} [2]
array2 '{110, 44, 92, 43} [3]

Rule:
The size of the part select or slice must be constant, but the position can be variable.
As per the rule ‘array2 = array1[j +: k]’; or ‘array2 = array1[j -: k];’, k must be always constant.
in the above examples k=8.

Hope this logic's will be useful to everyone !!!
Giving feedback is more precious than writing an article!!! 😊😊😊😊😊
Always welcome both positive and negative feedback's !!!
Feel free to post any queries related SV and UVM  

“No one can make you feel inferior without your consent.”      ― Eleanor Roosevelt,

`define Macro usage in System Verilog

 Hi Everyone !!! In this blog we are going to see the usage of `define macro in System Verilog. A text macro substitution facility has been ...