User-defined Types

There are two classes of user-defined types in Bitsy.

Enums

You can define your own enumerations with enum type.

For example, in a RISC-V core, you might find the following definition to capture the list of 7-bit instruction opcodes:

enum type Opcode {
    OP      = 0b0110011w7;
    OP_IMM  = 0b0010011w7;
    LOAD    = 0b0000011w7;
    STORE   = 0b0100011w7;
    JAL     = 0b1101111w7;
    BRANCH  = 0b1100011w7;
    LUI     = 0b0110111w7;
    AUIPC   = 0b0010111w7;
    JALR    = 0b1100111w7;
}

You can create a constant literal for any enum with the syntax Opcode::OP_IMM. You can convert an enum value to a Word of the appropriate size with word. For example, word(Opcode::OP_IMM) would equal 0b0010011w7.

Structs

You can define your own struct types with struct type.

For example, if you were writing hardware which made heavy use of 24-bit RGB color values, you could define Color as:

struct type Color {
    red   of Word[8];
    green of Word[8];
    blue  of Word[8];
}

You can construct values of a struct type with the syntax {red = 0, green = 0, blue = 0}. You can take a value with a struct type and refer to its components with the syntax color->red, etc.

Alts

An alt type is what’s sometimes known as an algebraic data type. Some programming languages also call them enum types.

Alt types are defined with a set of constructors. Each constructor takes zero or more arguments. The type of each argument is given when defining the alt type.

Here is an example of a definition for an alt type:

alt type State {
    Idle();
    Running(Word[32], Word[32]);
    Done(Word[32]);
}

We define State to have three constructors: Idle, Running, and Done.

You construct values of an alt type by calling the constructors. Prepend the constructors with an @ symbol to distinguish them from functions. The @ also reminds us that the identifier is not a variable or a fixed symbol. Instead, it is resolved to a concrete constructor only once you know the type.

mod StateMachine {
     reg state of State reset @Idle();
     // ...
}

To make use of an alt type, you can match on it:

mod StateMachine {
     reg state of State reset @Idle();
     state <= match state {
         @Idle() => ?idle_next_state;
         @Running(x, y) => ?running_next_state;
         @Done(x) => ?done_next_state;
     };
}