System Verilog : Queues

In your system verilog code, if extraction and insertion order of array elements are important, `queue` would be the best option. A queue is a variable-size, ordered collection of homogeneous elements. It is declared using the same syntax as unpacked arrays, but specifying $ as the array size. It is analogous to a one-dimensional unpacked array that grows and shrinks automatically. So like arrays, queues can be manipulated using concatenation, slicing, indexing and quality operators.

Each element in a queue is identified by an ordinal number that represents its position within the queue. In this 0 represents the first and $ represents the last. Insertion and deletion of elements from random locations using an index are also possible with queues.

Bounded queues
Queue size can be limited by giving the last index (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.

module queue_check;

//Declaration
int q_int[$];              //queue of integer
logic [31:0] q_logic [$];  // queue of 32 bit logic
integer q_integer[$:9];    // queue of integers with max 10 elements
int i;


initial begin

 //Adding and updating elements using unpacked array concatenation
 q_int = {500,1000,1500,2000};
 q_logic = {1,0,0,0,0,0,1,1,1,1,0};
 q_integer = {10,20,40,50};

 $display("q_int: %0d : %0d : %0d: %0d",q_int[0],q_int[1],q_int[2],q_int[3]);
 
 //Read first item from the queue
 i = q_int[0];
 $display("q_int -First item: %0d",i);
 
 //Read last item from the queue
 i = q_int[$];
 $display("q_int -Last item : %0d",i);
 
 //Delete last item from the array
 q_int = q_int[0:$-1];
 $display("q_int -Deleted last item: %0d : %0d : %0d : %0d",q_int[0],q_int[1],q_int[2],q_int[3]);
 
 //Write first item in the queue
 q_int[0] = 250;
 $display("q_int -Inserted first item: %0d",q_int[0]);
 
 //Write last item in the queue
 q_int[$] = 2500;
 $display("q_int -Inserted last item: %0d",q_int[$]);
 
 //Delete entire array
 q_int = {};
 $display("q_int -After deletion %0d",q_int.size);

 //size of q_integer
 $display("q_integer -size %0d",q_integer.size);
 
 
 //q_integer = {10,20,30,40,50,60,70,80,90,100,0}; //Warning: Unpacked array concatenation contains too many queue elements.
						 //Warning: SystemVerilog queue overflow beyond 10 items, tail entry lost


 $display("q_integer -Before insertion: %0d : %0d : %0d : %0d :%0d",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4]);
 
 //Insertion using concatenation
 q_integer = {q_integer[0:1], 30, q_integer[2:$] }; 
 $display("q_integer -After insertion: %0d : %0d : %0d : %0d :%0d",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4]);
 
 q_integer = {10,20,30,40,50,60,70,80,90,100};
 $display("q_integer -new size %0d",q_integer.size);
 
 //Read second element from q_logic
 $display("q_logic %0b",q_logic[1]);

end
endmodule
/*
ncsim> run
q_int: 500 : 1000 : 1500: 2000
q_int -First item: 500
q_int -Last item : 2000
q_int -Deleted last item: 500 : 1000 : 1500 : 0
q_int -Inserted first item: 250
q_int -Inserted last item: 2500
q_int -After deletion 0
q_integer -size 4
q_integer -Before insertion: 10 : 20 : 40 : 50 :x
q_integer -After insertion: 10 : 20 : 30 : 40 :50
q_integer -new size 10
q_logic 0
ncsim: *W,RNQUIE: Simulation is complete.
*/

There are some built in methods available in queue to do insertion, deletion, pushing, popping etc, without using the above methods.

Queue Methods
size() :
The size() method returns the number of items in the queue. If the queue is empty, it returns 0.

module queue_check1;

//Declaration
int q_int[$];              //queue of integer
logic [31:0] q_logic [$];  // queue of 32 bit logic
integer q_integer[$:9];    // queue of integers with max 10 elements

initial begin

 q_int = {500,1000,1500,2000};
 q_logic = {1,0,0,0,0,0,1,1,1,1,0};
 q_integer = {10,20,40,50};

 for ( int j = 0; j < q_int.size; j++ ) $display( "q_int : %0d",q_int[j] ); 
 for ( int j = 0; j < q_integer.size; j++ ) $display( "q_integer : %0d",q_integer[j] ); 
 
 $display("size of queues q_int size : %0d, q_integer size : %0d, q_logic size : %0d",q_int.size,q_integer.size,q_logic.size);

end
endmodule
/*
ncsim> run
q_int : 500
q_int : 1000
q_int : 1500
q_int : 2000
q_integer : 10
q_integer : 20
q_integer : 40
q_integer : 50
size of queues q_int size : 4, q_integer size : 4, q_logic size : 11
ncsim: *W,RNQUIE: Simulation is complete.
*/

insert():
The insert() method inserts the given item at the specified index position.

function void insert (int index, qtype item);  inserts an item at the index location insert() 

If the index argument has any bits with unknown (x/z) value, or is negative, or is greater than the current size of the queue, then the method call shall have no effect on the queue and may cause a warning to be issued.

module queue_insert_check;

integer q_integer[$];  

initial begin

 q_integer = {10,20,40,50};

 $display("q_integer -Before insertion: %0d : %0d : %0d : %0d :%0d",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4]);
 
 q_integer.insert(2,30); 
 $display("q_integer -After insertion: %0d : %0d : %0d : %0d :%0d",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4]);

end
endmodule
/*
ncsim> run
q_integer -Before insertion: 10 : 20 : 40 : 50 :x
q_integer -After insertion: 10 : 20 : 30 : 40 :50
ncsim: *W,RNQUIE: Simulation is complete.
*/

delete():
The delete() method deletes the item at the specified index. Index is optional. If index is not specified, entire elements in the queue will get deleted leaving the queue empty.

If the index argument has any bits with unknown (x/z) value, or is negative, or is greater than or equal to the current size of the queue, then the method call shall have no effect on the queue and may cause a warning to be issued.

module queue_delete_check;

integer q_integer[$];   

initial begin

 q_integer = {10,20,30,40,50};
 $display("q_integer -Before deletion: %0d : %0d : %0d : %0d :%0d",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4]);
 
 q_integer.delete(2); 
 $display("q_integer -After deletion of one element: %0d : %0d : %0d : %0d :%0d",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4]);

 q_integer.delete(); 
 $display("q_integer -After deletion: %0d : %0d : %0d : %0d :%0d",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4]);

end
endmodule
/*
ncsim> run
q_integer -Before deletion: 10 : 20 : 30 : 40 :50
q_integer -After deletion of one element: 10 : 20 : 40 : 50 :x
q_integer -After deletion: x : x : x : x :x
ncsim: *W,RNQUIE: Simulation is complete.
*/

pop_front():
The pop_front() method removes and returns the first element of the queue.

pop_back():
The pop_back() method removes and returns the last element of the queue.

push_front():
The push_front() method inserts the given element at the front of the queue.

push_back():
The push_back() method inserts the given element at the end of the queue.

module queue_push_pop_check;

integer q_integer[$];   
integer i;

initial begin

 q_integer = {10,20,30,40,50,60};
 $display("q_integer: %0d : %0d : %0d : %0d :%0d\n",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4]);
 
 i = q_integer.pop_front(); 
 $display("pop_front return: %0d",i);
 $display("q_integer : After pop_front: %0d : %0d : %0d : %0d :%0d \n",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4]);

 i = q_integer.pop_back(); 
 $display("pop_back return: %0d",i);
 $display("q_integer : After pop_back: %0d : %0d : %0d : %0d :%0d\n",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4]);

 q_integer.push_front(70); 
 $display("q_integer : After push_front: %0d : %0d : %0d : %0d :%0d\n",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4]);

 q_integer.push_back(80); 
 $display("q_integer : After push_back: %0d : %0d : %0d : %0d :%0d :%0d\n",q_integer[0],q_integer[1],q_integer[2],q_integer[3],q_integer[4],q_integer[5]);
end
endmodule
/*
ncsim> run
q_integer: 10 : 20 : 30 : 40 :50

pop_front return: 10
q_integer : After pop_front: 20 : 30 : 40 : 50 :60 

pop_back return: 60
q_integer : After pop_back: 20 : 30 : 40 : 50 :x

q_integer : After push_front: 70 : 20 : 30 : 40 :50

q_integer : After push_back: 70 : 20 : 30 : 40 :50 :80

ncsim: *W,RNQUIE: Simulation is complete.
*/

4 comments on “System Verilog : Queues

  1. Ramya

    Hi,
    I’m trying to use struct as data type in queues. Like as shown below:

    typedef struct {bit[31:0] addr, bit[3:0] id, bit[63:0] data; bit flag}
    packet_t;

    packet_t q1 [$];

    I want to populate the addr everytime a new addr comes in, like:

    if (intf.a && intf.b)begin
    q1.push_front.addr = intf.address;
    q1.push_front.id = intf.id;
    end

    I would like to store the addr and id in the same item (index) of the queue.
    (On the next cycle, if intf.a and intf.b evaluate to True, I want to store the id and addr as the second queue item)

    Will the above code achieve the intent?
    Are there examples of using struct as data type in queues and manipulating them?

    When data arrives(along with data id), I plan to use the “find_first with” to find the queue item that matches with the id to store the data into.

    Please let me know your inputs.

    Thanks!
    Ramya

    Reply
  2. Sai Ganesh

    If i want to store the value into the queue which is data_in of asynchronous fifo. What i have to do? please tell me i am a learner. This is to check whether the output and input are same.

    Reply
  3. shankar

    Hi Mam,

    I need to check the elements of the queue . how to do that
    and also Please let me know what is the operation of find_index with and find _index method

    Thanks,
    Shanar

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *