Logo

Structures and Unions in system verilog

03 Jun 2022
5 mins

Structures and unions are special data types which are used to group variables having different data types. We have seen that arrays also provide the grouping of various variables or elements. But in arrays, the data type of each element is the same, whereas structure and unions can have elements having different data types. Let’s explore structure and union in detail in this article. In the end, we will also know the difference between structure and union.

Structures

A structure is a collection of elements having different data types. These elements can be accessed as a whole or individually. Like Enums these can be used to make user-defined data types. When a structure is declared, the memory is allocated for all the elements.

Syntax

Struct keyword is used to declare a structure. If a user-defined data type needs to be created using the structure, the typedef keyword is also used. Please note that each element is seperated using ; and not ,.

<typedef> struct { <element1>; <element2>; ... } <name>;

// syntax example
struct {
    int roll;
    string name;
} student;

Example

module structure1();
    typedef struct {
        int roll;
        string name;
        int mark;
    } student;

    student s1, s2;
    initial begin
        s1 = '{ 23, "Amit", 78 };
        $display("s1 = %p", s1);
        $display("s2 = %p", s2);

        // chaning one of the element
        s1.name = "Anita";
        $display("s1 = %p", s1);

        // copyind one struct to another
        s2 = s1;
        $display("s2 = %p", s2);
    end
endmodule
Output
# s1 = '{roll:23, name:"Amit", mark:78}
# s2 = '{roll:0, name:"", mark:0}
# s1 = '{roll:23, name:"Anita", mark:78}
# s2 = '{roll:23, name:"Anita", mark:78}
Try this code in EDA Playground

Like the arrays, a structure can also be packed or unpacked. This concept of a packed and unpacked structure is exclusive to System Verilog. All structures are by default unpacked in nature.

Packed structure

A packed structure like a packed array can be thought of as a single dimension memory or a vector. In a packed array, this vector is divided into equal size partitions which can sometimes be inefficient as often data would be of different lengths. Packed structure on the other hand divides the vector into unequal size partitions providing more efficient packing of data.

Syntax

<typedef> struct packed { <element1>; <element2>; ... } <name>;

Example

module structure2();

    typedef struct packed{
        int roll;
        bit [10:0] mark;
    } student;

    student s1, s2;
    initial begin
        s1 = { 10'd23, 10'd78 };
        $display("s1 = %p", s1);

        // In this initialization the data will be
        // stored correctly
        s2 = { 32'd23, 11'd98};
        $display("s2 = %p", s2);
    end
endmodule
Output

In the below output it can be observed that in first initialization is not correct as the size of the assigned value was not correct.

# s1 = '{roll:11, mark:1102}
# s2 = '{roll:23, mark:98}
Try this code in EDA Playground

Packed vs unpacked structure

Packed StructureUnpacked Structure
members can be of packed data type onlyMembers can be of any data type
Initialization can be done for several members at once using the concatenation operator as well. This is because the packed structure is treated as a vector.Initialization can be done for several members at once but only with the assignment operator, i.e., '{}. The concatenation operator cannot be used.

In a packed structure, we can only use a packed data type. For example, a string cannot be used inside a packed structure. Also, all array types except a packed array cannot be used inside the packed address.

Unions

Unions are like structures, but in a union, we can only access one element at a time. When unions are declared the memory is allocated only for the largest data type.

Syntax

<typedef> union { <element1>; <element2>; ... } <name>;

// syntax example
union {
    int a;
    byte b;
} test;
Not all simulators support unions. Check the simulator manual before using unions.

Example

module union1 ();
    union {
        int n;
        byte d;
    } test;

    initial begin
        test.n = 'hFFFF;
        $display("n = %0h", test.n );
        $display("d = %0h", test.d );

        test.d = 'h48;
        $display("n = %0h", test.n );
        $display("d = %0h", test.d );

        $displayh("test = %p", test);
    end
endmodule
Output
# n = ffff
# d = ff
# n = ff48
# d = 48
# test = '{n:0000ff48, d:48}

Structure vs Union

StructureUnion
Struct keyword is used for declarationUnion keyword is used for declaration
The size of a structure is the sum of all the members of the structureThe size of a union is the size of the largest member of the union
All members are assigned different memory locationThe same memory location is shared by all the members
Individual members can be accessed at a timeOnly one member can be accessed at a time
Several members can be initialized at onceOnly the first member can be initialized

Unions can also be declared as packed, but in the packed union, all the elements should be of the same size. I do not find packed union useful as all members have the same size and also store the same value at a given time. Thus, a packed union can be replaced with a simple data type variable.

Tagged Unions

We have seen that the unions in System Verilog is not very useful as the value changed for one variable is reflected in other variables defined inside union. System Verilog introduced a new concept of tagged unions. In tagged union, we can assign a tag to a particular variable of any data type. Using this tag we can know that union is currently used to store which variable. This is useful when we want to have a packet which can store different value at different times.

Example

Below is an example of tagged union. In this example we have defined a tagged union which can store cpu instruction. We know at a particular time a instruction packet can hold any one type of instruction. Thus, using tagged union can save memory location and also instruction packet can be generated easily.

Below typdef command defines a new union data type named Instr. This is a tagged union having 2 outer tags, i.e, Add and Jmp. Jmp tag has inner tag which have 2 tags, i.e, JmpU and JmpC. When Add tag is used we can store 3 values each of 5 bits. Similarly if JmpU is used, we can store a 10 bit address and for JmpC we can have 2 bit condition along with the address.

Also note, if we have assigned a particular tag to the union, we can’t use any other tag to access the union. It will lead to a run time error.

module tagged_union();
    typedef union tagged {
        struct {
            bit [4:0] a, b, c;
        } Add;
        union tagged {
            bit [9:0] JmpU;
            struct {
                bit [1:0] cc;
                bit [9:0] addr;
            } JmpC;
        } Jmp;
    } Instr;

    Instr i1;
    reg e;
    reg [4:0] e1, ed;

    initial begin
        e= 1'b1;
        e1 = $urandom();
        ed = $urandom();
        i1 = ( e
            ? tagged Add { e1, 4, ed } // struct members by position
            : tagged Add { b:45, a:3, c:19 });

        $display("i1 = %p", i1.Add);
        $display("i1 = %p", i1);
        $display("i1 = %p", i1.Jmp.JmpC); // This will show a run time error as Add is assigned as tag

        i1 = tagged Jmp (tagged JmpU 129); // struct members by position
        $display("\ni1 = %p", i1.Jmp);
        $display("i1 = %p", i1);
    end
endmodule
Output
# i1 = '{a:24, b:4, c:6}
# i1 = '{Add:Add:'{a:24, b:4, c:6}}
# ** Error (suppressible): Union is tagged 'Add', but is referenced as 'Jmp'.
#    Time: 0 ns  Iteration: 0  Instance: /tagged_union
# ** Error (suppressible): Union is tagged 'ˆëþð', but is referenced as 'JmpC'.
#    Time: 0 ns  Iteration: 0  Instance: /tagged_union
# i1 = '{cc:0, addr:4}
# 
# i1 = '{JmpU:JmpU:129}
# i1 = '{Jmp:Jmp:'{JmpU:JmpU:129}}

Eda playground link is not given for this example as the free simulator available in Eda playground does not support tagged Unions as of now. It can be simulated in simulators like Questasim, VCS, etc.