LANGUAGES Signal 362
Solving Advent Of Code on FPGAs with Haskell Clash
The post demonstrates solving an Advent of Code puzzle by writing the solution in Haskell with Clash and synthesizing the resulting design onto an FPGA.
For engineers, it shows how a functional programming language can be used as a hardware description language, allowing high-level algorithmic expression to be turned into synthesizable logic. It also outlines the concrete steps required to set up a Clash development environment, iterate on designs, and verify the output on real hardware.
Written by elseif from the cluster below · every claim links back to a sourceThe three things worth knowing
Clash translates a synthesizable subset of Haskell into low-level HDL such as Verilog, enabling FPGA implementation of algorithms expressed functionally.
Exact circuit widths are enforced at compile time using type-level natural numbers, which rely on the DataKinds extension and singleton types like SNat to be known before synthesis.
The workflow involves cloning the repository, launching a REPL with specific GHC plugins, writing incremental designs, generating a bitstream, and loading it onto an FPGA to compute the Advent of Code answer.
THE READ
What the cluster adds up to.
The author begins by treating the Advent of Code day-four problem as a hardware task: a grid that evolves like a single-rule Game of Life is modeled as a synchronous circuit. Using Clash, the grid update rule is written as a pure Haskell function that operates on fixed-size vectors. This function is then annotated with Clash types so that the compiler can produce a netlist ready for synthesis. The approach lets the designer focus on the algorithmic logic while Clash handles the translation to timing-aware hardware.
To guarantee that wires have the correct bit-width, Clash uses type-level natural numbers. These numbers are expressed through the KnownNat constraint, which requires the DataKinds language extension and singleton values such as SNat. The singleton carries the concrete size information at the type level, allowing operations like addition or multiplication on sizes to be resolved during compilation. The post notes that enabling the GHC plugins for type-level solving makes working with these constraints more ergonomic in the REPL.
Practical development starts with cloning the advent-of-clash repository and launching a nix-based REPL that loads the Clash prelude and utility modules. The author shows an example interaction where a helper function showDigit produces a binary literal, confirming that the environment is correctly set up. From there, three incremental designs are built: first a simple combinational block, then a sequential register holding the grid state, and finally a top-level module that drives the design on an FPGA board. Each step is verified in simulation before proceeding to synthesis.
Adopting this flow entails learning both Haskell and the Clash subset that maps to synthesizable hardware, which can be a steep climb for engineers accustomed to traditional HDLs. The resulting design is also bounded by the resources of the target FPGA; large state tables or wide data paths may exceed available logic or memory. Moreover, only the synthesizable fragment of Haskell is supported, so features like arbitrary recursion or lazy data structures cannot be used directly. Despite these constraints, the method provides a clear path from high-level algorithm to working hardware for suitably sized problems.
Written by elseif from the cluster below · checked for specifics the sources never containedTHE CLUSTER
↗