SearchA-ZM › MEGA65

MEGA65

2020 Online · WebAssembly Open source · GPL-2.0

The MEGA65 is a 2020s open-hardware recreation and completion of the Commodore 65, the 8-bit successor Commodore prototyped in 1990-91 but never shipped. It runs a 45GS02 CPU: a fast (up to ~40 MHz) superset of the 6502. This page runs the MEGA65 in your browser via a WebAssembly build of the open-source Xemu emulator, booting to a Commodore 65 / MEGA65 BASIC "READY." prompt with a full in-frame debugger for the 45GS02.

Visit the official site ↗

Runs on: any modern web browser (WebAssembly)

MEGA65 Online Emulator

Play MEGA65 using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
MEGA65 — C65 BASIC 10 (READY.)MEGA65MEGA65greyOpen ⛶
MEGA65 — open-ROMs firmwareMEGA65MEGA65openOpen ⛶

Machines emulated

Chips

Notes

Embedding

The MEGA65 core is Xemu (an SDL2 C program) built to WebAssembly with make ARCH=html. Vendor the three build outputs — xmega65.js, xmega65.wasm and Xemu's loader xemu-boot.js — plus a compressed SD-card image, then boot it with the loader:

// Xemu's *_WINDOW() macros call window.alert() in the wasm build; silence them
// so a headless / embedded boot is never blocked by a modal dialog.
window.alert = function () {};
// xemu-boot.js defines window.Module and Module.Xemu.start()
Module.Xemu.start({
  emulatorId: "xmega65",
  arguments: ["-sdimg", "mega65.img", "-fullborders"],
  fileFetchList: ["mega65.img"],   // fetched into the in-memory MEMFS
  divId: "mega65-box"            // Xemu creates its <canvas> here (= Module.canvas)
});

Xemu drives its own emscripten_set_main_loop, so there is no JS loop to own. Everything the debugger needs is reached through Module.ccall into hooks added to the C core (see below), and the transport is published on window.EMU_BOOT once the wasm runtime is up:

function num(fn, a){ return Module.ccall(fn, "number", a !== undefined ? ["number"] : [], a !== undefined ? [a] : []); }
window.EMU_BOOT = {
  canvas: Module.canvas,
  transport: {
    pause:   function(){ Module.ccall("xemudbg_pause", null, ["number"], [1]); },
    resume:  function(){ Module.ccall("xemudbg_pause", null, ["number"], [0]); },
    stepInsn:function(n){ Module.ccall("xemudbg_step",  null, ["number"], [n||1]); },
    /* reset, breakpoints{has,toggle,list,clear}, watchpoints{...} — all ccall */
  }
};

The on-screen keyboard calls xemudbg_key(scancode, pressed), which feeds Xemu's HID layer exactly like a physical key; the host keyboard already reaches the same place through SDL2's own browser key-event handling.

Debugger integration

Xemu is a native emulator, not a JS object graph, so the debugger cannot poke at plain globals the way it can with a JS core. Instead the C source was extended with a compact set of EMSCRIPTEN_KEEPALIVE functions (kept out of dead-code elimination, exported to JS) that expose exactly what the shared framework needs. These are the ONLY additions the MEGA65 needed:

C hookWhat it does
xemudbg_reg_get / _set(i)Read / write the live 45GS02 registers off the CPU65 struct: A, X, Y, Z, SP, PC, P (via cpu65_get_pf / cpu65_set_pf), plus SPH and the base-page B register.
xemudbg_read_cpu / _write_cpu(a)Side-effect-free peek/poke of the CPU's banked 64K view via Xemu's debug_read_cpu_byte / debug_write_cpu_byte (no I/O latches touched).
xemudbg_read_lin / _read_ram(a)Read the 28-bit linear address space and the raw fast-RAM array (the ROM sits at linear $20000).
xemudbg_step(n)Run exactly n instructions by calling cpu65_step(0) — the single-step primitive.
xemudbg_pause(v)Set dbg_freeze. The added line at the top of emulation_loop() makes the loop return to the browser while frozen instead of spinning (Xemu's native while(paused) busy-loop would hang a tab).
xemudbg_bp_* / _wp_*Small execution-breakpoint (PC) and write-watchpoint sets. New checks inside emulation_loop() scan them before / after each opcode and set dbg_freeze on a hit — the watchpoint compares the current byte against the value snapshotted when it was armed.
xemudbg_key(scancode, pressed)Injects a key straight into hid_key_event(), driving the C65/MEGA65 key matrix for the on-screen keyboard.

The disassembly reuses the shared mos6502 decoder: the 45GS02 is a 6502 superset, so its base opcodes disassemble correctly and its extended opcodes fall back to .byte. Two small non-debugger patches make the wasm build self-contained and non-blocking: the SD image is auto-created & formatted in the browser MEMFS when absent (the built-in ROM is written onto it), and the *_WINDOW() alert popups are neutralised by window.alert = () => {} in the embed.

Architecture

The MEGA65 is a 2020s open-hardware recreation and completion of the Commodore 65 — the 8-bit successor Commodore prototyped in 1990-91 but never shipped. It runs a 45GS02 CPU: a fast (up to ~40 MHz) superset of the CSG 4510 / 65CE02, itself a superset of the NMOS 6502, with a Z register, a 16-bit stack pointer, a relocatable base page, and 32-bit "linear" addressing (a flat 28-bit address space over the 8-bit CPU view).

  • cpu65 — the shared Xemu 6502-family core in 45GS02 mode. cpu65_step() runs one instruction; the CPU65 struct holds every register.
  • HYPPO / HICKUP — the MEGA65 hypervisor. It sets the machine up on reset, mounts the SD card, and hands off to the ROM. Xemu embeds it (and can override the ROM in RAM at linear $20000).
  • VIC-IV — the MEGA65 video chip (a superset of the C65 VIC-III / C64 VIC-II), rendered by Xemu into an SDL2 / WebGL canvas.
  • ROM — this build boots the freely-redistributable Commodore 65 system ROM (910111, BASIC 10) from the SD image; the closed MEGA65 "BASIC 65" ROM can be dropped in by an owner, and the fully-open open-ROMs firmware is embedded as an alternative.
  • SD card — a real SDHC card is mandatory for MEGA65 boot; here it is a small RLE-compressed image Xemu decompresses on the fly.

Because the whole machine is a native C emulator in wasm, the debugger reaches it exclusively through the exported C hooks above — which is what makes single-stepping, live registers, side-effect-free memory and breakpoints/watchpoints possible on a 45GS02.