Statements
The body of any unit, or block is a list of statements followed by a resulting expression. Statements can declare things local to the block and contain expressions to be evaluated
Let bindings
Let bindings bind a pattern to a value.
Those not used to bindings and patterns can view a let
binding as assigning a value
to a variable.
The pattern has to be an irrefutable pattern
If the type specification is omitted, the type is inferred.
Syntax
let
pattern [:
type specification]=
expression;
Examples
Binding a value to a variable
let a = some_value;
Binding a value to the result of an if expression
let a = if x {0} else {2};
Unpacking a tuple
let (a, b) = some_value;
Unpacking a struct with an explicit type signature
let Struct$(a, b): Struct<int<8>> = some_value;
Registers
Free-standing (i.e. non-pipelining registers) are defined using reg(clk) ...
The register definition is quite complex and includes
- The clock signal which triggers an update
- A pattern to bind the current value of the register to. It must be irrefutable
- An optional type specification. Like let bindings, the type is inferred if the type signature is omitted
- An optional reset consisting of a reset trigger and a reset value.
Whenever the reset trigger is
true
the value of the register is asynchronously set to the reset value1 - An expression which gives new value
On the rising edge of the clock signal, the value of the register is updated to the value of the new value. The new value expression can include variables from the register itself.
Syntax
reg(
clock: expression)
pattern [:
type specification] [reset(
reset trigger: expression:
reset value expression)
]=
new value: expression;
Examples
A register which counts from -128 to 127 (Note that because no initial value is specified, this will be undefined in simulation):
reg(clk) value: int<8> = trunc(value + 1);
A register which counts from 0 to 200 (inclusive) and is reset to 0 by rst
:
reg(clk) value reset(rst: 0) =
if value == 200 {
0
} else {
trunc(value + 1)
};
Pipeline stage markers
Stage markers (reg;
) are used in pipelines to specify where pipeline registers should be inserted.
After a reg
statement, all variables above the statement will be put in registers and any reference
to those variables refer to the registered version.
Syntax
reg;
reg *
integer;
reg[
expression];
Repeated
In cases where more than one stage should be inserted without any new statements in between, there is a shorthand syntax:
reg * n`
where n
is an integer. This is compiled into n
simple reg statements, i.e.
reg * 3;
is the same as
reg;
reg;
reg;
Conditioned
A condition for the registers to accept values can also be specified in square brackets
reg[condition]
The semantics of this are explained in the section on dynamic pipelines
Pipeline stage labels
Pipeline stages can be given names to refer to them from other stages. This is done using 'name
.
'first
let x = ...;
reg;
To refer to a named stage, use a []
Set
Set the value of a mutable wire to the specified value.
set wire = value;
Set statements can only appear at the top block of a unit. This might be surprising as you would expect to be able to write
#![allow(unused_variables)] fn main() { if condition { set wire = value; } }
However, this is not well-defined in hardware because the wire needs some value, but no value is specified if condition does not hold. This particular point isn't true if an else branch is also specified, but the exact hardware that gets generated from imperative code like this is not obvious, particularly with more nesting.
Therefore, if you want to write
if condition {
set wire = on_true;
} else {
set wire = on_false
}
you should move the set
statement outside to make it unconditional, i.e.
set wire =
if condition {
on_true
} else {
on_false
}
Syntax
set
expression=
expression;
Assert
Takes a boolean condition and evaluates it, raising a runtime error in
simulation if it ever evaluates to false
. In synthesis, this is ignored
assert this_should_be_0 == 0;
NOTE: Assert statements are currently not supported for synthesis with Verilator, only with Icarus.
Comptime
TODO