SystemVerilog Linked Lists

Linked lists and arrays are similar since they both store collections of data. The terminology is that arrays and linked lists store "elements" on behalf of "client" code. The specific type of element is not important since essentially the same structure works to store elements of any type. One way to think about linked lists is to look at how arrays work and think about alternate approaches.

The List package implements a classic list data-structure, and is analogous to the STL (Standard Template Library) List container that is popular with C++ programmers. The container is defined as a parametrized class, meaning that it can be customized to hold data of any type. The List package supports lists of any arbitrary predefined type, such as integer, string, or class object. First declare the Linked list type and then take instances of it. SystemVerilog has many methods to operate on these instances. 

A double linked list is a chain of data structures called nodes. Each node has 3 members, one points to the next item or points to a null value if it is last node, one points to the previous item or points to a null value if it is first node and other has the data. 

Difference between Queue and Linked list:

A queue can pretty much do anything a linked listed can do, and more efficiently. The only case where a linked list might be more efficient is when you need to join two lists together, or insert one list in the middle of another list. A queue is very efficient for adding one element at a time.

Previous : SystemVerilog Queue
Next :

SystemVerilog Queue

Queue is a variable size, ordered collection of homogeneous elements which can grow and shrink. The size of a queue is variable similar to a dynamic array, but a queue may be empty with no element and it is still a valid data structure. Queues can be used as LIFO (Last In First Out) Buffer or FIFO (First In First Out) type of buffers.

Syntax:
A queue is declared simply by putting a $ as the size of an array.
integer my_q[$];

You can initialize a queue at the place of its variable declaration:
integer my_q[$] = {1, 3, 5};

You can also set up an upper limit of index for a queue (a bounded queue):
integer my_q[$:127];

Since index of an array can only be non-negative, the maximum number of elements for the queue in the above case is 128 (i.e., 0 through 127).

Each element in the queue is identified by an ordinal number that represents its position within the queue, with 0 representing the first element and $ represents the last element.

Bounded Queues
Size of a queue can be limited by giving the last index (i.e. upper bound) as follows

int queueA[$:99]; // A queue whose maximum size is 100 integers 

These are called bounded queues.It will not have an element whose index is higher than the queue’s declared upper bound. Operators on bounded queue can be applied exactly the same way as unbounded queues, except that, result should fall in the upper bound limit.

The size of the queue is variable similar to dynamic array but queue may be empty with zero element and still its a valid data structure.

Queues and dynamic arrays have the same assignment and argument passing semantics. Also, queues support the same operations that can be performed on unpacked arrays and use the same operators and rules except as defined below:


// SystemVerilog Queue Operations
int q[$] = { 2, 4, 8 }; 
int p[$]; 
int e, pos; 
e = q[0]; // read the first (leftmost) item 
e = q[$]; // read the last (rightmost) item 
q[0] = e; // write the first item 
p = q; // read and write entire queue (copy) 
q = { q, 6 }; // insert '6' at the end (append 6) 
q = { e, q }; // insert 'e' at the beginning (prepend e) 
q = q[1:$]; // delete the first (leftmost) item 
q = q[0:$-1]; // delete the last (rightmost) item 
q = q[1:$-1]; // delete the first and last items 
q = {}; // clear the queue (delete all items) 
q = { q[0:pos-1], e, q[pos,$] }; // insert 'e' at position pos 
q = { q[0:pos], e, q[pos+1,$] }; // insert 'e' after position pos 

Queue Methods:

Queues also provides several built-in methods to access/modify queue. Below we have list down all such methods.
  • The size() method returns the number of items in the queue. If the queue is empty, it returns 0. 
  • The insert() method inserts the given item at the specified index position. 
  • The delete() method deletes the item at the specified index. 
  • The pop_front() method removes and returns the first element of the queue. 
  • The pop_back() method removes and returns the last element of the queue. 
  • The push_front() method inserts the given element at the front of the queue. 
  • The push_back() method inserts the given element at the end of the queue. 

// SystemVerilog Queue Methods
module queue_methods();

// Queue is declated with $ in array size
  integer queue[$] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
integer i;

initial begin
  $display ("Initial elements in the queue");
  print_queue;
  // Insert new element at begin of queue
  queue = {11, queue};
  $display ("new element added using concatenation");
  print_queue;
  // Insert using method at beginning
  queue.push_front(12);
  $display ("new element added using push_front");
  print_queue;
  // Insert using method at end
  queue.push_back(12);
  $display ("new element added using push_back");
  print_queue;
  // Using insert to insert, here 6 is index
  // and 13 is value
  queue.insert(6,13);
  $display ("new element added using insert(index,value)");
  print_queue;
  // get first queue element method at begining
  i = queue.pop_front();
  $display ("element poped using pop_front");
  print_queue;
  // get last queue element method at end
  i = queue.pop_back();
  $display ("element poped using pop_end");
  print_queue;
  // Use delete method to delete element at index 4 in queue
  queue.delete(10);
  $display ("deleted element at index 10");
  print_queue;
  #1 $finish;
end

  // Method to print queue
task print_queue;
  integer i;
  $write("Queue contains ");
  for (i = 0; i < queue.size(); i ++) begin
    $write (" %g", queue[i]);
  end
  $write("\n");
endtask

endmodule

Results:
Initial elements in the queue
Queue contains  0 1 2 3 4 5 6 7 8 9 10
new element added using concatenation
Queue contains  11 0 1 2 3 4 5 6 7 8 9 10
new element added using push_front
Queue contains  12 11 0 1 2 3 4 5 6 7 8 9 10
new element added using push_back
Queue contains  12 11 0 1 2 3 4 5 6 7 8 9 10 12
new element added using insert(index,value)
Queue contains  12 11 0 1 2 3 13 4 5 6 7 8 9 10 12
element poped using pop_front
Queue contains  11 0 1 2 3 13 4 5 6 7 8 9 10 12
element poped using pop_end
Queue contains  11 0 1 2 3 13 4 5 6 7 8 9 10
deleted element at index 10
Queue contains  11 0 1 2 3 13 4 5 6 7 9 10

Try simulation yourself here

Hope you get the idea how to declare and use the SystemVerilog Queues. Next we will learn about Linked lists, array methods and we will compare the array types in SystemVerilog.

Previous : SystemVerilog Associative Arrays
Next : SystemVerilog Linked Lists

SystemVerilog Dynamic Arrays

In this SystemVerilog Tutorial so far we have seen basic array type i.e. SystemVerilog Fixed arrays, as its size is set at compile time. 

Now what if you don't know the size of array until run-time? 

You may wish to set the size of array run-time and wish to change the size dynamically during run time. 

For example an IP packet varies length from one packet to other packet. In verilog, for creating such packet, array with maximum packet size is declared and only the number of elements which are require for small packets are used and unused elements are waste of memory. 

SystemVerilog overcomes this problem and provides us dynamic arrays. 

Following are the features of SystemVerilog Dynamic arrays :

1. Size of dynamic array can be set at runtime.
2. Previously set size of the dynamic array can be changed runtime without loosing the previous contents.

Hence, dynamic array is unpacked array whose size can be allocated run time along with the option to resize.

Declaration of SystemVerilog Dynamic Arrays :
Dynamic arrays are declared with empty word subscript [ ].


1
2
3
integer dyn_array_1[];
integer dyn_array_1[];
integer multi_dime_dyn_array[][]; 

Allocating size of Dynamic Array :
As seen above the dynamic array is declared with empty word subscript [ ], which means you do not wish to allocate size at compile time, instead, you specify the size at runtime.

The dynamic arrays used builtin function new[ ] to allocate the storage and initialize the newly allocated array.


// SystemVerilog Dynamic arrays
module dyn_arr;
  int dyn[], d2[];             // Empty dynamic arrays
  initial begin
    dyn = new[5];              // Allocate 5 elements
    foreach (dyn[j]) begin
      dyn[j] = j;              // Initialize the elements
      $display("j = %0d dyn = %0d",j,dyn[j]); 
    end
    $display("Copy the dynamic array");
    
    // Copy a dynamic array
    d2 = dyn;
    $display("dyn[0] = %0d d2[0] = %0d",dyn[0],d2[0]);
    
    $display("Modify contents of copy");
    // Modify the copy
    d2[0] = 5;                 
    $display("dyn[0] = %0d d2[0] = %0d",dyn[0],d2[0]);
    
    $display ("Extend the array length and check previous content");
    // Expand and copy
    dyn = new[20](dyn);
    $display("dyn[4] = %0d", dyn[4]);
    
    $display ("Extend the array length and check previous content");
    // Allocate 100 new integers. Old values will lost
    dyn = new[100];    
    $display ("dyn[4] = %0d", dyn[4]);
    // Delete all elements
    dyn.delete;   
  end
endmodule

Simulation result :
j = 0 dyn = 0
j = 1 dyn = 1
j = 2 dyn = 2
j = 3 dyn = 3
j = 4 dyn = 4
Copy the dynamic array
dyn[0] = 0 d2[0] = 0
Modify contents of copy
dyn[0] = 0 d2[0] = 5
Extend the array length and check previous content
dyn[4] = 4
Extend the array length and check previous content
dyn[4] = 0

Run Simulation

Methods associated with Dynamic arrays :

.size() : Returns the size of dynamic array. We can also use system task $size() method instead of .size() method.

.delete() : SystemVerilog also provides .delete() method clears all the elements yielding an empty array (zero size).


Previous : Fixed Size Arrays
Next : Associative Arrays

SystemVerilog Fixed Arrays

Let's talk about most used data type - Arrays. An array is a collection of data elements having the same type. Individual elements are accessed by index using a consecutive range of integers. However there are some type of arrays allows to access individual elements using non consecutive values of any data types. SystemVerilog Arrays offers several flavors of arrays beyond the single-dimension, fixed-size Verilog-1995 arrays. Many enhancement have been made to these classic arrays. Arrays can be classified as
  • Fixed Arrays or Fixed-Sized Arrays (sometimes known as static arrays) whose size cannot be changed once declared. 
  • Dynamic arrays which can be resized run time.

Declaring and initializing fixed-size array
Verilog requires that the low and high array limits must be given in the declaration. Almost all arrays use a low index of 0, so SystemVerilog lets you use the shortcut of just giving the array size, similar to C:

Example 1 : Declaring and using SystemVerilog fixed-sized arrays

int data[0:15];  // 16 ints [0]..[15]
int address[16]; // 16 ints [0]..[15]
address[15] = 1; // Set last array element


You can create multidimensional fixed-size arrays by specifying the dimensions after the variable name. This makes an unpacked array; we will take a look for packed arrays later. The following example creates several two-dimensional arrays of integers, 8 entries by 4, and sets the last entry to 1.

Example 2 : Declaring and using multidimensional fixed-sized array

int array2 [0:7][0:3]; // Verbose declaration
int array3 [8][4];     // Compact declaration
array2[7][3] = 1;      // Set last array element

SystemVerilog stores each element on a longword (32-bit) boundary. So a byte, shortint, and int are all stored in a single longword, while a longint is stored in two longwords. (Simulators frequently store four-state types such as logic and integer in two or more longwords.)

Example 3 : SystemVerilog Unpacked Array Declaration

bit [7:0] unpacked_array[3]; // Unpacked array

Unpacked array declared above is stored as shown below


You can initialize an array using an array literal that is an apostrophe and curly braces. Using this array literal you can set some or all elements at once. Also its easy to replicate values by putting a count before the curly braces. Below we have shown example to initialize the systemverilog fixed arrays

Example 4 : Initialize SystemVerilog Array

int ascend[4] = {0,1,2,3}; // Initialize 4 elements
int decend[5];
int array[2][3] = {{0,1,2}, {3,4,5}};
descend = {4,3,2,1,0}; // Set 5 elements
descend[0:2] = {5,6,7}; // Set first 3 elements
ascend = {4{8}}; // Four values of 8

Basic Array Operations
The most common way to manipulate an array is with a for or foreach loop. In below example the variable "i" is declared local to the for loop. To get the size of array we can use system function $size that returns the size of array. For foreach loop statement, you specify the array name and an index in square brackets and Systemverilog automatically steps through all the elements of the array. The index variable is local to the loop.

Example 5 : Access the arrays using for and foreach loops

// SystemVerilog For and Foreach loop to access arrays
module array_loops;
  initial begin
    bit [31:0] src[5], dst[5];
    for (int i=0; i<$size(src); i++) begin
      src[i] = i;
      $display("src[%0d] = %0d", i, src[i]); 
    end
    foreach (dst[j]) begin
      dst[j] = src[j] * 2; // dst doubles src values
      $display("dst[%0d] = %0d", j, dst[j]); 
    end
  end
endmodule

Simulation Results:
src[0] = 0
src[1] = 1
src[2] = 2
src[3] = 3
src[4] = 4
dst[0] = 0
dst[1] = 2
dst[2] = 4
dst[3] = 6
dst[4] = 8

Now in below example note that for SystemVerilog multidimensional arrays the syntax is not as you might expected. Instead of listing each subscript in separate square brackets – [i][j] – they are combined with a comma – [i,j].

Example 6: SystemVerilog Accessing Multidimensional Arrays using Foreach loop


// SystemVerilog For and Foreach loop to access arrays
module array_loops;
  int md[2][3];
  initial begin
    $display("Initial value:");
    foreach (md[i,j]) // Yes, this is the right syntax
      $display("md[%0d][%0d] = %0d", i, j, md[i][j]);
    $display("New value:");
    md = '{{9, 8, 7}, {default:5}}; // Replicate last 3 values
    foreach (md[i,j]) // Yes, this is the right syntax
      $display("md[%0d][%0d] = %0d", i, j, md[i][j]);
    end
endmodule

Simulation Results:
Initial value:
md[0][0] = 0
md[0][1] = 0
md[0][2] = 0
md[1][0] = 0
md[1][1] = 0
md[1][2] = 0
New value:
md[0][0] = 9
md[0][1] = 8
md[0][2] = 7
md[1][0] = 5
md[1][1] = 5
md[1][2] = 5

Packed arrays :


Before knowing what exactly packed and unpacked arrays are, lets also see how you can know which array is what, just by their declaration. 

Packed arrays have an object name comes before size declaration. 
For example: bit [3][7] a;

As specified previously unpacked array have an object name comes after size declaration. 
For example: bit a[3];

For some data types, you may want both to access the entire value and also divide it into smaller elements. For example, you may have a 32-bit register that sometimes you want to treat as four 8-bit values and at other times as a single, unsigned value. A SystemVerilog packed array is treated as both an array and a single value. Packed arrays can be made of only the single bit data types (bit, logic, reg) and recursively other packed arrays and packed structures. It is stored as a contiguous set of bits with no unused space, unlike an unpacked array.

Packed Array Example 
The packed bit and word dimensions are specified as part of the type, before the variable name. These dimensions must be specified in the [lo:hi] format. The variable bytes is a packed array of four bytes, which are stored in a single longword.


1
bit [3:0] [7:0] bytes; // 4 bytes packed into 32-bits

Packed Array Layout



You can mix packed and unpacked dimensions. You may want to make an array that represents a memory that can be accessed as bits, bytes, or long words. In Example 2-14, barray is an unpacked array of three packed elements.


Declaration of mixed packed and unpacked arrays


1
bit [3:0] [7:0] barray [3]; // Packed: 3x32-bit

The variable bytes is a packed array of four bytes, which are stored in a single longword. barray is an array of three of these elements.


With a single subscript, you get a longword of data, barray[2]. With two subscripts, you get a byte of data, barray[0][3]. With three subscripts, you can access a single bit, barray[0][1][6]. Note that because one dimension is specified after the name, barray[3], that dimension is unpacked, so you always need to use at least one subscript.

Choosing Between Packed and Unpacked Array

Which should you choose — packed or unpacked array?
A packed array is handy if you need to convert to and from scalars. For example, you might need to reference a memory as a byte or as a longword. The above array barray can handle this requirement. Only fixed-size arrays can be packed, not dynamic arrays, associative arrays, or queues.

If you need to wait for a change in an array, you have to use a packed array. Perhaps your testbench might need to wake up when a memory changes value, so you want to use the @ operator. But this is only legal with scalar values and packed arrays. Using the earlier examples, you can block on the variable lw, and barray[0], but not the entire array barray unless you expand it: @(barray[0] or barray[1] or barray[2]).

Previous : Net Type
Next : Dynamic Arrays

SystemVerilog Net Type

In Verilog, Net data types are used to model physical connections. They do not store values (there is only one exception - trireg, which stores a previously assigned value). The net data types have the value of their drivers. If a net variable has no driver, then it has a high-impedance value (z).

Verilog allows you to use nets without defining them, a feature called implicit nets. This shortcut helps net-listing tools and lazy designers, but is guaranteed to cause problems if you ever
misspell a net name in your SystemVerilog code. The solution is to disable this language feature with the Verilog-2001 compile directive: ‘default_nettype none. Put this (without a period) before the first module in your Verilog code. Any implicit net will cause a compilation error.

Previous : SystemVerilog Strings
Next : Fixed Size Array

SystemVerilog Strings

String data type is used for storing strings, the size is dynamic and string data types come with build in methods. If you have ever tried to use a Verilog reg variable to hold a string of characters, your suffering is over with this post. The SystemVerilog string type holds variable-length strings. String literals are packed arrays of a width that is a multiple of 8 bits which hold ASCII values i.e. an individual character is of type byte. The elements of a string of length N are numbered 0 to N-1. Note that, unlike C, there is no null character at the end of a string, and any attempt to use the character “\0” is ignored.


string StringName = "VLSI Encyclopedia";

Strings use dynamic memory allocation, so you do not have to worry about running out of space to store the string. Example 1 shows various string operations.

Below is the list of string methods :
  • str.len() returns the length of the string, i.e., the number of characters in the string. 
  • str.putc(i, c) replaces the ith character in str with the given integral value. 
  • str.getc(i) returns the ASCII code of the ith character in str. 
  • str.toupper() returns a string with characters in str converted to uppercase. 
  • str.tolower() returns a string with characters in str converted to lowercase. 
  • str.compare(s) compares str and s, and return value. This comparison is case sensitive. 
  • str.icompare(s) compares str and s, and return value .This comparison is case insensitive. 
  • str.substr(i, j) returns a new string that is a substring formed by index i through j of str. 
  • str.atoi() returns the integer corresponding to the ASCII decimal representation in str. 
  • str.atoreal() returns the real number corresponding to the ASCII decimal representation in str. 
  • str.itoa(i) stores the ASCII decimal representation of i into str (inverse of atoi). 
  • str.hextoa(i) stores the ASCII hexadecimal representation of i into str (inverse of atohex). 
  • str.bintoa(i) stores the ASCII binary representation of i into str (inverse of atobin). 
  • str.realtoa(r) stores the ASCII real representation of r into str (inverse of atoreal)

Example 1: SystemVerilog String Methods


// SystemVerilog Strings
module str; 
  string S1; 
  string S2; 
  initial begin 
    S1 = "VLSI "; 
    S2 = "Encyclopedia"; 
    $display(" %d ",S1.len() ); 
    $display(" %s ",S2.getc(5) ); 
    $display(" %s ",S1.tolower); 
    $display(" %s ",S2.toupper); 
    $display(" %d ",S2.compare(S1) ); 
    $display(" %d ",S1.compare("VLSI") ); 
    $display(" %s ",S1.substr(2,3) ); S1 = "111"; 
    $display(" %d ",S1.atoi() ); 
  end 
endmodule 

Simulation Result :

 5
 l
 vlsi
 ENCYCLOPEDIA
 -17
 1
 SI
 111

Pattern Matching of SystemVerilog Strings
In below example we have used a method to match the strings in SystemVerilog.

Example 2 : Pattern matching


// SystemVerilog String Pattern Matching
 
program main; 
  string S1,S2; 
  initial begin 
    S1 = "String matching in SystemVerilog"; 
    S2 = "String"; 
    if(match(S1,S2)) 
      $display(" S2 : %s : found in :%s:",S2,S1); 

    S2 = "SystemVerilog"; 
    if(match(S1,S2)) 
      $display(" S2 : %s : found in :%s:",S2,S1); 

    S2 = "String matching"; 
    if(match(S1,S2)) 
      $display(" S2 : %s : found in :%s:",S2,S1); 

    S2 = "matching in "; 
    if(match(S1,S2)) 
      $display(" S2 : %s : found in :%s:",S2,S1); 

    S2 = "String matching in SystemVerilog"; 
    if(match(S1,S2)) 
      $display(" S2 : %s : found in :%s:",S2,S1); 
  end 
endprogram

function match(string s1,s2); 
  int len1,len2; 
  len1 = s1.len(); 
  len2 = s2.len(); 
  match = 0 ; 
  if( len2 > len1 ) 
    return 0; 
  for(int i = 0;i < len1 - len2 + 1; i ++) 
    if( s1.substr(i,i+len2 -1) == s2) 
  return 1; 
endfunction

Simulation Results:
 S2 : String : found in :String matching in SystemVerilog:
 S2 : SystemVerilog : found in :String matching in SystemVerilog:
 S2 : String matching : found in :String matching in SystemVerilog:
 S2 : matching in  : found in :String matching in SystemVerilog:
 S2 : String matching in SystemVerilog : found in :String matching in SystemVerilog:

SystemVerilog operations
There are variety of operations associated with SystemVerilog strings that you can perform to manipulate the  combination of string variables and string literals. Below are the basic operation that can be performed on strings.

1. Checking equality of two strings : S1 == S2
Checks whether the two strings are equal. Checking equality results 1 if they are equal and 0 if they are unequal. Both strings can be of type string. Or one of them can be a string literal. If both operands are string literals, the operator is the same Verilog equality operator as for integer types.

Example 3 : Checking Equality

// SystemVerilog Strings Equality
module str; 
  string S1 = "VLSI Encyclopedia"; 
  string S2 = "VLSI Encyclopedia";
  string S3 = "vlsi encyclopedia";
  initial begin 
    if(S1 == S2) 
      $display(" S1 and S2 are equal"); 
    else 
      $display(" S1 and S2 are not equal"); 
    if(S1 == S3) 
      $display(" S1 and S3 are equal"); 
    else 
      $display(" S1 and S3 are not equal"); 
  end 
endmodule 

Simulation Results 
S1 and S2 are equal
S1 and S3 are not equal

2. Checking equality of two strings : S1 != S2
Reverse to the equality operation this operation results 0 if two strings are equal and 1 if they are unequal.

Example 4: Checking Inequality

// SystemVerilog Strings Equality
module str; 
  string S1 = "VLSI Encyclopedia"; 
  string S2 = "VLSI Encyclopedia";
  string S3 = "vlsi encyclopedia";
  initial begin 
    if(S1 != S2) 
      $display(" S1 and S2 are not equal"); 
    else 
      $display(" S1 and S2 are equal"); 
    if(S1 != S3) 
      $display(" S1 and S3 are not equal"); 
    else 
      $display(" S1 and S3 are equal"); 
  end 
endmodule 

Simulation Results 
S1 and S2 are equal
S1 and S3 are not equal

3. Concatenation of strings : {S1, S2, S3,...,Sn}
To concatenate two or more strings, specify the string variable inside {} each separated by comma",". Each operand can be of type string or a string literal.

Example 5 : Concatenation


// SystemVerilog Strings Concatenation
module str; 
  string S1, S2, S3, S4, S5; 
  initial begin 
    S1 = "Con"; 
    S2 = "cate"; 
    S3 = ""; 
    S4 = "na"; 
    S5 = "tion"; 
    $display(" %s ",{S1,S2,S3,S4,S5}); 
  end 
endmodule 

Simulation Results
Concatenation

4. Replication of Strings : {N{S1}}
The result of replication is a string containing N concatenated copies of S1. N is the multiplier ans S1 can be of string type or string literal.

Example 6 : Replication

// SystemVerilog Strings Replication
module str; 
  string S1, S2; 
  initial begin 
    S1 = "w"; 
    S2 = ".vlsiencyclopedia.com"; 
    $display(" %s ",{{3{S1}},S2}); 
  end 
endmodule 

Simulation Results :
www.vlsiencyclopedia.com

5. String Indexing : S1[Index]
It returns a byte, an ASCII code at the given Index. Index can range from 0 to N where N is the number of characters in the string. If the Index is out of range then result will be 0.

Example 7 : Indexing

// SystemVerilog Strings Indexing
module str; 
  initial begin
    string S1; 
   S1 = "Indexing"; 
  for(int i =0 ;i < 8 ; i++) 
    $display("%s ",S1[i]); 
  end 
endmodule 

Simulation Result :
I
n
d
e
x
i
n
g

Previous : SystemVerilog Constants
Next : Net Type

SystemVerilog Constants

In previous post of this SystemVerilog Tutorial we talked about enumerated type in detail. Now we will look at the constants in SystemVerilog. There are several types of constants in systemVerilog. The classic Verilog way to create a constant is with a text macro. 

On the plus side, macros have global scope and can be used for bit field definitions and type definitions.
On the negative side, macros are global, so they can cause conflicts if you just need a local constant. 
Lastly, a macro requires the ` character so that it will be recognized and expanded.

In SystemVerilog, parameters can be declared at the $root level so they can be global. This approach can replace many Verilog macros that were just being used as constants. You can use a typedef to replace those large macros. The next choice is a parameter. A Verilog parameter was loosely typed and was limited in scope to a single module. Verilog-2001 added typed parameters, but the limited scope kept parameters from being widely used.

SystemVerilog allows you to declare constant identifiers. You can declare an identifier as constant by prefixing the usual identifier definition with the keyword const. At the time of defining a constant, the user needs to provide a value for the identifier. At any later stage in the code, a SystemVerilog compiler disallows any modification to the value bound to the identifier.


// Constant bit 
const bit [63:0] data_bus='hB6AB31E0;
// Constant int bus width
const int bus_width = 8;
// Constant String VLSI Encyclopedia
const string name = "VLSI Encyclopedia";
// Constant method
function int count (const ref bytes[]);

In addition to a normal identifier declaration, the const modifier can be used to declare function/task arguments as constants. An argument to a function may be of either a pass-by-value or pass-by-reference type. When using pass-by-value semantics, the const modifier has the usual meaning; the locally bound parameter's value can not be changed in the given function.

When using pass-by-reference semantic (as is the case with const ref arrays), the SV compiler ensures that the referenced value is not modified by the code in the function. Normally arrays (even dynamic ones) are passed by value. 

Since arrays could be very big, SystemVerilog allows you to declare an array parameter type as a reference, by prefixing the function parameter with keyword ref. But this introduces the danger of a user inadvertently altering the arrays (actually it's elements) value. By prefix const to the reference array parameter, you can avoid this danger. The compiler would ensure that inside the function, a user can not alter the arrays value.

Note :
Constant identifiers in SystemVerilog are not compile time constants. As a result it is not allowed to use a constant as a range parameter for an array. This is much unlike C++, wherein constants are compile time constants. As an alternative, SystemVerilog users are allowed to use parameters (aka parameterized functions and classes) as range specifiers for an array.

Previous : SystemVerilog Enumerated Types
Next : SystemVerilog Strings

SystemVerilog Enumerated Types

An enumeration creates a strong variable type that is limited to a set of specified names such as the instruction opcodes or state machine values. Using these names, such as ADD, MOVE, or STATE, makes your code easier to write and maintain than using literals such as 8’h01.

The simplest enumerated type declaration contains a list of constant names and one or more variables. This creates an anonymous enumerated type.

Example 1:
A simple enumerated type

enum {RED, BLUE, GREEN} color;

You usually want to create a named enumerated type to easily declare multiple variables, especially if these are used as routine arguments or module ports. You first create the enumerated type, and then the variables of this type.

You can get the string representation of an enumerated variable with the function name().

Example 2: Enumerated Type

module enum_method; 
  typedef enum {RED,BLUE,GREEN} colour; 
  colour c; 
  initial begin 
    c = c.first(); 
    $display(" %s ",c.name); 
    c = c.next(); 
    $display(" %s ",c.name); 
    c = c.last(); 
    $display(" %s ",c.name); 
    c = c.prev(); 
    $display(" %s ",c.name); 
  end 
endmodule 

Output :
RED
BLUE
GREEN
BLUE


Defining enumerated values

The actual values default to integers starting at 0 and then increase. You can choose your own enumerated values. The below line uses the default value of 0 for RED, then 2 for BLUE, and 3 for GREEN.

typedef enum {RED, BLUE=2, GREEN} color_e;

Enumerated constants, such as RED above, follow the same scoping rules as variables. Consequently, if you use the same name in several enumerated types (such as RED in different state machines), they have to be declared in different scopes such as modules, program blocks, routines, or classes.

Enumerated types are stored as int unless you specify otherwise. Be careful when assigning values to enumerated constants, as the default value of an int is 0. In Example 3 below, position is initialized to 0, which is not a legal ordinal_e variable. This behavior is not a tool bug – it is
how the language is specified. So always specify an enumerated constant with the value of 0, just to catch this error.

Example 3 Incorrectly specifying enumerated values

typedef enum {FIRST=1, SECOND, THIRD} ordinal_e;
ordinal_e position;


Example 4 Correctly specifying enumerated values

typedef enum {ERR_O=0, FIRST=1, SECOND, THIRD} ordinal_e;
ordinal_e position;

Enumerated methods : Methods associated with enumerated types

SystemVerilog also includes a set of specialized methods0 associated with enumerated types to enable iterating over the values of enumerated. 

The first() method returns the value of the first member of the enumeration. 

The last() method returns the value of the last member of the enumeration. 

The next() method returns the Nth next enumeration value (default is the next one) starting from the current value of the given variable. 

The prev() method returns the Nth previous enumeration value (default is the previous one) starting from the current value of the given variable. 

The name() method returns the string representation of the given enumeration value. If the given value is not a member of the enumeration, the name() method returns the empty string.

The functions next() and prev() wrap around when they reach the beginning or end of the enumeration.

Note that there is no easy way to write a for loop that steps through all members of an enumerated type if you use an enumerated loop variable. You get the starting member with first() and the next() member with next(). The problem is creating a comparison for the final iteration through the loop. If you use the test current!=current.last, the loop ends before using the last value. If you use current<=current.last, you get an infinite loop, as next never gives you a value that is greater than the final value. You can use a do...while loop to step through all the values.

Converting to and from enumerated types

The default type for an enumerated type is int (2-state). You can take the value of an enumerated variable and put it in an integer or int with a simple assignment. But SystemVerilog does not let you store a 4-state integer in an enum without explicitly changing the type. SystemVerilog requires you to explicitly cast the value to make you realize that you could be writing an out-of-bounds value.

Example 5:  Assignments between integers and enumerated types


module enum_method; 
  typedef enum {RED, BLUE, GREEN} COLOR_E;
  COLOR_E color, c2;
  integer c;
  initial begin
    c = color; // Convert from enum to integer
    c++; // Increment integer
    if (!$cast(color, c)) begin // Cast integer back to enum
      $display("Cast failed for c=%0d", c);
    end
    $display("Color is %0d & %0s", color, color.name);
    c2 = COLOR_E'(c); // No type checking done
  end

endmodule 

Output : 
Color is 1 & BLUE

Run Simulation


In above Example 5, $cast tried to assign from the right value to the left. If the assignment succeeds, $cast returns 1. If the assignment fails because of an out-of-bounds value, no assignment is made and the function returns 0. If you use $cast as a task and the operation fails, SystemVerilog prints an error.

You can also cast the value using the type’(val) as shown above, but this does not do any type checking, so the result may be out of bounds. You should not use this style.

Previous : SystemVerilog Built-in Data Types
Next : SystemVerilog Constants

SystemVerilog Built-In Data Types

Verilog-1995 has two basic data types: variables (reg) and nets, that hold four-state values: 0, 1, Z, and X. RTL code uses variables to store combinational and sequential values. Variables can be unsigned single or multi-bit (reg [7:0] m), signed 32-bit variables (integer), unsigned 64-bit variables (time), and floating point numbers (real). Variables can be grouped together into arrays that have a fixed size. All storage is static, meaning that all variables are alive for the entire simulation and routines cannot use a stack to hold arguments and local values. A net is used to connect parts of a design such as gate primitives and module instances. Nets come in many flavors, but most designers use scalar and vector wires to connect together the ports of design blocks.

SystemVerilog adds many new data types to help both hardware designers and verification engineers.

The logic type

The one thing in Verilog that always leaves new users scratching their heads is the difference between a reg and a wire. When driving a port, which should you use? How about when you are connecting blocks? System-Verilog improves the classic reg data type so that it can be driven by continuous assignmentsgates and modules, in addition to being a variable. It is given the new name logic so that it does not look like a register declaration. The one limitation is that a logic variable cannot be driven by multiple drivers such as when you are modeling a bidirectional bus. In this case, the variable needs to be a net-type such as wire.

Example: shows the SystemVerilog logic type.
module logic_data_type(input logic rst_h);
  parameter CYCLE = 20;
  logic q, q_l, d, clk, rst_l;

initial begin
  clk <= 0; // Procedural assignment
  forever #(CYCLE/2) clk = ~clk;
end

assign rst_l = ~rst_h; // Continuous assignment
not n1(q_l, q); // q_l is driven by gate
my_dff d1(q, d, clk, rst_l); // d is driven by module

endmodule

Two-state types

SystemVerilog introduces several two-state data types to improve simulator performance and reduce memory usage, over four-state types. The simplest type is the bit, which is always unsigned. There are four signed types: byte, shortint, int, and longint.

shortint i                // 2-state, 16-bit signed
int i                        // 2-state, 32-bit signed
longint i                 // 2-state, 64-bit signed
byte b                    // 2-state, 8-bit signed
bit b;                      // 2-state, single-bit
bit [31:0] b32;       // 2-state, 32-bit unsigned


Tips:
You might be tempted to use types such as byte to replace more verbose declarations such as logic [7:0]. Hardware designers should be careful as these new types are signed variables, so a byte variable can only count up to 127, not Chapter 2: Data Types 29 the 255 you may expect. (It has the range -128 to +127.) You could use byte unsigned, but that is more verbose than just bit [7:0]. Signed variables may cause unexpected results with randomization, as discussed in Chapter 6. Be careful connecting two-state variables to the design under test, especially its outputs. If the hardware tries to drive an X or Z, these values are converted to a two-state value, and your testbench code may never know. Don’t try to remember if they are converted to 0 or 1; instead, always check for propagation of unknown values. Use the $isunknown operator that returns 1 if any bit of the expression is X or Z.

Example: Checking for four-state values

if ($isunknown(iport)
$display("@%0d: 4-state value detected on input port",
$time, iport);

Next : SystemVerilog Enumerated Types

Button-Size Wearable Computer by Intel

button_by_intelIt just got a lot easier to build wearable gadgets that aren’t so bulky or awkward.

Intel CEO Brian Krzanich showed off a minuscule computer, dubbed Curie, during a keynote speech at the International Consumer Electronics Show in Las Vegas on Tuesday. Krzanich plucked a button off his blazer before explaining that it contained a Curie demo module.

Curie is a sure sign that hardware makers are eager to build wearable devices of all kinds. It also points to the unwelcome size of many existing smart watches and smart glasses.

Intel’s new device will include a Bluetooth low-energy radio, motion sensors, and components designed to rapidly and precisely differentiate between different types of physical activity. Krzanich said Curie will run “for extended periods of time” on a coin-size battery and would be available in the second half of the year.

Curie appeared much smaller than a postage-stamp-size computer, called Edison, that Krzanich showed off at last year’s CES.

The world’s largest chip maker evidently sees wearables as one of the most important categories in consumer electronics. It’s a belief held by a lot of other companies at CES, where gadgets meant to be worn on the body or clipped to clothing were all over the show floor this year (see “CES 2015: Wearables Everywhere”).

To make it clear that Curie is already functional, the company built a simple step-tracking smartphone app to go with the module Krzanich had on him; at one point he pulled the phone out of his pocket, and its display indicated he’d taken 1,788 steps during the keynote.

As part of its wearables push, Intel has partnered with a number of companies in the fashion and accessories businesses, including Luxottica Group, which is the world’s largest eyeglass maker with brands such as Ray-Ban and Oakley. Krzanich said Luxottica will use Curie to make “truly consumer-friendly” smart glasses—a notoriously tricky thing to do, in part because of the size of components needed to make them work.

Oakley CEO Colin Baden joined Krzanich on stage to talk about wearables, which Oakley has built in the form of devices like ski goggles that include a head-up display. When you put a wearable device on your face, Baden said, it becomes part of your personality. “It’s important the form factor compress so the electronic component of it doesn’t become burdensome,” he said.

Popular Posts