Week 5 · Day 21 · 7 hours

Day 21 — SystemVerilog Data Types

Compare 2-state and 4-state types, model packed and unpacked data, and debug signedness/casting.

01

Concept lesson

Understand the language feature before coding

Day 21 — SystemVerilog Language: Data Types

Simulation status (28 Oct 2026): The commands below pass on Icarus Verilog 12. Use Icarus for this day: Verilator 5.052 is two-state (X and Z become 0 or 1), so its run stops at the four-state check. Details: Week 5 validation record (VALIDATION.md).

Time: Theory 2 h + guided 2 h + independent 2 h + debug/assignment 1 h.

Workspace: project_workspace/week5_systemverilog/day21_data_types

Guided experiments (1–5)

  1. logic vs bit initialization and X/Z behavior.
  2. 2-state/4-state equality and case equality.
  3. Packed vectors and bit selection.
  4. Unpacked arrays and indexed access.
  5. Multidimensional arrays.

Independent experiments (6–10)

  1. typedef aliases.
  2. Signed and unsigned values.
  3. Width truncation and explicit casting.
  4. string basics.
  5. Typed packet fields.

Run and capture evidence

mkdir -p sim logs
iverilog -g2012 -Wall -o sim/day21.vvp tb/day21_types.sv
vvp sim/day21.vvp | tee logs/day21.log

These commands pass on Icarus Verilog 12. Record your simulator version with the log, and do not claim completion if compilation fails.

Debug task

Reproduce the deliberately wrong 4-bit cast of 8'hF3; explain the truncation and replace it with the intended width. Attach before/after values and PASS evidence. Convert a Verilog TB data model into typed SystemVerilog declarations.

Deliverable: SV datatype exercise set, log, debug note, and explanation of 2-state vs 4-state behavior.

Language boundary and package fundamentals

SystemVerilog extends Verilog; it does not make every construct synthesizable. Modules and a supported RTL subset describe hardware. Classes, constrained randomization, mailboxes, and covergroups are verification facilities. The extension .sv alone does not select a language version: use the simulator's SystemVerilog mode and record its version. Synthesis support still depends on the tool and the construct.

Choose a 4-state type such as logic for signals where x and z are useful debug evidence. A 2-state bit cannot preserve an unknown value; it is useful for testbench bookkeeping when unknown detection is not needed. Don't replace a DUT-facing logic signal with bit just to make an initialization warning disappear.

SystemVerilog also provides process forms that state the intended hardware:

Form Intended behavior Review point
always_comb Combinational logic with automatically derived sensitivity. Assign every output on every path; inspect latch diagnostics.
always_ff Edge-triggered state. Use a clear clock/reset event and one procedural owner for each variable.
always_latch Level-sensitive storage when a latch is intentional. Make the enable and retained-value behavior explicit.

These forms improve intent checking; they do not make incorrect logic correct, and support depends on the selected SystemVerilog mode and tool.

unique, unique0, and priority can document selection assumptions and enable run-time diagnostics. Use them only when the specification supports the assumption: unique expects exactly one matching choice, unique0 allows no match but expects at most one, and priority expects a matching choice. Keep safe defaults and explicit error behavior where required. Overlapping wildcard branches, unknown values, or a synthesis tool's optimization of assumed-unreachable cases can make an incorrect assumption costly; test those boundaries instead of treating the keyword as functional coverage.

A package gives related type and helper declarations a named scope. Compile the package before files that use it, then either qualify a name or import it:

package protocol_types;
  typedef enum logic [1:0] {IDLE, ACTIVE} state_t;
endpackage
module state_check;
  import protocol_types::*;
  state_t state;

  initial begin
    state = IDLE;
    if (state != IDLE) $fatal(1, "package type check failed");
    $display("PACKAGE_PASS");
    $finish;
  end
endmodule

The same type can be named as protocol_types::state_t when an explicit scope is clearer than importing all package names. Avoid broad wildcard imports from several packages when names may collide. A package is a compiled SystemVerilog construct, unlike a text include, which is expanded by the preprocessor.

Save the snippets in protocol_types.sv and state_check.sv, then run:

iverilog -g2012 -Wall -s state_check -o sim/package.vvp protocol_types.sv state_check.sv
vvp sim/package.vvp

Expected output is PACKAGE_PASS. If the selected tool rejects the construct, record that compatibility result; do not silently switch language modes.

02

Visual explanation

Connect syntax with simulator behavior

SystemVerilog type families: 4-state: logic, reg, integer; 2-state: bit, byte, shortint, int, longint; Choose type based on X/Z semantics and width
SystemVerilog type families
Packed vs unpacked arrays: logic [7:0] data; packed 8 bits; logic [7:0] words [0:3]; 4 unpacked elements; Packed dimensions precede variable name
Packed vs unpacked arrays
03

Worked example

Read and run the supplied SystemVerilog source

Example source · Day 21
module day21_types;
  logic four_state;
  bit two_state;
  logic [7:0] packed_data;
  logic [7:0] unpacked_data [0:1];
  logic [3:0] matrix [0:1][0:1];
  typedef logic [7:0] byte_t;
  byte_t packet_header;
  logic signed [7:0] signed_value;
  logic [7:0] unsigned_value;
  logic [3:0] truncated;
  logic [7:0] corrected;
  string label;
  initial begin
    four_state = 1'bx;
    two_state = 1'b0;
    if (four_state !== 1'bx || two_state !== 1'b0) $fatal(1,"state types");
    four_state = 1'bz;
    if (four_state !== 1'bz) $fatal(1,"z state");
    packed_data = 8'hA5;
    if (packed_data[7:4] !== 4'hA) $fatal(1,"packed");
    unpacked_data[0] = 8'h12;
    unpacked_data[1] = 8'h34;
    if (unpacked_data[1] !== 8'h34) $fatal(1,"unpacked");
    matrix[1][0] = 4'hC;
    if (matrix[1][0] !== 4'hC) $fatal(1,"matrix");
    packet_header = 8'h5A;
    if (packet_header !== 8'h5A) $fatal(1,"typedef packet");
    signed_value = -8'sd3;
    unsigned_value = 8'hFD;
    if (!(signed_value < 0) || unsigned_value !== 8'd253) $fatal(1,"signedness");
    truncated = 4'(8'hF3);
    corrected = 8'(8'hF3);
    if (truncated !== 4'h3 || corrected !== 8'hF3) $fatal(1,"casts");
    label = "packet";
    if (label.len() != 6) $fatal(1,"string");
    $display("PASS Day 21: data types and deliberate truncation detected");
    $finish;
  end
endmodule

Compile and run

  1. mkdir -p sim logs
  2. iverilog -g2012 -Wall -o sim/day21.vvp tb/day21_types.sv
  3. vvp sim/day21.vvp

What to verify

  • logic vs bit
  • X/Z 4-state
  • packed and unpacked arrays
  • multidimensional array
  • typedef
  • signedness
  • casts
  • strings
  • packet fields
  • bug fix

Pass condition: PASS is printed and $fatal is never triggered.

04

Hands-on practice

Complete the exercises in order

  1. 1

    Compare logic and bit initialization and X/Z assignments.

  2. 2

    Measure 2-state versus 4-state behavior using === and !==.

  3. 3

    Create and index packed vectors.

  4. 4

    Create and index unpacked arrays.

  5. 5

    Build a multi-dimensional array and print selected entries.

  6. 6

    Declare typedef aliases for packet fields.

  7. 7

    Compare signed and unsigned values at boundaries.

  8. 8

    Demonstrate explicit casts and width truncation.

  9. 9

    Use strings for human-readable labels.

  10. 10

    Represent packet header fields with typed SV variables.

Written assignment

  1. Explain bit versus logic and demonstrate X/Z handling.
  2. Show signed and unsigned interpretations of the same bit pattern.
  3. Explain packed versus unpacked dimensions with examples.
  4. Document one deliberate truncation bug, its correction and evidence.
  5. Convert one Verilog testbench data model into SystemVerilog.

Debug challenge

Find and fix width, signedness and explicit-cast errors in the supplied data model.

Completion criteria

Ten mapped exercises, self-checking PASS, deliberate width bug detected and fixed.

05

Knowledge check

Check your understanding

Why can logic represent X while bit cannot?

logic is four-state; bit is two-state.

How does logic [7:0] a differ from logic a[0:7]?

The first is a packed vector; the second is an unpacked array.

What happens when a wider unsigned value is assigned to a narrower destination?

High-order bits are truncated.

Why should signedness be explicit in arithmetic checks?

The same bit pattern can represent different signed and unsigned values.

Why is an enum useful for protocol states?

It gives legal values meaningful names and improves type checking and debug.

When is case equality (===) useful in verification code?

When X and Z bits must be compared as explicit values.

Evidence to retain

  • source code
  • simulator version and compile command
  • PASS/FAIL transcript
  • before/after debug note