Game Boy — written in Mere

A Sharp LR35902 (Game Boy) emulator compiled from Mere to WebAssembly. The same machine that passes Blargg's cpu_instrs suite (11/11, interrupts included) on all four Mere backends — CPU, timer, interrupt controller, PPU, and MBC1 cartridge banking — here renders to a <canvas>, driven per frame by dom_on_frame.

A tiny playable cartridge (game.gb, hand-written in RGBDS assembly): use the arrow keys to move the sprite — it plays a startup arpeggio and beeps while you move (audio starts on your first key press, per the browser autoplay policy). The same emulator also runs dmg-acid2, the reference PPU test (swap the fetched ROM to dmg-acid2.gb). The cartridge is served to the Wasm module a byte at a time via a small dom_rom_byte host import; keys are polled through dom_key_held; the APU's two pulse channels drive dom_audio_tone onto Web Audio; and the 160×144 framebuffer is blitted (only the pixels that changed each frame) with the classic DMG green palette.

What's happening

  1. mere -w -I . gameboy.mere lowers the whole machine — the LR35902 core, the timer/interrupt spine, the scanline PPU, and MBC1 banking — to WebAssembly.
  2. The page fetches dmg-acid2.gb and hands it to the glue (setRom); the module pulls it in through dom_rom_size / dom_rom_byte.
  3. Each requestAnimationFrame runs a slice of the CPU (advancing the timer, PPU, interrupts, and APU), repaints the pixels that changed via dom_canvas_fill_rect, and maps the sound channels onto Web Audio through dom_audio_tone.