Spade 0.8.0
Posted 2024-05-14 by The Spade Developers
Today we're releasing v0.8.0
of Spade. This release adds a bunch of new stuff
to the standard library, fixes a bunch of papercuts around test and adds
inout<T>
to work with inout ports. We also had 2 new contributors in this
release which is very fun to see, thanks @0xC01DC0FFEE and @phire
Add reduce_*
functions (first contribution)🔗
@0xC01DC0FFEE added three new functions to std::ops
:
fn reduce_and<#N>(x: uint<N>) -> bool
fn reduce_or<#N>(x: uint<N>) -> bool
fn reduce_xor<#N>(x: uint<N>) -> bool
These compute the and
, or
and xor
of all bits in a number. reduce_xor
is especially useful for computing parity.
stage
improvements (first contribution)🔗
Scott Mansell (@phire) has fixed several issues this release. The most
important fix resolves a long-standing issue where referencing pipeline
variables using stage
inside blocks would cause a panic. With this change,
you can now write
let x = if condition {stage(+1).y} else {stage(+2).y}
reg;
let y = /* ... */;
reg;
Higher level memory primitives in std::mem
🔗
std::mem::dp_bram
provides a more structured primitive for working with dual
port memories. Unlike the raw std::mem::clocked_memory
primitive which can be
used to model any memory but is quite clunky to use in the common case, the
dp_bram
provides a memory with one read port and one write port that can
belong to different clock domains.
Writing to the memory is done using the std::Mem::WritePort
struct
entity writer(
clk: clock,
wport: WritePort<10, uint<16>>,
) {
let (addr0, write_val0) = /* ... */;
set wport.addr = addr0;
set wport.write = write_val0;
}
And reads are done on the ReadPort
struct, preferably using std::mem::read_read_port
pipeline(1) reader(
clk: clock,
rport: ReadPort<10, uint<16>>,
) -> [[uint<16>; 3]; 3] {
let addr0 = /* ... */;
let addr1 = /* ... */;
let out0 = inst(1) read_read_port(clk, addr0, rport)
// Since the memory read unit is a pipeline, we can't accidentally forget that the memory
// has read latency
reg;
// Do something fun with the read values!
}
The dp_bram
module returns two ports which you can then pass along to the reader and writer
entity top(clk: clock) {
let (write, read) = inst dp_bram::<1024, uint<16>, 10>$(write_clk: clk, read_clk: clk);
let _ = inst writer(clk, write);
let _ = inst reader(clk, read);
}
One big advantage of this is that since the memory ports are struct port
, the compiler
will ensure that there aren't multiple users of the ports. For example, the following code results
in a compilation error
entity top(clk: clock) {
let (write, read) = inst dp_bram::<1024, uint<16>, 10>$(write_clk: clk, read_clk: clk);
let _ = inst writer(clk, write);
let _ = inst reader(clk, read);
// ^^^^ First use here
let _ = inst reader(clk, read);
// ^^^^
// Use of consumed resource
}
Clock domain crossing primitives🔗
The second addition to the stdlib is the new
std::cdc
module which contains primitives for crossing clock domains. The primary
additions are std::cdc::sync2_bool
, std::cdc::sync_wide
and
std::cdc::handshake
which provide primitives for a few different crossing
scenarios. All of these are extremely danger if used incorrectly, so make
sure to read the documentation for the
modules
to make sure that you satisfy the constraints they have to behave correctly.
Test improvements🔗
We have made several improvements to the testing system in Spade
A minor but important change is that tests now support modules that return
void
. In addition, the verilator
wrapper now works on modules with &mut
inputs.
For verilator
tests, we have also added .spade_repr
to fields which returns
a human-readable Spade representation of the field. This is useful if you need
to, for example, print a result.
Using these changes, it is possible to use the simulation speed of Verilator
to write "interactive" test benches, here is an example of a testbench that
visualizes the memory access pattern of a camera project I'm working on:
Latch-Up presentation🔗
Two weeks ago, Frans presented Spade at Latch-Up 2024 in Boston. You can see a recording of the talk here: