SystemVerilog Basics Part 1
SystemVerilog Basics Part 1
Basics
Part 1
Daniyal Tahsildar
Disclaimer:
Welcome to this educational document! Here, you'll find a comprehensive
overview of various SystemVerilog concepts, accompanied by example code. Each
topic is conveniently linked to its corresponding code repository on GitHub. Look
for a symbol! Babu’s symbol
Please note that this document is designed solely for educational purposes, aiming
to provide foundational knowledge of SystemVerilog concepts.
All code snippets included have been thoroughly tested using tools such as Mentor
Questa 2021.3 and Synopsys VCS 2021.03, available on EDA Playground.
If you seek a deeper understanding of the topics covered in this document, please
refer the SystemVerilog reference manual. This document primarily serves to
provide a foundational understanding of these concepts.
Your feedback, input, and critique are highly valued! Feel free to connect with me
on LinkedIn or via Email to share your thoughts.
Page | 1
Contents
Data types .................................................................................................................................. 4
1. Integral Data Types ......................................................................................................... 4
2. Real Data Types .............................................................................................................. 4
3. String Data Type ............................................................................................................. 4
4. Enum Datatype................................................................................................................ 6
5. User Defined Data Types ................................................................................................ 6
6. Structure (struct) Data Type ............................................................................................ 7
7. Void Data Type................................................................................................................ 8
Operators ................................................................................................................................... 9
1. Concatenation Operator .................................................................................................. 9
2. Replication Operator ..................................................................................................... 10
3. Wildcard Equality Operator .......................................................................................... 10
4. Set Membership Operator ............................................................................................. 11
5. Streaming Operator ....................................................................................................... 12
Arrays ...................................................................................................................................... 14
1. Packed Arrays ............................................................................................................... 14
2. Unpacked Arrays........................................................................................................... 14
3. Multidimensional arrays (array of arrays) .................................................................... 14
3.1. Multidimensional array allocation ......................................................................... 15
4. Static Arrays .................................................................................................................. 16
5. Dynamic Arrays ............................................................................................................ 16
5.1. Dynamic Array Allocation ..................................................................................... 16
5.2. Dynamic Elements in Dynamic Arrays (e.g., Class Instances) ............................. 17
5.3. Dynamic Array Methods ........................................................................................ 17
6. Queues........................................................................................................................... 18
6.1. Queue Methods ...................................................................................................... 19
7. Associative array........................................................................................................... 20
7.1. Why Use Associative Arrays ................................................................................. 20
7.2. Associative Array Methods .................................................................................... 21
Page | 2
8. Common array manipulation methods.......................................................................... 22
8.1. Array locator methods............................................................................................ 23
8.2. Array ordering methods ......................................................................................... 24
8.3. Array reduction methods........................................................................................ 25
9. Printing arrays ............................................................................................................... 25
9.1. Printing Entire Array .............................................................................................. 25
9.2. Printing Single Elements........................................................................................ 26
10. String formatting in arrays ........................................................................................ 26
Page | 3
Data types
A data type serves as a classification defining the kind of data a variable can hold and
the operations that can be performed on that data. For instance, in SystemVerilog, data types
such as logic, real, and string specify the nature of the information stored within variables.
Page | 4
len():
Returns the count of characters in a string.
putc():
Substitutes a character in the string at the specified index passed as the putc() argument. Does
not change the size of the string only
replaces characters.
getc():
Retrieves a character (ASCII value) from the string
at the specified index provided as the getc()
argument.
toupper():
Converts all characters in a string to uppercase and returns it.
tolower():
Converts all characters in a string to lowercase and returns it.
compare():
Compares two strings. Returns 0 since both the strings
are identical or the difference in ASCII values if strings
are different.
icompare():
Performs a case-insensitive comparison of two strings,
disregarding upper and lower cases.
Additionally, the following functions are used to convert ASCII characters to numbers
(integers), which proves useful when conducting file handling operations with characters as
numbers in the file.
atoreal():
Converts ASCII to real and returns values.
atoi():
Converts ASCII to integer and returns values.
itoa():
Converts integer to ASCII values and stores in the string.
Page | 5
4. Enum Datatype
SV introduces a concept called enum enabling users to represent numbers in words,
enhancing code readability without altering functionality. Instead of numerical values, words
can be used.
Syntax: enum {enum_word_1 = value, enum_word_2 = value, …….} enum_name
The value parameter is optional and if not specified, it starts from 0 for enum_word_1, 1 for
enum_word_2 and so forth.
For example:
In this example, default values for SMALL is 0, MEDIUM is 1, and LARGE is 2.
Specific values can be assigned as follows:
The values of the enum type are derived from the value of the first element. If the first
enum_word value is 4, subsequent enum_word values will increment accordingly if not
specified.
For example:
Page | 6
typedef can also be used to create an array of class data type:
Here, class_array stores data of the class_name type, enabling the storage of multiple
instances of a class within an array. This approach proves beneficial in scoreboarding logic,
where multiple data transactions need to be compared. Instead of storing class data in separate
arrays, a single array of class type can be utilized, where different elements can be accessed
through array indexing.
This defines a struct named data_set consisting of three elements. Now, this struct data type
can be utilized to create an array:
Here, data_setQ collectively refers to a queue of data_set instances, with each data_set
containing three elements.
While classes serve a similar purpose, they are dynamic in nature, requiring memory
allocation. In contrast, structs are static and lack tasks, functions, or constraints.
Accessing struct fields is done using the '.' operator, such as struct_name.field_name.
Page | 7
For example:
When a function is intended to perform a task without returning any data, the return_data_type
is set as void. This ensures that the function does not produce any output data.
Page | 8
Operators
1. Concatenation Operator
Concatenation refers to the process of combining bits from one or more expressions into
a single entity. In SV, concatenation supports the merging of bit streams, integers, strings, and
arrays (with only one element of the array usable, not the entire array).
It is required to use variables with bounded sizes in concatenations. This ensures that
the tool can calculate the complete size of the concatenation accurately. If unbounded size
variables are used in concatenations, the tool defaults to the size of the left-hand side (LHS)
variable, potentially overwriting existing elements within the concatenation.
For example:
Part selection within a concatenation operation is also possible but restricted to the right-hand
side (RHS) concatenation.
Page | 9
Do keep in mind that it is essential to avoid using unbounded values during concatenation.
A concatenation of data objects of type string is allowed. If any operand is a string, the
concatenation is treated as a string, with all other arguments being converted to string data
type. The destination variable (of type string) is resized to accommodate the resulting string
(dynamic nature).
2. Replication Operator
Replication involves duplicating a specified number of copies of a concatenation. The
replication operator assigns vectors with the necessary number of 1s and 0s based on the vector
size.
The syntax for replication is: {replication_constant {value}}
For example:
Page | 10
a ==? b: Indicates that a equals b, with X and Z values in b acting as wildcards. Positions with
X or Z bits in b (RHS expression) will not be compared.
Wildcard Inequality Operator (!=?):
a !=? b: Indicates that a does not equal b, with X and Z values in b acting as wildcards. If a
(LHS expression) has X or Z, the output of the comparison will be X.
Page | 11
When used in a constraint block in class:
5. Streaming Operator
Streaming operators perform the packing and unpacking of bit-stream types into a
sequence of bits in a user-specified order. When applied to the left-hand side, streaming
operators perform the reverse operation by unpacking a stream of bits into one or more
variables.
The output of streaming operators is always a queue when it is on the RHS. These operators
are crucial in packing large bit streams into queues of bytes, bits or user specified size.
Syntax: Q_name = {>> / << data_type_size {stream_data}}
The >> or << stream operators determine the order in which blocks of data are streamed.
>> causes blocks of data to be streamed in a left-to-right order, while << causes blocks of data
to be streamed in a right-to-left order. In the case of right-to-left streaming using <<, the order
of blocks in the stream is reversed.
The data_type_size determines the size of each block, measured in bits. It can be any integral
type (bit, byte, int, etc.) and can also be user-defined using typedef.
Example:
Using typedef:
In this example, the streaming operator extracts data from the queue shift_Q and assigns it to
variables num_combined_1 and num_combined_2.
Page | 13
Arrays
Arrays can be categorized based on how memory is allocated, leading to two primary
classifications: Packed arrays and Unpacked arrays.
1. Packed Arrays
In the case of Packed arrays, similar to Verilog vectors, memory is allocated in a single
address location for the entire array. The array dimensions are declared before the array name,
and the data type is restricted to bit, logic, or reg. Packed arrays, representing singular data
variables stored in a single address location, support all SV operations.
Example:
2. Unpacked Arrays
Unpacked arrays resemble traditional verilog arrays as memory is distributed across
multiple address locations. The number of locations corresponds to the size of the array, with
each location having a size equal to the array's data type (32bit for int type, 4bit for logic [3:0]
etc). Array dimensions are declared after the array name, and there are no restrictions on data
type; any SV data type can be employed. Unpacked arrays may be fixed size arrays, dynamic
arrays, associative arrays, or queues.
Example:
However, it's essential to note that unpacked arrays do not support all SV operations.
Unlike Packed arrays, which represent singular data variables, Unpacked arrays represent
multiple address locations and, as a result, only permit whole array operations. While whole
array assignment or comparison is possible, any other operation requires the use of specific
indices.
For example:
Packed 3 4 1 2 Unpacked
dimensions dimensions
This is a multidimensional array with 4 dimensions. This array encapsulates a total of 4*6*8*4
bits, stored across 4*6 addresses, with each location accommodating 8*4 bits.
Unpacked dimensions determine the number of address locations, while packed dimensions
specify the number of bits stored in each location.
Assigning values for multidimensional unpacked arrays is facilitated using {} notation.
For example:
Each number here has its own unique
memory.
Another classification based on memory allocation distinguishes between Static arrays and
Dynamic arrays.
Page | 15
4. Static Arrays
Static arrays have a fixed size allocated at compile time, making them immutable
throughout simulation. They must be declared with a predetermined integer number for the
array size, and they can be both packed and unpacked, including multidimensional arrays.
For example:
foreach() loops are exclusive to static arrays (or arrays with known size) and are utilized for
traversing through elements efficiently. For instance, looping through elements of intA (with
a size of 3) can be achieved with foreach (intA[i]).
Comparing arrays involves the use of assert or if statements. For example:
compares entire arrays, a functionality not available in Verilog.
5. Dynamic Arrays
In contrast, dynamic arrays allocate memory at runtime, allowing for size adjustments
during execution. They necessitate the use of the new[] keyword for memory allocation,
although dynamic arrays can operate without new through array assignment. Unlike static
arrays, the size is not specified during array declaration.
They also offer flexibility in memory management, enabling size increments,
decrements, or deletions during runtime. They are exclusively unpacked arrays; packed arrays
cannot be dynamic.
Associative arrays and queues (discussed later), are also dynamic as they allocate
memory upon usage but do not require new[] for memory allocation. Dynamic arrays can be
assigned to fixed size arrays (static arrays) and vice versa, provided both arrays share a
compatible data type and have the same size.
Here, intDA dynamically adjusts its size to accommodate the elements from intQ (queue) or
intSA (static array) without requiring explicit memory allocation.
Page | 17
delete():
Deletes all contents of a dynamic array. However, there is no built-in method to delete only
one element of a dynamic array.
For example:
size():
Retrieves the size of the dynamic array, returning it as a value. It returns the size as an integer.
For example: If the number of elements in pkt is 5, then
count = 5 here.
6. Queues
A queue represents a variable sized, ordered collection of uniform (homogeneous)
elements. Variable size allows for both expansion and reduction as needed. In addition, the
elements within a queue are ordered, with each element assigned an index starting from 0, and
can be accessed based on index values.
Queues are dynamic data types, and memory allocation does not require the use of the
new[] keyword. They are declared using a syntax similar to unpacked arrays, with the size
specified using $. The maximum size of a queue can be defined by indicating its optional last
index.
The syntax for declaring a queue is: data_type Q_name[$]
Queue declaration examples:
Queues can be compared as a whole, assuming both queues have the same number of
elements. Comparison operations can be performed directly between queues, between a queue
and a dynamic array, or between a queue and a fixed array without the need for a foreach loop.
Page | 18
Queues are particularly valuable in scenarios where the number of elements frequently
grow and shrink, and where users require efficient search and sort functionalities. One such
example is in the implementation of scoreboards.
pop_front():
Removes and returns the first element from the queue.
pop_back():
Removes and returns the last element from the queue.
push_front():
Adds data into the queue at the first index position.
push_back():
Adds data into the queue at the end of the queue.
shuffle():
Shuffles the queue elements in random order.
Page | 19
reverse():
Reverses the order of elements in the queue.
*Note: The data variable used in pop_front(), pop_back(), push_front() and push_back()
needs to be of the same type as the elements in the queue.
7. Associative array
Associative arrays are a type of array where elements are stored and accessed using
corresponding index values. These index values are not required to be continuous and can start
from any value.
Declaration: data_type arr_name[index_type]
Where, data_type represents the type of data stored, and index_type is the lookup key used to
access array elements. Both data_type and index_type can be of any SV data type.
Associative arrays do not require elements to exist at every index, allowing for non-
continuous indexing. In the case of a fixed size array, the index range implies that elements
must exist at all those indices. However, associative arrays have the flexibility to have
elements only at specific indices that are accessed. They behave similar to linked lists and
keep track of next and previous indices.
They are particularly useful for modelling large memories when the user doesn't want
to allocate memory to each location of the memory range. Memory is only allocated for
elements that are accessed, making them more memory efficient.
Associative arrays support various index types such as integer, bit, string, or even class
types. Most commonly, index types are integers, bits, or strings. For string indices, ASCII
values are treated as address values, and for class indices, handle address values are used for
indexing.
Examples of different associative array declarations:
Consider a scenario where testing a very large memory with 1 million addresses is
necessary. To verify its functionality, it's sufficient to write to a few random locations and read
Page | 20
those locations in a random order. In this case, using only 10 addresses for verification suffices.
Challenges with Static Arrays:
Using static arrays poses a problem even when dealing with only 10 addresses. Despite
needing a small subset of addresses, declaring a memory of size 1 million is compulsory. Static
arrays require storing data in a continuous index basis, meaning if location 100 exists,
locations 0 to 99 must also exist, leading to unnecessary memory allocation.
Challenges with Dynamic Arrays:
Similarly, dynamic arrays allow runtime size allocation, but they encounter the same
issue as static arrays. They still require the declaration of a large memory size upfront,
regardless of the actual usage.
The Solution:
A storage method is needed where only assigned locations are allocated, leaving the
remaining memory addresses non-existent. This approach optimizes memory usage, especially
when dealing with vast memory spaces.
Associative arrays offer a solution by creating a linked list of the indices that are used,
allowing for dynamic memory allocation based solely on the utilized addresses. In contrast to
static or dynamic arrays, where elements are stored in continuous address locations,
associative arrays store elements at discrete locations. Therefore, indexing becomes a crucial
aspect of accessing elements within associative arrays.
Associative arrays can only be assigned to another associative array of a compatible
type and with the same index type. Other types of arrays cannot be assigned to an associative
array, nor can associative arrays be assigned to other types of arrays, whether fixed-size or
dynamic.
delete():
Allows deletion of either all array elements or a specific element.
Deleting all elements:
Page | 21
Deleting a specific element:
Returns 0 if the index 23 is not present in the
array, otherwise, deletes the element at index
23 and returns 1.
exists():
Checks if an element exists at a given index.
Returns 1 if index 6 exists; otherwise, returns 0.
first():
Returns the first index value in the array and assigns it to
index_name.
Index can be declared as int, string, etc.
last():
Returns the last index value in the array and assigns it to
index_name
next():
index_name needs to be initialized to an index value present
in the associative array. Returns the next index value in the
array for a given index_name.
prev():
Returns the previous index value in the array for a given
index_name. index_name needs to be initialized to an index
value present in the associative array.
Page | 22
8.1. Array locator methods
These methods return a queue containing the elements that fulfil the specified criteria.
The return type of the index method varies depending on the array iterator items: for most
arrays, it's an integer, while for associative arrays, it matches the associative index type. It's
important to note that associative arrays with a wildcard index type ([*]) are not permitted.
Here are the key array locator methods:
All the following methods require a with() clause, not using with() will cause an error
find():
Returns all elements satisfying the given expression.
find_first():
Returns the first element satisfying the given expression.
find_last():
Returns the last element satisfying the given expression.
find_index():
Returns the indices of all elements satisfying the given expression.
find_first_index():
Returns the index of the first element satisfying the given expression.
Page | 23
find_last_index():
Returns the index of the last element satisfying the given expression.
unique():
Returns all elements with unique values. The returned queue
contains only one entry for each unique value found in the
array.
unique_index():
Returns the indices of all elements with unique values.
Page | 24
8.3. Array reduction methods
Array reduction methods are used to condense arrays with integral values into a single
value. with() can be used with all of them.
sum():
Returns the sum of all the array elements.
product():
Returns the product of all the array elements.
and():
Returns the bitwise AND of all the array elements.
or():
Returns the bitwise OR of all the array elements.
xor():
Returns the bitwise XOR of all the array elements.
9. Printing arrays
Printing arrays in SV can be done efficiently using the packed print method (%p), which
prints the entire array in a single line, starting from the most significant bit (MSB) side.
Additionally, printing individual elements is also feasible.
This line prints the entire array intA1 in a single line, starting from the MSB side.
Page | 25
9.2. Printing Single Elements
If you wish to print specific elements of the array, you can specify the index within square
brackets []:
Here, intA1[0] denotes the element at index 0 of the array intA1. Using %d, the value of this
specific element is printed.
In this loop, i iterates from 1 to 10, and for each iteration, the $sformatf function formats the
string according to the pattern "str%0d", where %0d represents a placeholder for the integer
i. This results in strings like "str1", "str2", and so forth being assigned to elements of the names
array.
Additionally, you can use $sformat which is string format task:
Page | 26