UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 

Unions in SystemVerilog

Xilinx Employee
Xilinx Employee
4 0 378

Basic Unions

A union in SystemVerilog is simply a signal that can be referenced with different names and aspect ratios.

The way this works is to declare with a typedef that it is a union and give it different identifiers which you can use to refer to the union.  These different identifiers are known as "fields". 

For example:

typedef union packed {
     logic [3:0] a;
     logic [3:0] b;
} union_type;

union_type my_union;

The above code has created a new type called "union_type". 

This type is 4 bits wide, and it can be referred to either as "a" or "b". 

In addition, the last line of the code has created a new signal called "my_union" that is of type "union_type". 

To use this, the syntax will be "<signal name>.<field_name>". 

For example:

always@(posedge clk) begin 
my_union.a <= in1;
end

always@(posedge clk) begin out1 <= my_union.a; out2 <= my_union.b; end

When running this in Vivado, the schematic looks like the following:

image.pngFig 1 : Basic unionNotice that my_union is still just 4 bits, and both assignments referring to it as "a" or "b" give the same logic.  The assignment to my_union used "a", and the reading from the union used "a" and "b" for out1 and out2.

There are two types of unions, packed and unpacked. In the previous example, we specified a packed union.  By default, if you do not give your union a type, the compiler will assume it is an unpacked union. The difference between packed and unpacked unions is that in packed unions, all of the identifiers in the union must by packed types and be exactly the same size.  In the previous example, both "a" and "b" are 4 bits.  However if one of them is 4 bits and the other is 2 bits, an error will be given in the tool.  In an unpacked union, you can have unpacked types and the sizes of the identifiers do not need to be the same.  So in the previous example of a 4 and 2 bit union, leaving out the "packed" statement will allow the RTL to go through the tool.  In general, packed unions are more widely supported in synthesis tools and are much easier to conceptualize.  For the first few examples of unions in this article, we will be using packed unions, but then we will show a couple of unpacked unions towards the end.

 

Unions with multidimensional fields

The previous example showed off what a union can do, however it was not very interesting.  Let's look at a slightly more complicated union:

typedef union packed {
     logic [3:0] a;
     logic [1:0][1:0] b;
} union_type;

union_type my_union;

As before, a union is declared and a signal of type "union_type" is created.  What is different is that one field "a" is 4 bits, and the other field "b" is also 4 bits, but it is arranged as 2 2-bit vectors.  Because both of these fields are the same size and field "b" is using packed types, this is a legal packed union.

The structure looks like the following:

 

image.pngFig 2 : Union with multidimensional array

It is assigned with the RTL below:

always@(posedge clk) begin
my_union.a <= in1;
end

always@(posedge clk) begin out1 <= my_union.b[0]; out2 <= my_union.b[1]; end

The schematic will look like the following:

image.pngFig 3 : Schematic for multidimensional union

Unions with structures

Unions can also be used with structures.  As with all packed unions, the size of the structure needs to be the same size as any other type in the union.

For example:

typedef union packed {
     logic [9:0] data;
     struct packed {
          bit op1;
          bit [2:0] op2;
          bit [1:0] op3;
          bit op4;
          bit [2:0] op5;
     } op_modes;
} union_type;

union_type my_union;

This RTL describes a union of 2 fields, both of 10 bits.  The first field is a vector called "data" that is 10 bits.  The second field is a structure with 5 fields whose sizes also add up to 10 bits. 

The structure that is created for this looks like the following:image.pngFig 4 : Union with a structure

Because there is now a structure within a union, the correct way to reference it is by referencing the struct within the union:

always@(posedge clk) begin
     my_mult <= my_union.op_modes.op2 * my_union.op_modes.op5;
end

 

Unpacked unions

A union needs to be declared unpacked if the fields inside the union are not the same size, or if the fields within the union are themselves using unpacked types.

For the first case, if a union with fields of different sizes is specified, the union itself becomes the size of the largest field.

Example RTL:

typedef union {
     logic [5:0] a;
     logic [3:0] b;
     logic c;
} union_type;

union_type my_union;

This will create a structure that looks like the following:

image.pngFig 5 : Unpacked union with different sized fields

Unpacked unions with structures

As with packed unions, the unpacked unions can also use structures.

typdef struct {
     bit [3:0] a1;
     bit a2;
} s_1;

typedef union {
     logic [7:0] b1;
     s_1 b2;
} union_type

union_type my_union;

 The above example creates a union with two fields. One is a vector "b1" that is 8 bits, and the other is a 5 bit struct that is made up of one 4 bit vector a1, and one bit called a2. 

The union will be created as an 8-bit vector and will look like the following:

 

image.pngFig 6 : Unpacked union with a struct

 

As before, because there is a struct inside the union, the signals need to be referenced as follows:

always@(posedge clk) begin
     my_union.b1 <= in1;
     out1 <= my_union.b2.a1;
     out2 <= my_union.b2.a2;
end