SystemVerilog Structures and User-Defined Types#
🏗️ What is a Struct?#
A struct in SystemVerilog is a composite data type that groups different data types into a single logical unit. Similar to structures in C/C++, it allows you to organize related variables under one name.
🔹 Key Features of Structs:#
- Heterogeneous data grouping (different types in one structure)
- Modular data organization
- Improves code readability
- Ideal for data packing and protocol modeling
🔹 Basic Struct Syntax:#
struct {
data_type1 member1;
data_type2 member2;
// ...
} struct_name;
🔹 Example Struct Definition:#
struct {
string name;
int age;
logic[3:0] id;
bit is_active;
} employee;
🔹 Packed vs. Unpacked Struct:#
- Packed Struct: Bit-accurate, contiguous memory allocation
struct packed { logic [7:0] r; logic [7:0] g; logic [7:0] b; } pixel_t;
- Unpacked Struct: Default, more flexible (members may not be contiguous)
🔹 Accessing Struct Members:#
employee.name = "Ahmet";
employee.age = 32;
if (employee.is_active) ...
🔹 Using typedef
with Structs (Best Practice):#
typedef struct {
logic [31:0] addr;
logic [63:0] data;
logic valid;
} transaction_t;
transaction_t trx;
Structs are widely used in SystemVerilog for data packets, protocol messages, and complex data structures in RTL and verification.
🔄 Understanding Unions in SystemVerilog#
Unions allow a single storage location to be accessed as different data types, providing memory-efficient ways to represent data that can be interpreted in multiple ways.
🔹 Key Features of Unions:#
- Shared memory space for all members
- Only one member active at a time
- Memory-efficient for alternative data representations
- Useful for protocol processing and hardware register modeling
🔹 Basic Union Syntax:#
union {
data_type1 member1;
data_type2 member2;
// ...
} union_name;
🔹 Packed vs Unpacked Unions:#
- Packed Union: All members share exact same bit width
union packed { logic [31:0] int_val; logic [7:0] byte_arr[4]; } data_u;
- Unpacked Union: Members can have different sizes (less common)
🔹 Practical Union Example:#
typedef union {
int as_int;
shortreal as_float;
logic [31:0] as_bits;
} number_u;
number_u num;
num.as_float = 3.14; // Store as float
$display("Integer view: %0d", num.as_int); // Reinterpret as int
🔹 Union with Struct:#
typedef struct {
logic [7:0] addr;
union {
logic [31:0] data;
logic [7:0] bytes[4];
} payload;
} packet_t;
🔹 Common Use Cases:#
- Protocol Processing (different interpretations of same bits)
- Hardware Register Access (multiple views of same register)
- Type Conversion (bit reinterpretation without casting)
- Memory Optimization (when only one variant is needed at a time)
🔹 Important Notes:#
- Only the last written member should be read
- No type checking - programmer must track active member
- Packed unions are synthesizable (unpacked unions typically aren’t)
- Use with caution in verification due to potential type safety issues
🔹 Union vs Struct Comparison:#
Feature | Union | Struct |
---|---|---|
Memory | Shared (overlapping) | Dedicated (contiguous) |
Access | One member at a time | All members simultaneously |
Size | Size of largest member | Sum of all members |
Typical Use | Alternative representations | Data grouping |
🏷️ SystemVerilog User-Defined Types and Type Aliases#
SystemVerilog allows users to define custom data types using the typedef
keyword. This feature enhances code readability, reusability, and type abstraction, especially in large RTL or verification projects.
🔤 What is typedef
?#
The typedef
keyword creates an alias (alternative name) for an existing data type or a complex type definition.
Basic Syntax:#
typedef original_type alias_name;
✅ Why Use typedef
?#
- Improves readability for complex types
- Simplifies parameter passing in tasks/functions
- Enables strong typing and abstraction
- Reduces code duplication
📌 Examples of typedef
Usage#
1. Simple Alias#
typedef logic [7:0] byte_t;
byte_t a, b; // Equivalent to: logic [7:0] a, b;
2. Typedef for Structs#
typedef struct {
string name;
int age;
bit is_valid;
} person_t;
person_t user1;
user1.name = "Kerim";
3. Typedef for Enums#
typedef enum logic [1:0] {
IDLE,
RUN,
DONE
} state_t;
state_t fsm_state;
4. Typedef for Arrays#
typedef logic [15:0] word_t;
typedef word_t mem_array_t [0:255]; // 256-word memory
mem_array_t my_ram;
5. Typedef for Unions#
typedef union packed {
int as_int;
byte_t as_bytes[4];
} data_u;
data_u data;
🔁 Using typedef
with Parameterized Types#
You can define flexible and reusable types inside parameterized modules or interfaces:
module fifo #(parameter WIDTH = 8) ();
typedef logic [WIDTH-1:0] data_t;
data_t buffer;
endmodule
🧩 Struct Assignment Styles in SystemVerilog#
SystemVerilog provides flexible methods to assign values to struct elements — both member-wise and aggregate-based.
1. Individual Member Assignment#
You can assign each member of a struct one by one:
employee.name = "Ali";
employee.age = 30;
employee.id = 4'b1100;
employee.is_active = 1;
2. Aggregate Assignment (Literal Initialization)#
You can assign the entire struct using a literal list ('{...}
), in declaration or at runtime:
employee = '{ "Ayşe", 28, 4'b0011, 1 };
✅ Order must match the declaration order of struct members.
You can also use named assignments for clarity:
employee = '{
name: "Zeynep",
age: 25,
id: 4'b1001,
is_active: 0
};
🧠 Named assignments make your code self-documenting and less error-prone.
3. Default Value Initialization#
SystemVerilog allows partial or full default initialization using the default:
keyword:
employee = '{logic: 0, default: 0}; // All fields reset to 0 or "", All logic kind variable reset to 0
This is especially useful in testbenches and struct arrays.
🚨 Notes and Best Practices#
- Use
_t
suffix to indicate type aliases (e.g.,byte_t
,state_t
) typedef
cannot define a new class—only primitive types, structs, enums, unions, or arrays- Highly useful in testbenches, UVM components, and interfaces
📚 Summary Table#
Usage | Syntax Example | Description |
---|---|---|
Alias for basic type | typedef logic [7:0] byte_t; | Shorter, reusable name for vector types |
Struct alias | typedef struct { ... } my_struct_t; | Clean, modular data grouping |
Enum alias | typedef enum {A, B, C} mode_t; | Finite state or mode definitions |
Array alias | typedef logic [15:0] mem_t [0:255]; | Predefined memory or buffer abstraction |
Union alias | typedef union packed { ... } union_t; | Bit-shared data representation |