2 unstable releases

new 0.2.0 Feb 21, 2025
0.1.0 Feb 9, 2025

#3 in #🦀

Download history 107/week @ 2025-02-04 19/week @ 2025-02-11

126 downloads per month

MPL-2.0 license

1MB
1.5K SLoC

Rust 1K SLoC // 0.0% comments JavaScript 253 SLoC // 0.0% comments

marlin 🐟

CI Badge Code Style Badge cargo-deny badge Crates.io Version docs.rs Crates.io License

Read the documentation

Marlin is a really powerful library (and API) that lets you "import" hardware modules into Rust (or Rust functions into hardware modules!).

No precompilation step and manual updates with verilator harnesses; no Makefiles and quirky decorators with cocotb testbenches. You're writing a regular Rust crate here.

Add this library to your Cargo.toml like any other library. Use hardware modules as structs like any other Rust struct. Hook them up to tokio or serde even. cargo test as hard as you want.

Marlin works out of the box on macOS and Linux (verified under continuous integration).

Early example of using this with Spade

[!NOTE] The above screenshot is pre-0.1.0, so it's a bit out of date -- Marlin has improved a lot since then!

🔥 Motivation

Why does hardware testing suck? Consider the ways we have to test (System)Verilog:

  • Test natively: Verilog is already a terrible enough language, and writing tests in Verilog is really annoying.
  • Use verilator harnesses: You have to first run Verilator to get the right headers, recompile manually every time, deal with raw pointers and C++, etc.
  • Use cocotb: You have to use Makefiles or write your own Python runner, performance isn't the greatest, you get no LSP support for ports, etc.

The problem gets worse with custom HDLs, so they've come up with some creative solutions:

Still, a lot of these are less than optimal.

✨ Features

  • 🚀 Minimal overhead over directly using verilator
  • 🔌 Works completely drop-in in your existing projects
  • 🪙 Declarative API for usability + Dynamic API for programmability
  • 🔄 DPI support in Rust: call Rust functions from (System)Verilog
  • 🦀 Rust. Did I say Rust?

⚡️ Requirements

📦 Install

Marlin is on crates.io, so just use cargo add --dev marlin to add Marlin as a dependency for your tests (dev-dependencies).

❓ How it works

I'll write more on this once I get further in the development process. The TLDR is procedural macros + dlopen.

Hardware simulation tools are slow! How does Marlin deal with that?

Simulation tools take an absurd amount of time to run. For example, when you use Marlin in a Spade project, it calls out to:

  • swim build, which recompiles the entire Spade compiler from source
  • verilator, which compiles and links C++ code

Marlin automatically running them with all the right flags and arguments --- and it caches and only invokes them when needed.

  • verilated-rs is a super cool library that uses a build script to statically link in verilated bindings, but is unmaintained for years as of writing this.

Marlin is licensed under the Mozilla Public License 2.0. This license is similar to the Lesser GNU Public License, except that the copyleft applies only to the source code of this library, not any library that uses it. That means you can statically or dynamically link with unfree code (see https://www.mozilla.org/en-US/MPL/2.0/FAQ/#virality).

I use cargo-deny (see the deny.toml to ensure no licensing violations occur. I also check this on CI to prevent merging any new dependencies or dependency updates that introduce incompatible licenses.

Dependencies

~10–18MB
~231K SLoC