Queues in SystemVerilog

In SystemVerilog, a queue is a variable-size, indexed data structure that can grow or shrink as elements are added or removed. Unlike fixed-size arrays, queues are highly flexible, making them an ideal choice for implementing FIFO (First-In, First-Out) structures and various temporary storage needs in verification environments. This data structure allows for dynamic resizing, enabling easy addition and removal of elements, which makes it especially suitable for applications where the number of stored items may vary during runtime.

A queue in SystemVerilog is defined as follows:

data_type queue_name[$];

Here, data_type is the type of elements that the queue will hold, and $ indicates that the queue size is dynamic. Queues in SystemVerilog support random access by index and provide several built-in methods to manipulate elements.

Creating and Initializing a Queue

You can create a queue by declaring it with square brackets and a dollar sign ([$]), which signifies its dynamic size. A queue can be bounded or unbounded. Bounded queue means queue size is specified or no of entries are limited whereas unbounded queue means queue size is not specified. Here’s an example:

int my_queue[$];    // Declares a queue of integers  (unbounded queue)
bit queue_1[$:127]  // queue of bits  (Bounded queue with 128 entries)

To initialize the queue with values, you can use assignments as shown below:

my_queue = {1, 2, 3, 4};  // Initializes the queue with values 1, 2, 3, and 4

Methods Available for Queues in SystemVerilog

SystemVerilog offers a variety of methods to perform different operations on queues. These methods make it easy to insert, delete, and retrieve elements as well as manipulate the queue structure.

1. Size Method

The size method returns the current number of elements in the queue. It’s helpful when you need to know the queue length, especially since queues are dynamic.

int count = my_queue.size();

2. Insert Method

The insert method allows you to add an element at a specified index. This is particularly useful if you want to insert elements at any position, not just at the end.

my_queue.insert(index, value);

For Example:

my_queue.insert(1, 10);  // Inserts the value 10 at index 1

3. Delete Method

The delete method removes elements from the queue. You can either delete an element at a specific index or delete a range of elements.

  • Delete by index:
my_queue.delete(index);
  • Delete a range of elements:
my_queue.delete(start_index, end_index);

For Example:

my_queue.delete(2);        // Deletes the element at index 2
my_queue.delete(1, 3);     // Deletes elements from index 1 to 3

4. Push Back Method

The push_back method appends an element to the end of the queue, making it easy to add elements sequentially.

my_queue.push_back(value);

Example:

my_queue.push_back(5);  // Adds the value 5 to the end of the queue

5. Push Front Method

The push_front method inserts an element at the beginning of the queue. This is useful if you want to treat the queue as a stack or need to prioritize new data at the front.

my_queue.push_front(value);

Example:

my_queue.push_front(0);  // Inserts 0 at the beginning of the queue

6. Pop Back Method

The pop_back method removes the last element in the queue. It’s particularly useful for queue operations that require removing items from the end.

int last_element = my_queue.pop_back();

7. Pop Front Method

The pop_front method removes the first element from the queue, allowing for FIFO behavior.

int first_element = my_queue.pop_front();

8. Sort Method

The sort method arranges the elements in ascending order, which can be helpful when order matters.

my_queue.sort();

Example: Using a Queue in SystemVerilog

Here’s a practical example that demonstrates the use of some common queue methods:

module queue_example;
  int my_queue[$];
  int removed_element;

  initial begin
    my_queue = {10, 20, 30};       // Initializing queue with values
    my_queue.push_back(40);         // Adding an element at the end
    my_queue.push_front(5);         // Adding an element at the beginning
    
    $display("Queue: %p", my_queue);  // Displays the queue
    
    removed_element = my_queue.pop_front();
    $display("Removed element: %0d", removed_element); // Displays removed element

    my_queue.insert(2, 15);         // Inserts 15 at index 2
    my_queue.delete(3);             // Deletes the element at index 3
    my_queue.sort();                // Sorts the queue

    $display("Sorted Queue: %p", my_queue);
  end
endmodule

Output:

Queue: '{5, 10, 20, 30, 40} 
Removed element: 5
Sorted Queue: '{10, 15, 20, 40}

Conclusion

Queues in SystemVerilog offer an efficient and flexible way to manage collections of data that need to change in size during runtime. By understanding and utilizing the built-in methods like size, push_back, push_front, pop_back, pop_front, insert, delete, find, unique, and sort, you can easily manage queue elements for various verification and modeling purposes.

System Verilog queues bring powerful tools to your coding arsenal, making it easier to build and manipulate complex data structures required in modern digital design verification.