The short answer: SystemVerilog adds the 4-state logic type (which replaces most uses of wire and reg), 2-state types (bit, byte, int, longint) for faster testbench code, user-defined types (typedef, enum, struct, union), strings, and three kinds of run-time arrays: dynamic arrays (resized with new[]), queues (grow and shrink at either end) and associative arrays (sparse, indexed by any type). Use 4-state types in RTL so x bugs stay visible, and 2-state or dynamic types in testbenches.
Data types are where SystemVerilog first feels different from Verilog. Some changes make RTL cleaner; most of the new types exist to make testbenches easier to write. This post combines my older posts on data types, enumerations, and dynamic arrays and queues.
- Overview
- logic and the 4-state vs 2-state choice
- enum
- struct and union
- Packed vs unpacked arrays
- Dynamic arrays
- Queues
- Associative arrays
- Which array when?
Table of Contents
Part 1: Overview

Part 2: logic and the 4-state vs 2-state choice
logic [7:0] a; // 4-state, can be assigned from assign or always
bit [7:0] b; // 2-state, starts as 0
int i; // 32-bit signed 2-state
byte c; // 8-bit signed 2-state
b = 8'bx; // becomes 0: x is lost
A logic variable can have only one driver; use a net (wire) for multiply-driven signals like tri-state buses. In RTL I stick to logic, because 2-state types hide uninitialised registers.
Part 3: enum
typedef enum logic [1:0] {IDLE, LOAD, RUN, DONE} state_t;
state_t state, next;
next = state.next(); // methods: first, last, next, prev, num, name
$display("state = %s", state.name());
Enums give states names in waveforms and messages, and assigning a plain number to an enum variable is an error without an explicit cast, which catches mistakes.
Part 4: struct and union
typedef struct packed {
logic [3:0] opcode;
logic [4:0] rd;
logic [22:0] imm;
} instr_t; // 32 bits, can be sliced like a vector
instr_t ins;
assign ins = instr_word;
assign is_load = (ins.opcode == 4'h3);
Packed structs are stored as one vector, so they’re synthesisable and ideal for bus fields and instruction formats. Unpacked structs are for testbenches. Unions give two views of the same bits.
Part 5: Packed vs unpacked arrays
logic [3:0][7:0] word; // packed: 32 contiguous bits, word[2] is a byte
logic [7:0] mem [0:255]; // unpacked: 256 separate bytes
mem = '{default: '0}; // whole-array assignment (SystemVerilog)
Part 6: Dynamic arrays
int data[];
data = new[16]; // 16 elements
data = new[32](data); // resize, keeping the old contents
$display(data.size());
data.delete();
Part 7: Queues
int q[$];
q.push_back(5);
q.push_front(1);
x = q.pop_front();
q.insert(1, 9);
foreach (q[i]) $display(q[i]);
Queues are my default for scoreboards: push expected items at the back, pop them from the front when the actual result arrives.
Part 8: Associative arrays
bit [31:0] mem_model [bit [31:0]]; // indexed by address
mem_model[32'h1000] = 32'hCAFE;
if (mem_model.exists(addr)) rdata = mem_model[addr];
int count_by_name [string];
count_by_name["read"]++;
Only written entries use memory, so they’re perfect for modelling a large address space that is sparsely used.
Part 9: Which array when?
| Need | Use |
|---|---|
| Size known at compile time | Fixed array (packed or unpacked) |
| Size known at run time, then fixed | Dynamic array |
| Items added and removed in order | Queue |
| Sparse data or non-integer keys | Associative array |
Practise this on VLSI Forge
I built VLSI Forge so you can write RTL in your browser, run it on a real simulator and check every signal in the waveform. Free, nothing to install.
Previous in my SystemVerilog series: What is SystemVerilog?. Next: SystemVerilog for RTL design.
FAQ
What is the difference between logic and wire?
logic is a variable type that can be driven by one continuous assign or procedural block; wire is a net that can have multiple drivers and resolves them.
What is the difference between bit and logic?
bit is 2-state (0 and 1, starts as 0); logic is 4-state (0, 1, x, z, starts as x).
When should I use a queue instead of a dynamic array?
When items are added and removed one at a time, like a FIFO or scoreboard. Use a dynamic array when you set the size once.
Are enums and structs synthesisable?
Yes. Enums and packed structs are synthesisable and make RTL much clearer.
