Show Discourse: A RISC-V Emulator, built using Nix

Hello *,

I’d like to take a short second to announce a project I’ve been working on, which is a 32-bit RISC-V emulator named rv32-sail. You can play with it online, right now, in your browser. You can also look at the source code, which does not mine any bitcoins. Be sure to use any web browser you want to view this web page, as long as that browser is Chrome.

You might be wondering why I’m announcing an emulator for a computer when you already own a real computer. That’s because this computer and its software is developed almost entirely with Nix – and I believe, it would not have been possible to put together so easily without it.

This project is comprised of multiple moving components so that it can be reliably developed and tested, including:

  • A full cross compiler build of GCC,
  • A bunch of demos,
  • A bespoke programming language, used to describe the RISC-V ISA and its semantics,
  • A continuous integration and deployment system, built using GitHub Actions, that can deploy Docker containers for demos, and Cachix artifacts for developers,
  • A fancy build system written in Haskell that’s pretty cool,
  • A bunch of really lovely Nix code,
  • Other spooky stuff I won’t elaborate much on! (Static linking with pkgsMusl, nixpkgs bootstrap code, a few code generators, etc)

However, this project relevant to Nix developers, I think – because it shows how you can put together a complete, bespoke project. If you are still struggling to think about how things fit together, this project is certainly a non-trivial example that tries to be reliable, maintainable, and I strive to keep it easy to understand. And almost all of these features are made possible and driven by Nix at some level. (Years ago, I wouldn’t have even thought of putting together a project like this, since simply maintaining and reliably managing all of these moving components can become extremely difficult in the long run. Alternatively, I would have had to greatly restrain its scope and utility.)

My inevitable goal isn’t just to make jokes, but to take this project quite a bit further, over time – not an especially simple task. Therefore I think Nix is a crucial component of its success as a vehicle for my own research. It also served as a really useful testing ground for new ideas, like automating it with GitHub, which I will continuously use in the future. Either way, I think this is a powerful example of what Nix makes possible, so I want to show it off!

There are also a bunch of other bits that are probably more reusable, for example, all of the GitHub actions can probably be fleshed out and refined. These tools should give a pretty easy and first-party way for Nix developers to deploy build artifacts. Here are some samples:

  • There is a nix-build action for performing Nix builds, using @LnL7’s nix-docker container. This action is very bespoke to my current build system, but shows the possibilities of driving builds including using dockerTools.buildLayeredImage, and tricks like exporting store closures.
  • A cachix action, which can allow you to upload build artifacts from a store into Cachix on commit. This is an easy way to integrate Cachix with simple projects, but requires some finagling, since it requires using nix copy --from to copy from a local closure.
  • A skopeo action – this one is probably really useful for Nix developers. For those who aren’t aware, skopeo lets you copy the result of dockerTools.buildLayeredImage – a tarball file – into a remote Docker repository. So if you combine this with something that invokes nix-build – you get free deployment on every commit! I use this to deploy a statically linked binary to Docker Hub

I think these combine together to make a pretty easy-to-use set of tools to deploy Nix applications, and we could do a lot more with them.

I’m more than happy to accept contributions or answer questions about these components – and if you want to try doing some low level/bare metal programming, you might find riscv32-sail entertaining! Happy hacking.