A RISC-V fantasy console — written in Mere

Two Mere programs, all the way down. The cartridge is a Mere program compiled by mere -rv straight to a flat RV32IM binary — no assembler, no linker. The console is the Mere-written RISC-V emulator (the same RV32IM core as memu) compiled to WebAssembly. So this page is a Mere-authored CPU, running in the browser, executing a Mere-authored game.

Use the arrow keys to move the cyan block around the field (the yellow dots are just scenery). Every frame, the emulator refreshes a memory-mapped input register from your held keys, runs the RV32IM cartridge until it calls present, then blits the 64×32 framebuffer to the <canvas>.

How the two halves meet

The cartridge and console share a tiny hardware contract — three operations the mere -rv backend lowers to bare machine code and memory-mapped I/O:

What's happening

  1. mere -rv game.mere > game.bin lowers the cartridge to a ~3 KB flat RV32IM binary.
  2. mere -w -I . rvconsole.mere lowers the RV32IM emulator to WebAssembly.
  3. The page fetches game.bin and hands it to the glue (setRom); the module reads it a byte at a time through dom_rom_size / dom_rom_byte into its emulated RAM at address 0.
  4. Each requestAnimationFrame polls the keys, runs the CPU to the next present, and repaints the framebuffer via dom_canvas_fill_rect.