Different Array Types and Queues in System Verilog
In short: SystemVerilog gives you four main array types beyond the fixed size array: the dynamic array (size set at run time with new[]), the associative array (sparse, indexed by any key such as a string), the queue (an ordered list that grows and shrinks with push and pop), and each has its own methods. Pick the dynamic array when the size is known only at run time, the associative array when the index range is huge but mostly empty, and the queue when you push and pop from the ends.
A fixed size array is fine when you know the count up front. But testbenches often do not know the count until the simulation runs, or need to look up data by an odd key, or need a list that changes length while it runs. SystemVerilog covers those needs with three flexible array types. This guide shows each one, its methods, and when to reach for it.
A simple way to picture it
Think of three ways to store books. A dynamic array is like a shelf where you decide the width when you install it, then keep everything in a neat row. An associative array is like a library card catalog: you look up a book by its title, not by shelf position, and most possible titles do not exist. A queue is like a line of people at a counter: new people join at either end and leave from either end, and the line length changes all the time.
Quick comparison of the array types
| Type | Size set when | Index type | Best for |
|---|---|---|---|
| Fixed size | Compile time | Integer, contiguous | Counts known up front |
| Dynamic array | Run time via new[] | Integer, contiguous | Size known only at run time |
| Associative array | Grows as keys are added | Any type: int, string, class | Sparse or huge index space |
| Queue | Grows and shrinks freely | Integer, contiguous | Push and pop from the ends |
Dynamic arrays
A dynamic array has a size you set at run time with the new[] operator. It stores its elements in a contiguous row and is indexed by an integer. You can resize it and even copy the old contents into the larger one in the same call.
module dyn_demo;
int data[]; // unsized at first
initial begin
data = new[4]; // allocate 4 elements
foreach (data[i]) data[i] = i * 10;
$display("size = %0d", data.size()); // 4
data = new[6](data); // resize to 6, keep old values
$display("after resize size = %0d, data[1] = %0d", data.size(), data[1]);
data.delete(); // empty it
$display("after delete size = %0d", data.size()); // 0
end
endmoduleThe key methods are size() to read the current length and delete() to empty the array and set its size to zero. Passing the old array name inside new[6](data) copies the existing values into the resized array.
Associative arrays
An associative array is the right choice when the index space is very large but only a few entries are used. Memory is only used for entries you actually write. The index can be an integer, a string, or another scalar type, so it works well as a lookup table.
module assoc_demo;
bit [7:0] age [string]; // indexed by a string key
initial begin
age["tom"] = 21;
age["joe"] = 32;
$display("entries = %0d", age.num()); // 2
if (age.exists("tom"))
$display("tom is %0d", age["tom"]); // 21
// Walk entries in key order
string k;
if (age.first(k))
do $display("%s -> %0d", k, age[k]);
while (age.next(k));
age.delete("joe");
$display("after delete entries = %0d", age.num()); // 1
end
endmoduleAssociative array methods
| Method | What it returns or does |
|---|---|
num() or size() | Number of entries currently stored |
exists(key) | 1 if an entry exists at that key, else 0 |
delete(key) | Removes one entry, or all if no key is given |
first(ref k) / last(ref k) | Gets the smallest or largest key |
next(ref k) / prev(ref k) | Steps to the next or previous key in order |
Queues
A queue is an ordered list of the same element type that can grow and shrink while the simulation runs. Unlike a dynamic array, it does not need new[]. You add and remove items with push and pop, and you can insert or delete at any position.
module queue_demo;
string q[$] = {"first", "second", "third"};
string item;
initial begin
q.push_back("fourth"); // add at the end
q.push_front("zero"); // add at the front
$display("size = %0d", q.size()); // 5
item = q.pop_front(); // remove from the front
$display("popped front = %s", item); // zero
item = q.pop_back(); // remove from the end
$display("popped back = %s", item); // fourth
q.insert(1, "inserted"); // insert at index 1
q.delete(0); // delete index 0
foreach (q[i]) $display("q[%0d] = %s", i, q[i]);
end
endmoduleNote the difference from the original example many people copy: always index the same queue variable you declared. A common typo is popping from q but printing from a differently named variable, which will not compile.
Queue methods at a glance
| Method | What it does |
|---|---|
push_back(x) / push_front(x) | Add x at the end or the front |
pop_back() / pop_front() | Remove and return the end or front element |
insert(i, x) | Insert x at index i |
delete(i) | Delete the element at index i |
size() | Current number of elements |
Expected output, in plain words
The dynamic array example allocates four elements, then resizes to six while keeping the first four, so the size prints 4 then 6, and delete brings it back to 0. The associative array example stores two named ages, confirms tom exists, walks the keys in order, then drops one entry. The queue example ends with five items, pops the two ends you added, then inserts and deletes to leave a short ordered list.
Note: these outputs describe what the code is written to produce based on a read of the IEEE 1800 LRM. Compile and run on your own simulator or EDA Playground for a true sign off.
When to use which array
- Fixed size array: the count is known at compile time and never changes.
- Dynamic array: the count is known only at run time, for example after reading a config or a file, and the data sits in a contiguous block.
- Associative array: the index range is huge or sparse, such as a memory model keyed by a wide address, or a lookup keyed by a string.
- Queue: you push and pop from the ends, such as a scoreboard holding expected transactions waiting to be matched.
Common mistakes to avoid
- Forgetting
new[]on a dynamic array: using it before allocation leaves it size zero and indexing fails. - Using an associative array where a queue fits: if you only add and remove at the ends, a queue is simpler and faster.
- Reading a missing associative key: check with
exists()first, or you may read a default zero and think the entry was real. - Mismatched variable names in queue loops: pop from and print the same queue variable, or the code will not compile.
- Assuming order in an associative array: walk it with
firstandnextif you need a defined order.
Dynamic array vs queue
Both grow at run time, so which do you pick? Use a dynamic array when you set the size once and then index it like a block of memory. Use a queue when the length changes often through push and pop, such as a buffer of pending items. The queue also gives you insert and delete at any index without a manual copy.
For more on the operator that packs these collections into a stream, see our guide on the streaming operator. To pass a queue of items between two threads, read about the SystemVerilog mailbox. More tutorials are in our SystemVerilog section and interview questions.
Frequently asked questions
Arrays and queues store values of a base type, so it helps to be solid on the logic data type that most of these arrays hold.
What are the array types in SystemVerilog?
Beyond the fixed size array there are three flexible types: the dynamic array sized at run time with new[], the associative array indexed by any key for sparse data, and the queue which grows and shrinks with push and pop.
What is the difference between a dynamic array and a queue?
A dynamic array is sized with new[] and used like a contiguous block of memory. A queue does not need new[]; it grows and shrinks through push and pop, and supports insert and delete at any index.
When should I use an associative array?
Use it when the index space is very large or sparse, such as a memory model keyed by a wide address, or a lookup keyed by a string. Memory is used only for entries you actually write.
How do I resize a dynamic array and keep the data?
Call new with the old array inside the parentheses, for example data = new[6](data). This resizes to six elements and copies the existing values into the new array.
How do I safely read an associative array?
Check the key first with exists(key). If you read a missing key you get a default value such as zero, which can look like a real entry. Use first and next to walk keys in order.
What are the main queue methods?
push_back and push_front add items, pop_back and pop_front remove and return items, insert adds at an index, delete removes at an index, and size returns the current count.


