Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here5
  • SystemVerilog Language Foundations28
    • SystemVerilog Data Types
    • Arrays: Packed, Dynamic, Queues & Associative
      • Packed vs Unpacked Arrays
      • Dynamic Arrays and Queues
      • Associative Arrays
      • Array Methods and Selection
    • Procedural Code & Scheduling
    • Operators, Expressions & Width Rules
    • Packages, Typedefs & Compilation
    • Interfaces, Modports & Clocking Blocks
  • Object-Oriented SystemVerilog for Verification30
  • Constraint Randomization — Interview-Critical Deep Dive39
  • SystemVerilog Assertions — Interview-Critical Deep Dive41
  • Functional Coverage in SystemVerilog25
  • Testbench Architecture in SystemVerilog24
  • Advanced Language & Integration26
  • Senior & Interview Preparation23
  • Principal-Level Verification34
Loading lesson

←Arrays: Packed, Dynamic, Queues & Associative
  1. Topics
  2. SystemVerilog
  3. SystemVerilog Language Foundations
  4. Arrays: Packed, Dynamic, Queues & Associative
  5. Packed vs Unpacked Arrays
On this page

    Part 1 of 9, lesson 6 of 28Part 1 of 9/Language Foundations/Lesson 6 of 28Intermediate

    Packed vs Unpacked Arrays

    Packed vectors versus unpacked elements: layout, slicing, copies and synthesis.

    A 16 KB memory model synthesized into 131,072 flip-flops instead of one RAM, because its dimensions sat on the wrong side of the name. Which side a dimension sits on decides what the array is.

    After this lesson you can: tell packed from unpacked dimensions, index and slice both kinds, and say which operations each allows.

    One vector or many elements

    Dimensions before the name are packed. The whole array is one contiguous vector that supports arithmetic, comparison and part-selects.

    Dimensions after the name are unpacked. Each element is independent, so whole-array arithmetic is illegal, while whole-array copy and == work element by element on matching shapes.

    Packed

    Unpacked

    Declaration

    logic [7:0] bus

    logic [7:0] mem [0:1023]

    Meaning

    One 8-bit vector

    1024 independent bytes

    bus + 1

    Legal

    Illegal: no whole-array arithmetic

    ==, !=

    Legal

    Legal when both arrays have the same element type and shape

    [3:0] slice

    Legal: selects bits

    Legal: selects whole elements, not bits

    Element type

    bit, logic, reg, packed structs, unions and enums

    Anything, including classes

    The declaration logic [7:0] mem [0:1023] reads as 1024 unpacked elements of packed 8-bit vectors. That is exactly the shape of a byte memory.

    Packed dimensions apply to single-bit types (bit, logic, reg), packed structs and unions, and enums. Integer types such as byte, shortint and int already count as packed vectors, but they cannot take extra packed dimensions: int [3:0] x is illegal, while int x [4] (unpacked) is fine.

    Ranges, order and slicing

    Packed ranges conventionally run [msb:lsb]. Unpacked ranges traditionally run [0:n-1], with [n] as shorthand for [0:n-1].

    Index unpacked dimensions first from left to right, then packed dimensions from left to right. Bit part-selects need a packed dimension. On an unpacked dimension, [3:0] and +: select a slice of whole elements.

    Dimensions before the name pack into one vector; dimensions after it make separate elements.
    • Declaration: packed dimensions sit before the name, unpacked dimensions after it.

    • Indexing: consume unpacked dimensions first left to right, then packed dimensions left to right.

    • Slicing: bit part-selects apply to packed dimensions only; unpacked slices select whole elements.

    • Copies: whole-array assignment and equality need identical element type and shape on both sides.

    Common mistakes

    A part-select on an unpacked dimension selects elements, not bits. For logic [7:0] mem [0:7], mem[0:3] is four bytes. Bit slices need a packed dimension.

    Likely question: “which side of the name makes an array packed?”

    • Before the name is packed: one vector with arithmetic and slicing.

    • After the name is unpacked: independent elements.

    • Order of indexing: unpacked first, then packed.

    Check yourself Why does bus + 1 compile for a packed array but not for an unpacked one?

    Only packed arrays are vectors. Arithmetic is a vector operation, and unpacked arrays are collections of independent elements.

    Check yourself logic [31:0] mem [0:4095] synthesizes to RAM, but one flat 131072-bit vector does not. Why?

    RAM inference looks for unpacked elements of packed words with an indexed read and a clocked write. One flat vector looks like discrete flops, so the tool builds flops.

    Testbench

    Predict first The bench writes 32'hDEAD_BEEF to frame[0], then 8'hAA to lane 3, then clears bit 7 of lane 3. What do frame[0][3] and frame[0][0] hold?

    8'h2A and 8'hEF. Lane 3 is bits 31:24, so it becomes AA and then loses its top bit; lane 0 keeps the EF from the first write.

    Layout, lane access, slicing and copy rules, proved with one self-checking testbench.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    module tb_packed_layout;
      logic [3:0][7:0] frame [0:1];   // 2 unpacked rows of packed 4-lane vectors
      logic [7:0] a [0:3];
      logic [7:0] b [0:3];
      int errors = 0;
    
      initial begin
        frame[0] = 32'hDEAD_BEEF;     // whole packed value of row 0
        frame[0][3] = 8'hAA;          // lane 3 (bits 31:24) of row 0
        frame[0][3][7] = 1'b0;        // clear top bit of lane 3: AA -> 2A
        frame[1][1:0] = 16'hCAFE;     // packed slice: lanes 1..0
        if (frame[0][3] !== 8'h2A) errors++;
        if (frame[0][0] !== 8'hEF) errors++;
        if (frame[1][1:0] !== 16'hCAFE) errors++;
    
        a = '{8'h11, 8'h22, 8'h33, 8'h44};
        b = '{default: 8'h00};
        b = a;                        // legal: identical shape, element-wise copy
        // c = a;                     // ILLEGAL when c has 8 elements vs 4
        if (a != b) errors++;
        if (b[2] !== 8'h33) errors++;
    
        if (errors != 0) $fatal(1, "FAIL: packed layout self-check");
        $display("PASS: packed lanes and slices read back, identical-shape copies compare equal");
        $finish;
      end
    endmodule
    Terminal
    PASS: packed lanes and slices read back, identical-shape copies compare equal
    • Dimensions before the name are packed: one vector with arithmetic and bit slices.

    • Dimensions after the name are unpacked: separate elements, copied and compared one by one.

    • Index unpacked dimensions first, then packed, each left to right.

    Rule of thumb: before the name is one vector; after the name is many elements.

    How this was checked

    Run with Verilator 5.048 (--binary --timing) on 2026-10-18; every bench printed the PASS line shown, with no warnings. Icarus 13 cannot run this bench (it rejects the default: assignment pattern).

    Related topics

    • Next: Dynamic Arrays and Queues

    Previous

    11 / 275

    Next: Dynamic Arrays and Queues

    Up next

    Up nextDynamic Arrays and Queues

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Associative Arrays
    • Array Methods and Selection