Spade
Spade is a new hardware description language which aims to make hardware description easier and less error prone. It does this by taking lessons from software programming languages, and adding language level support for common hardware constructs, all without compromising low level control over what hardware gets generated.
Using Spade
Spade is in its early stages, so everything is subject to change. You can build things with it but be prepared for bugs and missing features.
For an overview of what Spade is, have a look at this talk from June 2022. Documentation is very much a work in progress, but some is available in our book.
The Swim build tool
The recommended way of using Spade is with its build tool Swim.
Learn more
Feel free to follow the development either on Gitlab or in our Discord community server.
An Overview of the Language
Basic Semantics
As a basic example, a counter with a runtime-selectable maximum value can be written as
entity counter(clk: clk, rst: bool, max: int<10>) -> int<10> {
reg(clk) x reset (rst: 0) =
if x == max {0} else {trunc(x + 1)};
}
Spade, like Verilog and VHDL, describes the behaviour of a circuit from one cycle to the next. There is no magic execution model or overhead.
Most constructs in Spade are combinational. Sequential elements like registers are explicit language constructs.
Spade is also an expression based language. To conditionally assign a value to a variable, you assign the result of an if expression to the variable.
Language Level Pipelines
Pipelines are a first class construct in Spade, making retiming and re-pipelining trivial.
pipeline(4) X(clk: clk, a: int<32>, b: int<32>) -> int<64> {
let product = a * b;
reg * 3;
let result = f(a, product);
reg;
result
}
Types and Enums
Spade has a powerful type system with structs, arrays, tuples and algebraic data types called enums. Unlike the enums of C and Verilog, they can have associated payload.
You can model a value which may or may not be available with the Option
enum:
enum Option<T> {
Some(val: T),
None
}
Or why not model the instruction set of a CPU?
enum Insn {
Set { dreg: int<5>, val: int<32> },
Add { dreg: int<5>, lhs: int<5>, rhs: int<5> },
Sub { dreg: int<5>, lhs: int<5>, rhs: int<5> },
Jump { target: int<32> }
}
The compiler ensures that fields can only be accessed if the value is of the
correct type. For example, if the instruction is a Jump
, there is no way to
access a dreg
field.
Pattern Matching
Enums work really well with pattern matching which allows you to check conditions and easily bind sub-values to variables.
You can easily build an ALU:
fn alu(insn: Insn, rs1: int<32>, rs2: int<32>) -> int<32> {
let adder_result = match insn {
Insn::Add(_, _, _) => rs1 + rs2,
Insn::Sub(_, _, _) => rs1 - rs2,
Insn::Set(_, val) => sext(val),
Insn::Jump(_) => 0,
};
trunc(adder_result)
}
Or select the first of two values, and 0 if none are present:
let result = match (a, b) {
(Some (x), _) => x,
(_, Some(x)) => x,
_ => 0
}
Type inference
Spade has powerful type inference which gives you the benefits of static types, without all the typing.
Great Error Messages
The compiler should be your friend. Error messages give you as much information as possible
error: Match branches have incompatible type
30 +-Insn::Add(_, _, _) => rs1 + rs2,
| ^^^^^^^^^
| This branch has type int<33>
32 | Insn::Set(_, val) => val,
| ^^^ But this one has type int<32>
|
= Expected: 33 in: int<33>
= Got: 32 in: int<32>
Bad error messages are considered a bug. Please report them!
Helpful tooling
Spade comes with a great set of tools around the language
- The official build tool Swim manages
your dependencies, calls synthesis tools and runs your tests. It can even
create a new project for you with a single command!
- Of course you can put the generated Verilog into your regular build flow as well.
- Tests are written in cocotb, allowing you to take advantage of python for all your testing needs.
- VCDs coming out of tests are automatically translated to include Spade type information so you never have to decode individual bits in your waveform.
Planned features
There are also some planned features:
- Integer ranges as types.
- Generics with traits
- Clock domain information on types.
- Mixing domains without explicit synchronization is a compilation error.
- Related: clock domain inference where the domain is obvious.
- And more...
Publications
To cite Spade itself, use the zenodo record.
- Frans Skarman, Oscar Gustafsson. Spade: An Expression-Based HDL With Pipelines. April 2023. In: 3rd Workshop on Open-Source Design Automation (OSDA).
- Frans Skarman, Oscar Gustafsson. Abstraction in the Spade Hardware Description Language. March 2023. In: 3rd Workshop on Languages, Tools, and Techniques for Accelerator Design (LATTE).
- Frans Skarman, Oscar Gustafsson. Spade: An HDL Inspired by Modern Software Languages. August 2022. In: 32nd International Conference on Field-Programmable Logic and Applications (FPL).
Development
Spade is currently being developed as an Open Source project at the Division of Computer Engineering, Department of Electrical Engineering, Linköping University, Sweden.
License
The Spade compiler and other tooling is licensed under the EUPL-1.2 license. The Spade standard library and this website is licensed under the terms of both the MIT license and the Apache license.