SearchA-ZS › Watara Supervision

Watara Supervision

1992 Open source · Potator Online

The Watara Supervision (1992), also sold as the QuickShot Supervision, is an 8-bit handheld game console and one of the many Game Boy rivals of its era. This is the Potator emulator, whose portable C core is compiled to WebAssembly so it runs the machine directly in the browser. It is wired into the in-page debugger, where you can single-step the 65C02 CPU, set breakpoints and watchpoints, and inspect the whole memory map. The 65C02 core it reuses is a compact portable 6502/65C02 emulator, credited in the notes below.

Runs on: Web browser

Watara Supervision Online Emulator

Play Watara Supervision using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
ChimeraWatara SupervisionWatara SupervisiongreyOpen ⛶
Super PangWatara SupervisionWatara SupervisiongreyOpen ⛶
SSSnakeWatara SupervisionWatara SupervisiongreyOpen ⛶
Journey to the WestWatara SupervisionWatara SupervisiongreyOpen ⛶
Tennis Pro ’92Watara SupervisionWatara SupervisiongreyOpen ⛶
CrystballWatara SupervisionWatara SupervisiongreyOpen ⛶
Plasma (65C02 demo)Watara SupervisionWatara SupervisionopenOpen ⛶

Machines emulated

Chips

Notes

Embedding

The online build is Potator, a Watara Supervision emulator (originally by Normmatt, this fork by infval), whose emulation core is portable C with no SDL dependency. We compile only that core to WebAssembly with Emscripten and reach it through a small hand-written shim (sv_shim.c) that exposes a handful of EMSCRIPTEN_KEEPALIVE entry points — there is never a per-cycle callback across the JS/wasm boundary.

Boot and load a ROM. The module is built with MODULARIZE, so loading supervision_core.js defines a SupervisionModule() factory. Instantiate it, cwrap the shim, copy the ROM image into the wasm heap and hand it over:

const Mod = await SupervisionModule();
const sv_init = Mod.cwrap('sv_init', null, []);
const sv_load = Mod.cwrap('sv_load', 'number', ['number', 'number']);
const sv_frame = Mod.cwrap('sv_frame', null, []);
sv_init();                                // gpu_init + memorymap_init, 65C02 IPeriod = 256
const rom = new Uint8Array(await (await fetch(romUrl)).arrayBuffer());
const p = Mod._malloc(rom.length);
Mod.HEAPU8.set(rom, p);
sv_load(p, rom.length);                    // memorymap_load + hard reset

The shim surface. Everything the debugger needs is a plain C function; the wasm holds all machine state:

ExportWhat it does
sv_frame()Run one whole video frame (256 CPU slices + timer + the vblank NMI) and blit the 160×160 LCD into an RGBA buffer.
sv_step()Execute exactly one 65C02 instruction (Exec6502). The single-step primitive.
sv_render()Re-scan the LCD out of video RAM without advancing the CPU, so a stepped state shows on screen.
sv_fb()Pointer to the 160×160 RGBA framebuffer inside the wasm heap, painted to a 2D canvas.
sv_read(a) / sv_write(a,v)Bus access over RAM / I/O / video RAM / ROM. sv_read is side-effect-free (reads the register file directly, never clearing a latch).
sv_pc()The 16-bit program counter.
sv_getreg(i) / sv_setreg(i,v)Read / write the register file: A, P, X, Y, S, PC.
sv_key(bit,down)Press or release a button (D-pad, A, B, Start, Select) on the controls latch.

Debugger integration

Wiring the wasm core into the shared in-browser debugger needed one boot shim that owns the loop, plus a new 65C02 disassembler.

A host-owned loop. Rather than call any built-in frontend, the boot drives the core itself so pause / step / breakpoints work. With no breakpoints or watchpoints it runs a whole frame at once; otherwise it steps one instruction at a time and checks state between instructions:

function stepFrame(){
  for (let i = 0; i < INSNS_PER_FRAME; i++) {
    if (bps.has(sv.pc())) { running = false; return; }   // execution breakpoint
    const before = snapshotWatched();
    sv.step();                                     // one 65C02 instruction
    if (watchedChanged(before)) { running = false; return; }
  }
  sv.render();
}

Techniques for deeper access.

  • A single-instruction primitive. The stock core only ran to a cycle boundary, so Exec6502 was added to the 65C02: a one-line step flag makes Run6502 return right after one instruction, giving the debugger an exact step.
  • Side-effect-free reads. The hex and disassembly views read through sv_read, which indexes the register file, RAM and ROM directly instead of routing through the hardware read path, so auto-polling a view never clears the timer or DMA latches.
  • Direct register state. sv_getreg/sv_setreg read and write the live M6502 struct; the status byte is surfaced as clickable N/V/B/D/I/Z/C flag chips.
  • Execution breakpoints. Because the loop is host-owned, a breakpoint is a JavaScript Set of PC values compared against sv_pc() before each instruction.
  • Write watchpoints. With no per-write hook across the wasm boundary, watched addresses are snapshotted before each instruction and compared after; a change pauses the loop — the same visible behaviour as a store watchpoint.

A new 65C02 decoder. debugger/src/cpus/w65c02.js was added: the shared NMOS 6502 table plus the 65C02 additions the Supervision runs (STZ, BRA, the stack ops PHX/PHY/PLX/PLY, TSB/TRB, BIT immediate, the (zp) indirect mode, JMP (abs,X)) and the Rockwell bit ops, with a .byte fall-back for raw data.

Architecture

The Watara Supervision (1992), also sold as the QuickShot Supervision, is an 8-bit handheld game console and one of the many Game Boy rivals of its era. It is built around a 65C02 (a CMOS 6502) running at about 4 MHz, with a 160×160 monochrome LCD showing four shades of grey.

  • 65C02 CPU — the CMOS 6502: the accumulator A, index registers X and Y, stack pointer S, 16-bit PC and the N/V/B/D/I/Z/C status flags, plus the 65C02 instruction additions.
  • Memory map — 8 KB system RAM at $0000, the I/O register block at $2000, 8 KB video RAM at $4000 that the LCD scans, and the cartridge ROM banked into $8000$FFFF.
  • Video — a scanline is read straight out of video RAM using the XPOS/YPOS/XSIZE registers; each byte packs four 2-bit pixels.
  • Timer & interrupts — a programmable timer and a vertical-blank NMI drive the machine; two bytes at $2024/$2025 latch the timer and DMA interrupt sources.

The 65C02 core the machine runs is a compact portable 6502/65C02 emulator (the M6502 / M65C02 by Marat Fayzullin and contributors), reused unchanged inside Potator; only a single-instruction step entry point was added for the debugger. The whole machine lives inside the WebAssembly module, and the debugger reads it each refresh through the shim.