SV9. SystemVerilog Packed vs. Unpacked arrays
Ever wondered how packed vs. unpacked arrays really work in SystemVerilog? This article dives into the syntax, memory layout, and use cases of both - with practical examples and code walkthroughs.
Video Tutorial
Watch this comprehensive video explanation of Implicit Net Declaration:
Packed and Unpacked Arrays in SystemVerilog
Packed Arrays (Sub-fields)
Packed arrays are treated as contiguous sets of bits. They are ideal for modeling hardware registers and buses since the bits are stored together in memory.
Example
logic [1:0][15:0] bus_w; // 32-bit bus: two 16-bit vectors
logic [15:0] data16;
assign data16 = bus_w[1]; // Get upper 16 bits
assign a = bus_w[0][15]; // Access bit 15 of lower half
Explanation:
bus_w
is a 2D packed array: 2 elements, each 16 bits wide.- Packed dimensions are declared to the left of the variable name.
- The total width of
bus_w
is 32 bits, and operations like slicing or bit selection are straightforward.
Unpacked Arrays
Unpacked arrays represent data where each element can be accessed individually, and each element may itself be a vector. Unlike packed arrays, they are not stored contiguously in memory and are more flexible in size and shape. The hardware implementation depends on synthesis tools and can be similar to packed arrays.
Examples
logic [31:0] mem [0:3]; // 4 elements, each 32 bits
logic [15:0] data2d [0:3][0:1]; // 2D array, 4 rows x 2 columns of 16-bit vectors
logic [7:0] data2d [4][2]; // Same as above, different index
logic data [0:3]; // 4 elements, each 1 bit
Accessing Elements
logic [31:0] data32;
logic [7:0] data8;
data32 = mem[2]; // Reads the third 32-bit word
data8 = data2d[2][1]; // Reads from row 2, column 1 (8-bit value)
List Initialization
SystemVerilog provides a concise way to assign values using list syntax:
logic [31:0] d0, d1, d2, d3;
mem = '{32'h0000_0000, 32'h1111_1111, 32'h2222_2222, 32'h3333_3333};
mem = '{d0, d1, d2, d3}; // Uses previously assigned values
2-D List Assignment
logic [15:0] data2d [0:3][0:1];
data2d = '{
'{8'h00, 8'h01},
'{8'h02, 8'h03},
'{8'h04, 8'h05},
'{8'h06, 8'h07}
};
Equivalent to:
data2d[0][0] = 8'h00;
data2d[0][1] = 8'h01;
// ...
data2d[3][1] = 8'h07;
Default Initialization
Need to zero-out an entire memory? SystemVerilog makes it easy:
logic [31:0] mem [0:3];
mem = '{default: '0};
This assigns 0
to each of the four 32-bit elements in mem
.
Mixed Packed-Unpacked Arrays
Consider the following example:
logic [2:0][7:0] mem [4];
Let’s break it down:
[2:0][7:0]
: This is a 2-dimensional packed array.[7:0]
: 8-bit field (byte).[2:0]
: 3 elements of 8 bits each → forms a 24-bit wide vector.
mem [4]
: Unpacked array of 4 elements.
Meaning:
mem
is an array of 4 elements (mem[0]
tomem[3]
).- Each element is a 24-bit vector composed of three packed 8-bit segments.
Assignment Example
mem[1] = 24'hcd_ef12; // The underscore _ is for readability
This effectively does:
mem[1][2] = 8'hCD; // Most significant byte
mem[1][1] = 8'hEF;
mem[1][0] = 8'h12; // Least significant byte
Sub-field Operations
mem[3][2][7:4] = mem[0][1][3:0];
Here, we are copying the lower 4 bits of mem[0][1]
(middle byte of the first element) into the upper 4 bits of mem[3][2]
(MSB byte of the last element).