This document covers tips for working on the Clash source tree itself. For user-facing documentation, see README.md. For an overview of the codebase, see ARCHITECTURE.md.
The repository contains the following test suites:
| Package | Suite | What it is |
|---|---|---|
clash-prelude |
unittests |
Unit tests for clash-prelude |
clash-prelude |
doctests |
Doctests for clash-prelude |
clash-lib |
unittests |
Unit tests for clash-lib |
clash-lib |
doctests |
Doctests for clash-lib |
clash-testsuite |
(executable) | End-to-end compiler tests; see below |
Copy-pastable commands:
cabal run clash-prelude:unittests
cabal run clash-prelude:doctests
cabal run clash-lib:unittests
cabal run clash-lib:doctests
cabal run clash-testsuite -- --auto-detect-tools -j$(nproc)cabal run treats anything after a bare -- as arguments to the executable
itself, not to cabal. So to forward flags like -j (parallelism) or -p
(pattern filter) to a test suite, use the double-dash:
cabal run clash-prelude:doctests -- -j8
cabal run clash-lib:unittests -- -j4 -p Netlist
cabal run clash-testsuite -- --auto-detect-tools -j8 -p .VerilogWithout the --, flags are interpreted by cabal and you'll usually get a
confusing error.
Pass --with-compiler=ghc-A.B.C to any cabal command to build/test with a
specific GHC. The compiler must be available on $PATH (e.g. via ghcup).
cabal build all --with-compiler=ghc-9.10.2
cabal run clash-lib:unittests --with-compiler=ghc-9.8.4 -- -j4The script scripts/build-with-all-supported-ghcs
loops over all currently supported GHC versions and builds the world with
-Werror. Run it before submitting a PR if you've touched code that's
sensitive to GHC version differences.
clash-prelude is a normal Haskell library, so most of the time you can just
use cabal build clash-prelude / cabal repl clash-prelude like any other
package.
HLS (haskell-language-server) does not work reliably on clash-prelude. As a
workaround, you can use the scripts/repld helper, which wraps
ghcid and auto-restarts on changes to dependencies.
./scripts/repld clash-prelude # or: ./scripts/repld p
./scripts/repld clash-prelude:tests # or: ./scripts/repld p:testsAny extra arguments are passed through to ghcid. For instance, to run a test
function main after every successful reload:
./scripts/repld p:tests -T mainHLS doesn't work well here either. Use scripts/repld:
./scripts/repld clash-lib # or: ./scripts/repld l
./scripts/repld clash-lib:tests # or: ./scripts/repld l:tests
./scripts/repld clash-ghc # or: ./scripts/repld gWhen changes touch transitive dependencies (e.g. you're hacking clash-lib
but clash-prelude also changed), repld notices and restarts the session.
For interactive Clash hacking, ./clash-dev starts a ghci
session that loads clash-lib + clash-ghc directly from source (no install
step). It's the fastest way to poke at the compiler from a REPL.
./clash-devclash-testsuite is the end-to-end test runner: it invokes the Clash
compiler on the test cases under tests/shouldwork and
tests/shouldfail, then optionally runs the generated
HDL through external simulators/synthesizers.
cabal run clash-testsuite -- --hide-successes --auto-detect-tools -j$(nproc)The test suite is quite large, so you probably only want to be notified by failing test, not every test's pass.
Many tests rely on external tools (ghdl, iverilog, verilator, vivado,
vsim/ModelSim, sby/SymbiYosys). Passing --auto-detect-tools tells the
testsuite to look on $PATH and silently skip tests for any tool that isn't
installed. Without it, you'd have to spell out --no-ghdl --no-iverilog ...
for everything you don't have.
-jN runs up to N tests in parallel. Cranking this up to $(nproc) is usually
a big win. You need about 2GB of RAM for each thread.
cabal run clash-testsuite -- --auto-detect-tools -j$(nproc)-p PATTERN is a tasty pattern that restricts which tests
run. A few useful examples:
# Only Verilog backend tests
cabal run clash-testsuite -- --auto-detect-tools -j8 -p .Verilog
# Anything with "clash" in the path
cabal run clash-testsuite -- --auto-detect-tools -j8 -p clash
# A specific test
cabal run clash-testsuite -- --auto-detect-tools -j8 -p BlockRamFile
# Combine: VHDL backend tests under shouldfail
cabal run clash-testsuite -- --auto-detect-tools -j8 -p .VHDL -p shouldfailA leading . matches a path component exactly, which is handy for backend
filters (.Verilog, .VHDL, .SystemVerilog).