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;
};
}