Introduction
Hardware verification engineers frequently encounter situations requiring systematic data storage and manipulation. Fixed-size arrays provide the foundational mechanism for grouping related data elements under a single identifier. Understanding array operations directly impacts simulation efficiency and code maintainability.
This article examines fixed-size array declarations, initialization techniques, iteration methods, and the critical distinction between packed and unpacked arrays. Readers will gain practical knowledge applicable to testbench development and RTL verification.
(toc) #title=(Table of Content)
What Are Fixed-Size Arrays?
A fixed-size array stores a predetermined number of elements, with the size specified at compile time. SystemVerilog extends the Verilog-1995 array model with C-style declaration shortcuts and multidimensional support.
Declaration Syntax
Two declaration styles exist for one-dimensional arrays:
int lo_hi[0:15]; // Explicit bounds: 16 integers from index 0 to 15
int c_style[16]; // C-style shortcut: 16 integers indexed 0 to 15
Multidimensional arrays use separate dimension specifiers:
int array2 [0:7][0:3]; // 8 rows, 4 columns - verbose style
int array3 [8][4]; // Same dimensions - compact style
array2[7][3] = 1; // Assigning the last element
Unpacked vs Packed Arrays
The storage methodology distinguishes two fundamental array categories.
Unpacked Arrays
Unpacked arrays store each element on a longword (32-bit) boundary. A byte array of three elements occupies three separate longwords, with unused space in each.
bit [7:0] b_unpacked[3]; // Three bytes, each in its own 32-bit word
Packed Arrays
Packed arrays store data as a contiguous set of bits with no unused space. The dimensions appear before the variable name using [lo:hi] format.
bit [3:0] [7:0] bytes; // Four bytes packed into 32 contiguous bits
bytes = 32'hdead_beef; // Assign all bits at once
Array Literals and Initialization
Array literals use an apostrophe followed by curly braces to initialize elements.
int ascend[4] = '{0,1,2,3}; // Initialize all four elements
int descend[5];
int md[2][3] = '{{0,1,2}, {3,4,5}}; // Nested literals for 2D arrays
descend = '{4,3,2,1,0}; // Assign all five elements
descend[0:2] = '{5,6,7}; // Assign first three elements only
ascend = '{4{8}}; // Replication: four copies of value 8
Array Operations Using for and foreach
The for Loop Approach
The $size function returns the total number of elements. Loop variables can be declared local to the loop construct.
initial begin
bit [31:0] src[5], dst[5];
for (int i = 0; i < $size(src); i++)
src[i] = i;
foreach (dst[j])
dst[j] = src[j] * 2;
end
The foreach Loop Syntax
The foreach loop automatically iterates through all array indices. For multidimensional arrays, combine subscripts with a comma rather than separate brackets.
initial begin
int md[2][3] = '{{0,1,2}, {3,4,5}};
foreach (md[i, j]) // Note: comma, not [i][j]
$display("md[%0d][%0d] = %0d", i, j, md[i][j]);
end
Copying and Comparing Arrays
Aggregate operations work on entire arrays without explicit loops. Comparison supports only equality (==) and inequality (!=).
initial begin
bit [31:0] src[5] = '{0,1,2,3,4}, dst[5] = '{5,4,3,2,1};
if (src == dst)
$display("src == dst");
else
$display("src != dst"); // This executes
dst = src; // Aggregate copy all elements
src[0] = 5;
$display("src %s dst", (src == dst) ? "==" : "!="); // !=
$display("src[1:4] %s dst[1:4]",
(src[1:4] == dst[1:4]) ? "==" : "!="); // ==
end
Note: Aggregate arithmetic operations (addition, subtraction) are not supported. Use loops or packed arrays for bitwise logical operations.
Mixed Packed and Unpacked Dimensions
Arrays can combine packed and unpacked dimensions. The unpacked dimension appears after the variable name.
bit [3:0] [7:0] barray [3]; // Three unpacked elements, each containing 32 packed bits
barray[0] = 32'h0123_4567; // Access entire packed element
barray[0][3] = 8'h01; // Access byte within packed element
barray[0][1][6] = 1'b1; // Access individual bit
| Operation | Subscript Count | Result Type |
|---|---|---|
barray[2] |
One | 32-bit packed value |
barray[0][3] |
Two | 8-bit byte |
barray[0][1][6] |
Three | Single bit |
Practical Applications
Memory modeling: Packed arrays efficiently represent register files where word, byte, and bit access are all required.
Testbench stimulus: Fixed-size arrays store expected response vectors for comparison without loop overhead.
Protocol packet construction: Mixed arrays model packet headers with field-level access while maintaining contiguous storage.
Outlook
Modern verification methodologies increasingly rely on dynamic data structures for flexible testbenches. However, fixed-size arrays remain essential for hardware-accurate models, interface definitions, and performance-critical operations where predictable storage layout matters. The packed array capability specifically enables efficient hardware-software co-verification by matching actual memory organization.