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.

The let Statement

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 is used to define a variable. Spade infers the type of most variables from context, but you can also specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
y the type with : <type> before the =.
a = 5;

Binding a value to the result of an if expression:

let is used to define a variable. Spade infers the type of most variables from context, but you can also specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
y the type with : <type> before the =.
positive = Returns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
(x > 0) {true} else {false};

Unpacking a tuple:

let is used to define a variable. Spade infers the type of most variables from context, but you can also specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
y the type with : <type> before the =.
(a, b) = some_pair;

Unpacking a struct with an explicit type signature:

let is used to define a variable. Spade infers the type of most variables from context, but you can also specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
y the type with : <type> before the =.
Struct$(a, b): Struct<Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
ies the number of bits
> = some_struct;

Registers

Free-standing (i.e. non-pipelining registers) are defined using reg keyword. The register definition is quite complex and includes:

On the rising edge of the clock signal, the value of the register is updated to 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) is used to define registers which maintain the state of your circuit.
All registers have a Type used to represent clock signals. (clk), a name and a new value after the = which is given as a function of the current value. Registers can also have a Defines the reset value of a register as (trigger: value). When trigger ist rue, the reset is synchronously reset to valuetrigger: value) wich means that the reset is synchronously set to value when trigger is true.
In pipelines, you can also define registers with reg; is used in a Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. to separate stages. When you refer to a variable defined above a reg; statement below a reg; statement you refer to a registered version of the original value. Registers defined with an explicit Type used to represent clock signals. (reg(clk)) are used for state registers both inside and outside pipelines. which are used to separate stages.
value: Type used to represent signed integers. The generic parameter (<N>) specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
ies the number of bits
= Truncates the input to a smaller size, throwing away the most signReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
icant bits. The size of the resulting value is type inferred.
value + 1);

A register which counts from 0 to 200 (inclusive) and is reset to 0 by rst:

reg(clk) is used to define registers which maintain the state of your circuit.
All registers have a Type used to represent clock signals. (clk), a name and a new value after the = which is given as a function of the current value. Registers can also have a Defines the reset value of a register as (trigger: value). When trigger ist rue, the reset is synchronously reset to valuetrigger: value) wich means that the reset is synchronously set to value when trigger is true.
In pipelines, you can also define registers with reg; is used in a Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. to separate stages. When you refer to a variable defined above a reg; statement below a reg; statement you refer to a registered version of the original value. Registers defined with an explicit Type used to represent clock signals. (reg(clk)) are used for state registers both inside and outside pipelines. which are used to separate stages.
value Defines the reset value of a register as (trigger: value). When trigger ist rue, the reset is synchronously reset to valuerst: 0) = Returns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
value == 200 { 0 } else { Truncates the input to a smaller size, throwing away the most signReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
icant bits. The size of the resulting value is type inferred.
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 refers to the registered version.

Basic Syntax

reg ;

Repeated Case

In cases where more than one stage should be inserted without any new statements in between, there is a shorthand syntax:

reg * integer ;

The code:

reg * N; creates N Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. registers with no computation between them. This is typically used when waiting for another Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline., or to insert several registers at the end of a computation to be re-timed into the computation by the synthesis tool.

where n is an integer is compiled into n simple reg statements. This:

reg * N; creates N Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. registers with no computation between them. This is typically used when waiting for another Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline., or to insert several registers at the end of a computation to be re-timed into the computation by the synthesis tool.

is the same as:

reg; is used in a Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. to separate stages. When you refer to a variable defined above a reg; statement below a reg; statement you refer to a registered version of the original value. Registers defined with an explicit Type used to represent clock signals. (reg(clk) is used to define registers which maintain the state of your circuit.
All registers have a Type used to represent clock signals. (clk), a name and a new value after the = which is given as a function of the current value. Registers can also have a Defines the reset value of a register as (trigger: value). When trigger ist rue, the reset is synchronously reset to valuetrigger: value) wich means that the reset is synchronously set to value when trigger is true.
In pipelines, you can also define registers with reg; which are used to separate stages.
) are used for state registers both inside and outside pipelines.
reg; is used in a Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. to separate stages. When you refer to a variable defined above a reg; statement below a reg; statement you refer to a registered version of the original value. Registers defined with an explicit Type used to represent clock signals. (reg(clk) is used to define registers which maintain the state of your circuit.
All registers have a Type used to represent clock signals. (clk), a name and a new value after the = which is given as a function of the current value. Registers can also have a Defines the reset value of a register as (trigger: value). When trigger ist rue, the reset is synchronously reset to valuetrigger: value) wich means that the reset is synchronously set to value when trigger is true.
In pipelines, you can also define registers with reg; which are used to separate stages.
) are used for state registers both inside and outside pipelines.
reg; is used in a Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. to separate stages. When you refer to a variable defined above a reg; statement below a reg; statement you refer to a registered version of the original value. Registers defined with an explicit Type used to represent clock signals. (reg(clk) is used to define registers which maintain the state of your circuit.
All registers have a Type used to represent clock signals. (clk), a name and a new value after the = which is given as a function of the current value. Registers can also have a Defines the reset value of a register as (trigger: value). When trigger ist rue, the reset is synchronously reset to valuetrigger: value) wich means that the reset is synchronously set to value when trigger is true.
In pipelines, you can also define registers with reg; which are used to separate stages.
) are used for state registers both inside and outside pipelines.

Conditional Case

A condition for the registers to accept values can also be specified in square brackets. In this case, the syntax is:

reg [ expression ] ;

We write:

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.

Syntax

This is done using just an identifier:

' name

Examples

Using this might look like:

'first
  let is used to define a variable. Spade infers the type of most variables from context, but you can also specReturns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
y the type with : <type> before the =.
x = ...; reg; is used in a Defines a pipeline. The number in in the parentheses is input-to-output latency of the pipeline. to separate stages. When you refer to a variable defined above a reg; statement below a reg; statement you refer to a registered version of the original value. Registers defined with an explicit Type used to represent clock signals. (reg(clk) is used to define registers which maintain the state of your circuit.
All registers have a Type used to represent clock signals. (clk), a name and a new value after the = which is given as a function of the current value. Registers can also have a Defines the reset value of a register as (trigger: value). When trigger ist rue, the reset is synchronously reset to valuetrigger: value) wich means that the reset is synchronously set to value when trigger is true.
In pipelines, you can also define registers with reg; which are used to separate stages.
) are used for state registers both inside and outside pipelines.

To refer to a named stage, use a [].

The set Statement

Set the value of a mutable wire to the specified value.

Syntax

set expression = expression ;

Examples

In Spade we write:

set wire = value;

to set the value of a given wire.

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:

Returns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
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:

Returns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
condition { set wire = on_true_value; } else { set wire = on_false_value; }

you should move the set statement outside to make it unconditional:

set wire =
  Returns the value of the first branch if the condition is true, otherwise the second branch.
Note that unlike software languages, Spade does not have conditional execution. You do not conditionally assign values inside if expressiosn, you compute a value and return it.
condition { on_true_value } else { on_true_value }

The assert Statement

The assert statement takes a boolean condition and evaluates it, raising a runtime error in simulation if it ever evaluates to false. In synthesis, this is ignored.

Note: Assert statements are silently ignored when simulating with Verilator.

Syntax

assert expression ;

Examples

assert this_should_be_0 == 0;

Comptime

TODO

Real World Example