HomeSystemVerilog VerificationDay 3 — Arrays
DAY 3 · SV FUNDAMENTALS

SystemVerilog Arrays, Queues & Associative Arrays — Complete Guide

By EcrioniX · Updated Jun 12, 2026

SystemVerilog arrays are far more powerful than anything Verilog offered. The language gives you five distinct array types — fixed-size, packed, unpacked, dynamic, queue, and associative — each designed for different verification patterns. Choosing the right one for your testbench makes the difference between clean, efficient code and a mess of manual size management.

SYSTEMVERILOG ARRAY TYPES FIXED PACKED DYNAMIC QUEUE ASSOCIATIVE int a[8] logic[7:0] b int d[] int q[$] int aa[string] Fixed size Compile time Bits in a word Synthesizable new[N] resize TB only push/pop FIFO TB only Hash map Sparse data

What is the difference between packed and unpacked arrays?

This is the most confusing distinction in SystemVerilog arrays, and getting it wrong causes subtle bugs. The rule: packed dimensions come before the variable name (they describe the bits within a single element), while unpacked dimensions come after the variable name (they describe the number of elements).

Packed arrays — bits within a single element

A packed array is a contiguous sequence of bits that can be treated as a single integer value. You can index individual bits, do arithmetic on the whole thing, and assign it to/from integers directly. Packed arrays are synthesizable and commonly used in RTL.

Unpacked arrays — collections of elements

An unpacked array is a collection of elements. Each element is a separate thing in simulation memory. You cannot directly assign an unpacked array to an integer. $size(arr) returns the number of elements. $dimensions(arr) returns the total number of dimensions.

Packed vs Unpacked — the key syntax rule

logic [7:0] packed_byte — 8-bit packed vector. ONE element, 8 bits wide.

logic [7:0] mem [0:15] — 16 unpacked elements, each 8 bits wide. A memory array.

logic [7:0] matrix [4][8] — 4×8 unpacked array of bytes. 32 elements total.

What is a SystemVerilog dynamic array and when should you use it?

A dynamic array (type[]) is an unpacked array whose size is not known at compile time. You allocate it at runtime with new[N], and you can resize it later with another new[N] (the old contents are preserved if the new size is larger — or copied into an existing array). Use dynamic arrays when you need indexed random access to all elements and the size is determined at runtime (e.g., read from a file, passed as a parameter).

Dynamic array operations

OperationSyntaxNotes
Allocatearr = new[N]Creates N elements, zero-initialized
Allocate + copyarr = new[N](old_arr)Copy old_arr into first elements of new array
Get sizearr.size()Returns current number of elements
Delete (free)arr.delete()Frees memory, size becomes 0
Indexarr[i]0 to arr.size()-1

What is a SystemVerilog queue and how does it work?

A queue (type[$]) is a dynamically-sized ordered list that supports efficient insertion and deletion from both ends. It is the natural choice for stimulus queues, scoreboards, FIFOs, and any testbench structure that needs to add/remove elements in order. Unlike dynamic arrays, queues do not require new[] — they auto-resize.

Queue operations — the complete API

MethodDescriptionComplexity
q.push_back(item)Add item to the end (tail)O(1)
q.push_front(item)Add item to the front (head)O(1)
q.pop_back()Remove and return tail itemO(1)
q.pop_front()Remove and return head itemO(1)
q.size()Number of elements currently in queueO(1)
q.delete()Delete all elementsO(N)
q.delete(i)Delete element at index iO(N)
q.insert(i, item)Insert item before index iO(N)
q[i]Random access by indexO(1)
q[$]Last element (shorthand for q[q.size()-1])O(1)
q[0:3]Slice: elements 0 through 3 as a queueO(N)

What is a SystemVerilog associative array used for?

A SystemVerilog associative array (type[key_type]) is a hash map that stores sparse data indexed by any integral type or string. Unlike fixed arrays, no memory is allocated for unused keys — ideal for sparse memories, coverage maps, and per-ID scoreboards in testbenches.

Associative array operations

MethodDescription
aa.exists(key)Returns 1 if key exists, 0 otherwise — ALWAYS check before reading
aa.delete(key)Delete the entry for key
aa.delete()Delete all entries
aa.size()Number of entries currently stored
aa.first(key)Set key to the first (smallest) key; returns 1 if exists
aa.last(key)Set key to the last (largest) key
aa.next(key)Advance key to the next entry; returns 1 if a next exists
aa.prev(key)Step key back to previous entry
foreach(aa[k])Iterate over all keys in ascending order

SystemVerilog array methods — sum, min, max, find, unique

SV provides a rich set of built-in array manipulation methods available on fixed, dynamic, and queue arrays. The with clause lets you filter or transform elements inline.

MethodReturnsDescription
.sum()element typeSum of all elements. Use with: .sum() with (item > 0 ? item : 0)
.product()element typeProduct of all elements
.min()queue of typeReturns a queue containing the minimum value(s)
.max()queue of typeReturns a queue containing the maximum value(s)
.find()queue of typeReturns elements matching the with clause
.find_index()queue of intReturns indices of matching elements
.find_first()queue of typeReturns first matching element
.find_last()queue of typeReturns last matching element
.unique()queue of typeReturns elements with unique values
.unique_index()queue of intReturns indices of unique elements
.sort()voidSort array in ascending order (in place)
.rsort()voidSort array in descending order
.reverse()voidReverse array order in place
.shuffle()voidRandomly shuffle elements in place

How does foreach work vs a regular for loop?

foreach(arr[i]) automatically iterates over every valid index of the array without needing to know its size. For multi-dimensional arrays, use foreach(matrix[i,j]). It works on all array types including queues and associative arrays. Use for when you need explicit index control (counting backwards, skipping elements). Use foreach for clean iteration over all elements.

Complete arrays demonstration — all types with testbench use cases

arrays_demo.sv
// ============================================================
// arrays_demo.sv — All SV Array Types with TB Use Cases
// EcrioniX · SV Verification Course · Day 3
// ============================================================
module arrays_demo;

  // ---- 1. FIXED-SIZE ARRAY ----
  int fixed_arr [8];          // 8 ints, indices 0..7
  logic [7:0] mem [0:255];    // 256-byte memory model (unpacked)

  // ---- 2. PACKED ARRAY ----
  logic [31:0] word;          // 32-bit packed vector — one element, 32 bits
  logic [3:0][7:0] quad_byte; // 4 bytes packed as one 32-bit value

  // ---- 3. DYNAMIC ARRAY ----
  int dyn[];                  // dynamic array of int, size unknown at compile time

  // ---- 4. QUEUE — stimulus and scoreboard ----
  int           stim_q  [$];  // stimulus queue
  logic [7:0]   sb_q    [$];  // scoreboard FIFO

  // ---- 5. ASSOCIATIVE ARRAY — coverage map ----
  int           cov_map  [string];    // hit count per scenario name
  logic [31:0]  sparse_mem [logic [31:0]]; // sparse address-mapped memory

  initial begin
    // ---- Fixed array: initialize and sum ----
    foreach (fixed_arr[i]) fixed_arr[i] = i * 2;
    $display("Fixed sum = %0d", fixed_arr.sum());  // 0+2+4+6+8+10+12+14 = 56

    // ---- Packed array: bit-level access ----
    word = 32'hDEAD_BEEF;
    $display("Byte 3 of word: 8'h%0h", word[31:24]);  // DE
    $display("Byte 0 of word: 8'h%0h", word[7:0]);    // EF
    quad_byte = 32'h01020304;
    $display("quad_byte[0] = %0h, [3] = %0h", quad_byte[0], quad_byte[3]); // 04, 01

    // ---- Dynamic array: allocate, use, resize ----
    dyn = new[4];
    foreach (dyn[i]) dyn[i] = i + 100;
    $display("dyn.size() = %0d", dyn.size());  // 4
    dyn = new[8](dyn);   // resize to 8, preserve existing 4 elements
    $display("after resize, dyn.size() = %0d", dyn.size()); // 8
    $display("dyn[0]=%0d  dyn[4]=%0d", dyn[0], dyn[4]);    // 100  0
    dyn.delete();
    $display("after delete, dyn.size() = %0d", dyn.size()); // 0

    // ---- Queue: stimulus FIFO ----
    // Build a stimulus queue of transactions to send
    stim_q.push_back(8'hAA);
    stim_q.push_back(8'hBB);
    stim_q.push_front(8'h00);  // priority: put 0x00 first
    $display("Queue size = %0d", stim_q.size()); // 3
    while (stim_q.size() > 0) begin
      automatic int item = stim_q.pop_front();
      $display("Sending: 8'h%0h", item);   // 00, AA, BB
    end

    // Queue slice and unique
    int vals[$] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
    $display("min = %0d, max = %0d", vals.min()[0], vals.max()[0]);  // 1, 9
    $display("sum = %0d", vals.sum());     // 39
    vals.sort();
    $display("sorted[0..3] = %0d %0d %0d %0d", vals[0],vals[1],vals[2],vals[3]);
    automatic int uniqs[$] = vals.unique();
    $display("unique count = %0d", uniqs.size()); // 7

    // find_with: filter elements > 4
    automatic int big[$] = vals.find() with (item > 4);
    $display("elements > 4: %0d entries", big.size());

    // ---- Associative array: coverage hit counter ----
    cov_map["reset_test"]   = 0;
    cov_map["burst_wr_test"] = 0;
    cov_map["idle_test"]    = 0;

    cov_map["reset_test"]++;
    cov_map["burst_wr_test"] += 3;

    // Iterate over all entries
    foreach (cov_map[scenario]) begin
      $display("Coverage[%s] = %0d hits", scenario, cov_map[scenario]);
    end

    // Check before accessing to avoid phantom entries
    if (cov_map.exists("unknown_test"))
      $display("unknown_test hit count: %0d", cov_map["unknown_test"]);
    else
      $display("unknown_test not in map (size stays %0d)", cov_map.size());

    // ---- Sparse memory model ----
    sparse_mem[32'h4000_0000] = 32'hDEAD_BEEF;
    sparse_mem[32'hFFFF_0000] = 32'hCAFE_BABE;
    $display("sparse_mem.size() = %0d (only 2 entries allocated)", sparse_mem.size());

    $display("\nAll array demos complete.");
    $finish;
  end

endmodule

Day 3 takeaways

Frequently Asked Questions

What is the difference between packed and unpacked arrays in SystemVerilog?

Packed arrays have their dimensions before the variable name (logic [7:0] byte_val) — they are contiguous bits treated as a single value, and they are synthesizable. Unpacked arrays have their dimensions after the name (logic [7:0] mem [256]) — they are collections of separate elements. Think packed = "bits of a word", unpacked = "array of words".

When should I use a queue vs a dynamic array in SystemVerilog?

Use a queue when you need to add/remove from either end (stimulus FIFO, scoreboard). push/pop are O(1). Use a dynamic array when you allocate once with a known size and need indexed random access. Dynamic arrays don't support efficient front insertion. In most TB code, queues are the right default.

What is a SystemVerilog associative array used for?

Associative arrays are hash maps — perfect for sparse memories (logic[31:0] mem[logic[31:0]]), coverage hit counters (int cov[string]), and per-ID scoreboards (Packet sb[int]). Only allocated entries consume memory. Always use .exists(key) before reading, or you'll accidentally create entries.

How do I use array methods like sum() and find() in SystemVerilog?

arr.sum() sums all elements directly. arr.find() with (item > 5) returns a queue of elements where the with clause is true. arr.min()[0] and arr.max()[0] return a 1-element queue containing the min/max — take [0] to get the value. arr.sort() sorts in place. These work on fixed, dynamic, and queue arrays.

Previous
← Day 2: SV Data Types

← Full course roadmap