SystemVerilog queue is very powerful data structures that allow you to store elements in a First In, First Out (FIFO) order. The unique feature of a queue is its ability to dynamically change its size, allowing it to store a varying number of elements. Queues in SystemVerilog are highly versatile and can store any type of data. This guide will provide an in-depth understanding of how queues work in SystemVerilog, their types, and their methods.

What is a SystemVerilog Queue?

A SystemVerilog queue is similar to an unpacked array, but with a major difference: its size can grow and shrink automatically. A queue allows you to manipulate its elements using various operations, including indexing, concatenation, and slicing. You can also pass queues to functions or tasks, either as reference (ref) or non-reference (non-ref) arguments.

Types of SystemVerilog Queues

There are two types of queues in SystemVerilog: bounded queues and unbounded queues. Each type has its specific behavior.

Bounded Queue

A bounded queue has a fixed size, meaning you can define the maximum number of elements it can store. Once the queue reaches its maximum size, it cannot accept more elements.

Example of a Bounded Queue:

int bounded_queue [$:10];  // Depth 10

Here, bounded_queue can hold a maximum of 10 elements. It cannot grow beyond this size.

Unbounded Queue

An unbounded queue has no size limit and can store an unlimited number of elements. The size of an unbounded queue grows dynamically as you add more items.

Example of an Unbounded Queue:

int unbounded_queue [$];  // Unlimited entries

The unbounded_queue can grow indefinitely and holds as many elements as required.

Basic Queue Operations

SystemVerilog queues allow you to perform various operations on their elements, such as insertion, deletion, and access. Let’s explore how to use these operations effectively.

Initializing Queues

You can initialize queues with elements, as shown in the following examples:

int q1 [$] = {1, 2, 3, 4, 5}; // Integer queue with initial values
int q2 [$];                    // Empty integer queue
int tmp;                       // Temporary variable to store values

Accessing Elements

To access queue elements, you can use indexing. SystemVerilog supports both regular and reverse indexing for queues.

tmp = q1[0];  // Get the first item of q1 (index 0)
tmp = q1[$];  // Get the last item of q1 (index 4)

Modifying Queue Elements

You can modify elements in a queue as follows:

q2 = q1;          // Copy all elements from q1 to q2
q1 = {};           // Empty the queue (delete all items)
q2[2] = 15;       // Replace element at index 2 with 15
q2.insert(2, 15);  // Insert value 15 at index 2
q2 = {q2, 22};     // Append 22 to the end of q2
q2 = {99, q2};     // Add 99 at the beginning of q2
q2 = q2[1:$];      // Delete the first item
q2 = q2[0:$-1];    // Delete the last item
q2 = q2[1:$-1];    // Delete both the first and last items

Using a Queue in a SystemVerilog Module

Here’s an example of how to use a queue in a SystemVerilog module to display and manipulate queue elements:

module tb;
  // Create a queue that can store "string" values
  string fruits [$] = {"orange", "apple", "kiwi"};

  initial begin
    // Iterate through each queue element
    foreach (fruits[i])
      $display("fruits[%0d] = %s", i, fruits[i]);

    // Display all elements in the queue
    $display("fruits = %p", fruits);

    // Delete all elements in the queue
    fruits = {};
    $display("After deletion, fruits = %p", fruits);
  end
endmodule

Queue Slicing

You can use slice expressions to select a subset of elements in a queue. This is useful when you want to access a range of elements.

$display("citrus fruits = %p", fruits[1:2]);
$display("fruits = %p", fruits[1:$]);

SystemVerilog Queue Methods

SystemVerilog provides several built-in methods to manipulate queues. Below is a table listing the most commonly used methods:

MethodDescription
int size()Returns the number of items in the queue. Returns 0 if empty.
void insert(int index, item)Inserts the item at the specified index position.
void delete(int index)Deletes the element at the specified index. Deletes all if index is not provided.
element_t pop_front()Removes and returns the first element of the queue.
element_t pop_back()Removes and returns the last element of the queue.
void push_front(item)Inserts an item at the front of the queue.
void push_back(item)Inserts an item at the end of the queue.

Example of Queue Operations:

module tb;
  string fruits [$] = {"apple", "pear", "mango", "banana"};

  initial begin
    // size() - Get the size of the queue
    $display("Number of fruits=%0d   fruits=%p", fruits.size(), fruits);

    // insert() - Insert an element at the specified index
    fruits.insert(1, "peach");
    $display("Insert peach, size=%0d fruits=%p", fruits.size(), fruits);

    // delete() - Delete element at the given index
    fruits.delete(3);
    $display("Delete mango, size=%0d fruits=%p", fruits.size(), fruits);

    // pop_front() - Pop the first element
    $display("Pop %s, size=%0d fruits=%p", fruits.pop_front(), fruits.size(), fruits);

    // push_front() - Push a new element at the front
    fruits.push_front("apricot");
    $display("Push apricot, size=%0d fruits=%p", fruits.size(), fruits);

    // pop_back() - Pop the last element
    $display("Pop %s, size=%0d fruits=%p", fruits.pop_back(), fruits.size(), fruits);

    // push_back() - Push an element to the back
    fruits.push_back("plum");
    $display("Push plum, size=%0d fruits=%p", fruits.size(), fruits);
  end
endmodule

Class-Based Queues

SystemVerilog allows you to create queues that hold objects of a class. For example, let’s create a queue of Fruit objects:

class Fruit;
  string name;

  function new(string name="Unknown");
    this.name = name;
  endfunction
endclass

module tb;
  // Create a queue of Fruit objects
  Fruit list [$];

  initial begin
    // Create a new class object for "Apple" and add it to the queue
    Fruit f = new("Apple");
    list.push_back(f);

    // Create another "Banana" object and add it to the queue
    f = new("Banana");
    list.push_back(f);

    // Iterate through the queue and display each fruit's name
    foreach (list[i])
      $display("list[%0d] = %s", i, list[i].name);
  end
endmodule

Queue of Dynamic Arrays

You can also create a queue of dynamic arrays in SystemVerilog. Here’s an example:

typedef string str_da [];

module tb;
  // Create a queue of dynamic arrays
  str_da list [$];

  initial begin
    // Initialize dynamic arrays
    str_da marvel = {"Spiderman", "Hulk", "Captain America"};
    str_da dcWorld = {"Batman", "Superman"};

    // Add dynamic arrays to the queue
    list.push_back(marvel);
    list.push_back(dcWorld);

    // Access elements from the dynamic arrays inside the queue
    foreach (list[i])
      foreach (list[i][j])
        $display("list[%0d][%0d] = %s", i, j, list[i][j]);

    // Print the entire queue
    $display("list = %p", list);
  end
endmodule

Simulation Output

After running the simulations, you will see the following output for various operations:

Number of fruits=4   fruits='{"apple", "pear", "mango", "banana"}
Insert peach, size=5 fruits='{"apple", "peach", "pear", "mango", "banana"}'
Delete mango, size=4 fruits='{"apple", "peach", "pear", "banana"}'
Pop apple, size=3 fruits='{"peach", "pear", "banana"}'
Push apricot, size=4 fruits='{"apricot", "peach", "pear", "banana"}'
Pop banana, size=3 fruits='{"apricot", "peach", "pear"}'
Push plum, size=4 fruits='{"apricot", "peach", "pear", "plum"}'

Conclusion

SystemVerilog queues are powerful, dynamic data structures that offer flexibility in handling a variety of data types. Understanding how to use bounded and unbounded queues, along with the built-in methods, can significantly improve your designs. Whether you’re managing simple data types or complex class objects, SystemVerilog queues provide the tools you need for efficient data storage and manipulation.

Scroll to Top