logo Spade Blog

Spade 0.4.0

Posted 2023-08-24 by Frans Skarman and Gustav SΓΆrnΓ€s

After a small summer break, it's time to release Spade 0.4.0. It contains an important milestone for Spade and several improvements to the surrounding tooling along with the usual batch of small fixes and changes.

Write your top module in Spade, not Verilog!πŸ”—

A very exciting milestone is that writing Spade projects no longer requires writing a Verilog shim! Historically, every Spade project has needed an outermost Verilog file that takes care of two things:

  1. Generating a reset signal.
  2. Naming the signals from the pin file that will be used and passing them to the Spade code.

From now on, you can do all these things directly in Spade. You can see this in action in the updated swim templates repository.

Initial values for registersπŸ”—

One change required for the previously mentioned heading is the possibility to specify initial values for registers. For example, here is how you would define a reset signal that is initialized to true and then set to false at the first clock cycle.

reg(clk) rst initial (true) = false;

WAL integrationπŸ”—

In the Spring, we did a collaboration with the WAL project. WAL is a language for analyzing simulation waveforms which makes it much easier to get high level information out of your simulation results.

The result of our joint work is a way to bundle WAL analysis code with Spade libraries, a set of annotations to effortlessly request the use of the analysis passes, and integration with Swim to allow running the requested passes in a single command - swim plugin analysis.

As an example of the capability this adds we can look at a project consisting of two devices communicating with a shared device via two wishbone buses connected to an arbiter.

We'll add the wishbone bus as a dependency to the project, along with the WAL analysis plugin:

[libraries.wishbone]
git = "https://gitlab.com/spade-lang/lib/fishbone"
branch = "main"

[plugins.wal_analysis]
git = "https://gitlab.com/spade-lang/wal_analysis"
branch = "main"

Then we'll instantiate two wishbone buses, connect their inputs and outputs to the master and arbiter:

entity wb_harness(clk: clock, rst: bool)
  -> (int<16>, int<16>)
{
    let (wb1, wb1inv) = port;
    let (wb2, wb2inv) = port;

    #[wal_trace(clk=clk, rst=rst))]
    let wb1 = wb1;
    #[wal_trace(clk=clk, rst=rst))]
    let wb2 = wb2;

    let _ = inst wishbone_arbiter( clk, rst, wb1inv, wb2inv, ...);
    let o1 = inst wishbone_master( clk, rst, wb1, ...);
    let o2 = inst wishbone_master( clk, rst, wb2, ...);

    (o1, o2)
}

The two #[wal_trace] attributes are where the magic happens. This tells the compiler to emit some special signals that the analysis scripts in the wishbone library should look for.

With this in place, after running swim plugin analysis you will get a whole bunch of high level information about the two buses:

[ANALYSIS] # wb_harness.wb1
[ANALYSIS]    Nr. transactions : 697
[ANALYSIS]    Nr. reads        : 16
[ANALYSIS]    Avg read latency : 6 clock cycles
[ANALYSIS]    Nr. writes       : 681
[ANALYSIS]    Avg write latency: 9 clock cycles
[ANALYSIS]    Inactive cycles  : 6%
[ANALYSIS] # wb_harness.wb2
[ANALYSIS]    Nr. transactions : 421
[ANALYSIS]    Nr. reads        : 0
[ANALYSIS]    Avg read latency : - clock cycles
[ANALYSIS]    Nr. writes       : 421
[ANALYSIS]    Avg write latency: 12 clock cycles
[ANALYSIS]    Inactive cycles  : 22%

And you'll even get a histogram showing the number of transactions over time which can give a lot of insight into the behaviour of the system.

Histogram showing the number of bus transactions over time

We will present this work at FDL 2023. If you want to learn more and see how it is implemented, you can read our paper.

Swim Simulation ImprovementsπŸ”—

Swim has also gotten some love recently. It now discovers and runs each test case in parallel instead of the previous fully sequential test running. Along with that, it has a new UI for the test running which scales with the size of your terminal, shows which tests are running, waiting and done, and only prints the stdout of failed tests. All of this is easier to showcase in a video:

Open VCD files in a single clickπŸ”—

In addition, if you run swim setup-links and run a terminal that supports OSC8 hyperlinks, swim will now print links to open the wave file from an individual test in a waveform viewer.

A new waveform viewerπŸ”—

Frans Skarman

Finally, in that last video you may have noticed an unusual waveform viewer. It is called surfer and is something I've been working on and off for the past few months. My goals here are a wave viewer with a nice to use interface and which is easy to integrate with languages like Spade where signal values are more than just bits. For Spade, that means it can translate Spade types into their fields or enum variants, but the translation interface is general, so other projects should also be able to add similar features.

The interface is snappy and thanks to some work by Lucas Klemmer of WAL fame, it also has a very nice keyboard centric interface as you can see in the next video.

The project is still in its early stages, but I have been using it for all my wave surfing needs for the past few weeks. You can follow along at https://gitlab.com/surfer-project/surfer.