Skip to content

Unions

In Neo, a union (commonly known as a tagged union or sum type) enables a logic value to contain different data types. The union contains a tag, which functions like an enum where each variant is associated with a LogicType representing one of the data types. The tag is checked via a match expression before accessing the data, which ensures the data on the wire is always interpreted as the correct type. They can also be parameterized.

Definition

Unions contain a list of Variants, each optionally containing a Logic Type defining the data value.

neo
union MyUnion {
  A(Bits(32)), // This variant must be constructed with a data value of Bits(32)
  B, // This variant does not have a data value
}

union MyParameterizedUnion(t: LogicType) {
  A(Bits(32)),
  B(t),
}

Use

For unparameterized unions, the name becomes a LogicType value and can be instantiated directly. For parameterized unions, the name is a function reference to be called with values for the parameters.

neo
logic val(0): MyUnion;

logic parameterized_val(0): MyParameterizedUnion(Int(32));

To construct a variant of a union, the union's LogicType value contains methods for each variant. For variants with data, the method requires an argument of the variant's specified LogicType, and that value's timing will apply to the instance of the union. For variants without data, the method takes no arguments and the instantiated value will be a constant.

neo
// some_data will have to be Bits(32) and have timing 0
assign val = MyUnion.A(some_data);

// Since the B variant has no data, no argument is required and there is no timing consideration
assign val = MyUnion.B();

// The name of the union can be inferred in assignments, which is particularly useful with parameterized unions
assign parameterized_val = .B(some_other_data);

To read the value of a union, a match expression is used:

neo
match val {
  A(x) => {
    // x is a Bits(32) and has the same timing as val
  }
  B => {
    // No data value is associated with B
  }
}

A match expresion has to be used as it enforces checking the variant before accessing the data, ensuring the data is always interpreted as the correct type.