SearchA-ZC › Commander X16

Commander X16

2021 Open source · BSD-2-Clause System ROMs · open Online

The Commander X16 (2021) is a modern 8-bit home computer designed by David "the 8-Bit Guy" Murray, built from period-correct parts: a WDC 65C02 CPU at 8 MHz, the FPGA-based VERA video/audio chip (640×480 VGA, tiles, sprites and PSG+PCM sound), and Commodore-style BASIC in ROM. This build is x16emu, the official X16Community emulator, compiled from C to WebAssembly with Emscripten and self-hosted here, so it boots straight to the X16 BASIC READY. prompt with no downloads. Its 65C02 core was extended with debugger hooks, so the whole machine can be single-stepped, breakpointed, watch-pointed and inspected live from the browser.

Visit the project on GitHub ↗

Visit the official site ↗

Runs on: Web browser

Commander X16 Online Emulator

Play Commander X16 using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
X16 BASICCommander X16Commander X16openOpen ⛶
Hello World demoCommander X16Commander X16openOpen ⛶
10 PRINT maze demoCommander X16Commander X16openOpen ⛶

Machines emulated

Chips

Notes

Embedding

x16emu is the official Commander X16 emulator (X16Community), a C program built to WebAssembly with Emscripten. It ships its own Module-based runtime and drives an SDL2 canvas from a C main() that installs an emscripten_set_main_loop frame callback. You embed it by defining window.Module (canvas, command-line arguments, keyboard element) and loading x16emu.js; the ROM is preloaded into the virtual filesystem as /rom.bin.

var Module = {
  canvas: document.getElementById('canvas'),
  arguments: ['-keymap', 'en-us', '-c02'],   // -c02 = force the 65C02 CPU
  preRun: [function(){ ENV.SDL_EMSCRIPTEN_KEYBOARD_ELEMENT = "#canvas"; }],
  onRuntimeInitialized: publishBoot          // wasm ready: expose the debugger hooks
};

Keyboard. The X16 uses a standard PC keyboard. SDL2 already listens for real keydown/keyup on the canvas, so the physical keyboard works once the canvas is focused. The on-screen keyboard reuses that path: each key synthesises a DOM KeyboardEvent (correct code, key and a latched Shift) and dispatches it at the canvas, so on-screen and physical keys are handled identically.

function dispatchKey(type, code, shift){
  var ev = new KeyboardEvent(type, { key: keyFor(code, shift), code: code, shiftKey: shift, bubbles: true });
  canvas.dispatchEvent(ev);
}

Text paste. The core also exports j2c_paste(str), which types a whole string into the KERNAL keyboard buffer — handy for injecting a BASIC demo. j2c_reset() resets the machine.

Debugger integration

A pure-WebAssembly core has no JavaScript objects to poke, so the debugger's needs were added to the C source as a small set of EMSCRIPTEN_KEEPALIVE exports (in src/javascript_interface.c), listed in EXPORTED_FUNCTIONS and reached from JS through the Emscripten Module. Nothing else in the emulator was changed except two one-line gates.

ExportWhat it does
dbg_reg_get(i) / dbg_reg_set(i,v)Read / write a live 65C02 register (0=A 1=X 2=Y 3=SP 4=PC 5=P) straight off the core's regs struct.
dbg_mem_read(a)Side-effect-free read of the banked 64K CPU bus via the core's debug_read6502 (skips the I/O latches).
dbg_mem_write(a,v) / dbg_ram_read(a)Poke the CPU bus; read the raw fixed low-RAM image.
dbg_step_insn(n)Execute exactly n instructions synchronously (calls the core's step6502()), so the debugger's Step advances the PC immediately.
dbg_set_pause(p) / dbg_get_pause()Freeze / resume the free-running RAF loop.
dbg_bp_toggle(a) / dbg_wp_toggle(a)Toggle an execution breakpoint (checked against PC in the loop) / a memory-write watchpoint (checked in write6502).

Two gates make the loop controllable. At the top of emulator_loop():

if (dbg_pause) return 0;                          // frozen: run no instruction, yield to the browser
if (dbg_bp_count && dbg_bp_map[regs.pc]) {        // PC breakpoint hit
  dbg_pause = 1; dbg_hit = 1; return 0;
}

and inside write6502() a watchpoint sets dbg_pause so execution halts right after the writing instruction. Because dbg_step_insn calls step6502() directly (not the RAF loop), stepping is synchronous: the JS transport can step and immediately re-read the PC and memory. Register writes, breakpoints and watchpoints all round-trip through these exports. The disassembler is the shared mos6502 decoder: the X16's 65C02 is an 8-bit core with 1-byte immediates, so mos6502 keeps disassembly framed correctly (the 65C816 w65816 decoder assumes 16-bit immediates and would mis-align every LDA #imm).

Architecture

The Commander X16 is a modern 8-bit home computer designed by David "the 8-Bit Guy" Murray, built from real period-correct parts:

  • CPU — a WDC 65C02 (the CMOS 6502) clocked at 8 MHz. x16emu also supports the 16-bit 65C816 as an option; this build boots the 65C02 (-c02).
  • VERA — the Video Enhanced Retro Adapter, an FPGA video/audio chip: a 640×480 VGA display with layered tile and bitmap modes, 128 sprites, a 16-voice PSG plus PCM audio. It lives in the I/O page at $9F20-$9F3F.
  • Memory map — 64K address space: fixed low RAM at $0000-$9EFF, the I/O page at $9F00-$9FFF, a banked 8K RAM window at $A000-$BFFF, and a banked 16K ROM window at $C000-$FFFF holding BASIC, the KERNAL and the built-in tools.
  • VIA 6522 — two versatile interface adapters for the PS/2 keyboard/mouse, joysticks and the I2C bus (real-time clock, system management controller).

x16emu is a cycle-aware C emulator: step6502() runs one instruction and returns its cycle count, and the peripherals (VERA, VIA, I2C, RTC, audio) are stepped by that many cycles each iteration of emulator_loop(). Under WebAssembly the loop runs one frame per requestAnimationFrame and yields to the browser.