Day 22 — SystemVerilog Language: Collections
Implement safe dynamic arrays, queues, associative maps, enum/struct/union models, and a packet database.
Concept lesson
Understand the language feature before coding
Day 22 — SystemVerilog Collections
Simulation status (28 Oct 2026): The full tb/day22_collections.sv passes on Verilator 5.052; Icarus Verilog 12 runs only the tb/day22_collections_icarus.sv subset. Details: Week 5 validation record (VALIDATION.md).
Schedule: 2h theory + 2h guided + 2h independent + 1h debug. Deliverable: SV collections utility.
Choose a collection by its access pattern
| Collection | Use it when | Boundary to check |
|---|---|---|
| Fixed unpacked array | The number of elements is known and stable. | The declared index range may not start at zero. |
| Dynamic array | The size is decided or changed at run time. | Allocate before indexing; check size() after resize or delete. |
| Queue | Items are added and removed in order, such as expected transactions. | Check size() before indexing or popping an empty queue. |
| Associative array | Sparse keys need direct lookup, such as address-to-value state. | Use exists(key) before treating a missing entry as valid data. |
Packed dimensions form one bit vector; unpacked dimensions hold separate
elements. A packed struct is useful when fields form one bit-level record,
while an unpacked array or queue is useful when the testbench needs a
collection of records. Prefer foreach when iterating declared dimensions,
and guard collection methods whose result depends on an empty or missing
element. The exercises below demonstrate these operations; they are not a
claim that every simulator supports every collection method.
Workspace
project_workspace/week5_systemverilog/day22_collections
Guided (1–5)
- Dynamic array allocation/resizing.
- Queue push/pop/insert/delete.
- Queue search/sort.
- Associative address map.
foreachtraversal.
Independent (6–11)
- enum opcode; 7. struct packet; 8. union storage; 9. reductions; 10. transaction queue; 11. scoreboard-style associative store.
Additional XLS lab catalog
20 exercises are enumerated in WEEK5_DAY22_LAB_CATALOG including dynamic delete, queue reverse, associative exists/delete, array min/max, unique/find, and empty-queue debug. These are requirements; the supplied demonstration is not proof that all 20 are executed.
Demo
Run .venv/bin/python scripts/check_week5_simulator.py --simulator iverilog --run for the Icarus-compatible queue/packed-struct subset. Icarus does not support all dynamic-array, associative-array and array-ordering features in the full tb/day22_collections.sv. Run the full exercise on Verilator 5: verilator --binary --timing --top-module day22_collections tb/day22_collections.sv -o day22_sim, then ./obj_dir/day22_sim. Capture version, compilation log, PASS/FAIL output and debug evidence.
Debug
Show unsafe empty-queue access, then correct it with size() guard; document index-range checks for dynamic arrays.
Boundary
No UVM, SVA, constrained random or Week 6 interfaces.
Visual explanation
Connect syntax with simulator behavior
Worked example
Read and run the supplied SystemVerilog source
Example source · Day 22
module day22_collections;
typedef enum int {OP_READ=0, OP_WRITE=1} opcode_t;
typedef struct packed {logic [7:0] addr; logic [7:0] data;} packet_t;
typedef union packed {logic [15:0] raw; packet_t packet;} packet_union_t;
int dyn[];
int q[$];
int address_map[int];
packet_t transactions[$];
packet_union_t u;
int errors=0;
initial begin
dyn = new[3]; foreach (dyn[i]) dyn[i] = i+1;
dyn = new[5](dyn);
if (dyn.size()!=5 || dyn[0]!=1) errors++;
dyn.delete(); if (dyn.size()!=0) errors++;
q.push_back(3); q.push_front(1); q.insert(1,2);
if(q.size()!=3 || q[1]!=2) errors++;
q.sort(); if(q[0]!=1 || q[2]!=3) errors++;
if(q.size()>0) void'(q.pop_front());
if(q.size()>0) void'(q.pop_front());
if(q.size()>0) void'(q.pop_front());
if(q.size()!=0) errors++;
if(q.size()==0) $display("EMPTY_QUEUE_GUARD PASS");
else errors++;
address_map[32'h1000] = 42;
if(!address_map.exists(32'h1000) || address_map[32'h1000]!=42) errors++;
foreach(address_map[key]) $display("MAP[%0d]=%0d",key,address_map[key]);
address_map.delete(32'h1000);
if(address_map.exists(32'h1000)) errors++;
transactions.push_back('{addr:8'h10,data:8'hA5});
if(transactions.size()!=1 || transactions[0].data!=8'hA5) errors++;
u.raw=16'h1234;
if(u.packet.addr!=8'h12) errors++;
if(errors==0) $display("DAY22 PASS");
else $fatal(1,"DAY22 FAIL errors=%0d",errors);
$finish;
end
endmodule
Compile and run
mkdir -p sim logsverilator --binary --timing --top-module day22_collections tb/day22_collections.sv -o day22_sim./obj_dir/day22_sim | tee logs/day22.log
What to verify
- dynamic allocate/resize/delete
- queue push/pop/insert/delete
- queue sort/search
- associative map exists/delete
- foreach
- enum/struct/union
- reductions
- transaction queue
- scoreboard store
- empty queue guard
Pass condition: Simulation terminates with PASS, zero errors and explicit empty-queue guard evidence.
Hands-on practice
Complete the exercises in order
Written assignment
- Explain dynamic-array resize and preservation of elements.
- Compare queue and associative-array lookup semantics.
- Show empty-queue guard with failing and corrected behavior.
- Provide transaction database output, simulator command and limitations.
Debug challenge
Detect and handle empty-queue and out-of-range access; build packet database utility.
Completion criteria
Eleven daily-plan activities plus 20 XLS SystemVerilog lab mappings documented; guarded queue and packet database demonstrated.
Knowledge check
Check your understanding
How is a dynamic array resized while retaining existing elements?
Use new[new_size](old_array) to copy existing elements into resized storage.
Why check queue size before pop_front()?
An empty queue has no valid element to remove; guard with size() > 0.
How do you check whether an associative-array key exists?
Use array.exists(key) before reading or deleting that key.
How do packed structs differ from unpacked structs?
Packed structs have contiguous packed bit representation; unpacked structs are collections of separately typed members.
When is a queue preferable to a dynamic array?
When elements are frequently inserted or removed at either end.
Why is an associative array useful for a sparse address model?
It allocates entries only for keys that are used.
Evidence to retain
- SV sources
- simulator/version compatibility matrix
- PASS/FAIL log
- packet database output
- debug before/after