Nix flake for working with the Altera DE2 (Cyclone II EP2C35F672C6) on
NixOS in 2026 — using Haskell Clash for the design and Quartus II
13.0sp1 Web Edition for synthesis, place-and-route, and flashing over the
board's onboard USB Blaster.
Cyclone II support was dropped in Quartus II 13.1, so 13.0sp1 is the last
version of any Quartus edition that can target the DE2. Since it's a 32-bit
vendor blob that nixpkgs does not ship, we wrap it in an FHS environment
with the 2013-era libraries it expects (libpng12, libudev.so.0 shim,
32-bit GTK/X11, etc.).
Scope: classic DE2 board only. DE2-70 and DE2-115 have different FPGAs and pin assignments — this flake will not synthesize correctly for them.
-
Download Quartus II 13.0sp1 Web Edition for Linux from Altera:
- https://www.altera.com/downloads/fpga-development-tools/quartus-ii-web-edition-design-software-version-13-0sp1-linux (click through the license agreement)
- Direct CDN: https://downloads.intel.com/akdlm/software/acdsinst/13.0sp1/232/ib_tar/Quartus-web-13.0.1.232-linux.tar
- Internet Archive fallback: https://archive.org/details/quartus-web-13.0.1.232
Expected sizes/hashes:
- 4.49 GB (
4,818,657,280bytes) - SHA1
2b110eff0d544bcda4013e265f6feaa507482357 - SRI
sha256-2sTQP/tpxGV5YjQ/3q9cIMpxXsvwbuG8fgD+MPy860w=
-
Pin the tarball into the local Nix store:
nix-prefetch-url --type sha256 file://$HOME/Quartus-web-13.0.1.232-linux.tarThat adds the file under
/nix/store/…-Quartus-web-13.0.1.232-linux.tar;requireFileinpkgs/quartus-ii-13/sources.nixresolves it by the pinned hash on every subsequent build.Keep a backup outside any Nix GC root (e.g.
~/quartus-backup/) so you don't have to re-download if Altera ever rotates the URL. -
(On NixOS host) enable the USB Blaster udev rules by importing the module into your system configuration:
# configuration.nix { inputs.alterade2-flake.url = "path:/home/mika/alterade2-flake"; # … imports = [ inputs.alterade2-flake.nixosModules.usb-blaster ]; hardware.altera-usb-blaster.enable = true; }
Rebuild and reboot (or at least
systemctl restart systemd-udevd).
# Enter a dev shell with clash, clashi, quartus_sh, quartus_pgm, gtkwave, …
nix develop
# Build just the Quartus toolchain (produces bin/quartus_sh etc. under ./result)
nix build .#quartus-ii-13
# Synthesize the DE2 Blinky — Clash → Verilog → Quartus → Blinky.sof
nix build .#de2-blinky
# Flash the resulting .sof over the USB Blaster (board must be plugged in)
nix run .#flash-de2
# Reformat all .nix with alejandra + deadnix + statix
nix fmtAfter nix build .#de2-blinky, the output tree contains:
result/
├── Blinky.sof # bitstream for quartus_pgm
├── reports/
│ ├── Blinky.fit.rpt # place-and-route summary
│ ├── Blinky.map.rpt # synthesis summary
│ ├── Blinky.sta.rpt # timing analysis
│ └── Blinky.asm.rpt
└── verilog/
└── Blinky.topEntity/
└── blinky.v # Clash-generated Verilog
Follow the shape of pkgs/de2-blinky/:
YourDesign.hs— a Clash module definingtopEntityplus a{-# ANN topEntity (Synthesize {...}) #-}with explicitPortNames.YourDesign.qsf— Quartus pin assignments; seeBlinky.qsffor the reusable DE2 pin block (CLOCK_50, KEY[0..3], LEDR[0..17], LEDG[0..8]).YourDesign.sdc— timing constraints;create_clock -period 20.0 [get_ports CLOCK_50]at minimum.YourDesign.qpf— trivial project file withPROJECT_REVISION.- A
package.nixcopied frompkgs/de2-blinky/package.nixwith theBlinkystring replaced.
| Target | File | Behaviour |
|---|---|---|
| FPGA SRAM | .sof |
Loaded immediately via JTAG; lost on power cycle. |
| EPCS64 flash | .jic |
Permanent; survives power cycle. Generate via quartus_cpf -c Blinky.cof. |
For day-to-day development, .sof is what you want — nix run .#flash-de2
uses it. Only use .jic when you want the design to persist across reboots.
quartus_sh: Unable to open USB device— stale jtagd.killall jtagdand retry; theflash-de2app does this automatically.jtagdcannot findpgm_parts.txt— symlink it into place:sudo mkdir -p /etc/jtagd && sudo ln -s result/share/altera13.0sp1/quartus/linux/pgm_parts.txt /etc/jtagd/jtagd.pgm_parts.- Segfault on startup (
quartus_sh) — known glibc ≥ 2.34 interaction; trysetarch x86_64 -R quartus_sh …(disables ASLR). lsusbdoesn't show09fb:6001— USB cable / port issue, or the udev module was enabled without a udev reload. Trysudo udevadm control --reload && sudo udevadm trigger.
alterade2-flake/
├── flake.nix # flake-parts entrypoint
├── flake.lock
├── README.md
├── CLAUDE.md
├── nix/ # flake-parts modules
│ ├── default.nix
│ ├── devshell.nix
│ ├── treefmt.nix
│ └── checks.nix
├── nixos-modules/
│ └── usb-blaster.nix # hardware.altera-usb-blaster.enable
├── pkgs/
│ ├── default.nix # perSystem wiring
│ ├── quartus-ii-13/
│ │ ├── sources.nix # requireFile + pinned hash
│ │ ├── unwrapped.nix # vendor installer → $out/opt/…
│ │ ├── fhs-env.nix # buildFHSEnv + libudev shim
│ │ └── package.nix # bin/<tool> wrappers
│ └── de2-blinky/
│ ├── Blinky.hs # Clash source
│ ├── Blinky.qsf # DE2 pins
│ ├── Blinky.sdc # timing
│ ├── Blinky.qpf # Quartus project file
│ └── package.nix # builds Blinky.sof
└── apps/
└── flash-de2.nix # nix run .#flash-de2