Search › A-Z › P › Pokémon Mini
Pokémon Mini
The Nintendo Pokémon Mini (2001) is the smallest cartridge-based game system Nintendo ever made. This is JustBurn's PokeMini 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 Epson S1C88 (Minx) CPU, set breakpoints and watchpoints, and inspect the whole memory map. It boots the open FreeBIOS and an openly-licensed homebrew demo, so no copyrighted ROM is needed.
Runs on: Web browser
Pokémon Mini Online Emulator
Play Pokémon Mini using JavaScript directly in your browser.
Controls
Configurations
| Configuration | Emulator | Machine | OS | Legal | |
|---|---|---|---|---|---|
| Bouncing (PokeMini demo) | Pokémon Mini | Nintendo Pokémon Mini | open | Open ⛶ |
Machines emulated
Chips
Notes
Embedding
PokeMini is JustBurn's Pokémon Mini emulator (GPLv3). Its emulation core is portable C with no SDL dependency, so we compile only that core to WebAssembly with Emscripten and reach it through a tiny hand-written shim (wasm_main.c) that exposes a handful of EMSCRIPTEN_KEEPALIVE entry points — never a per-cycle callback across the JS/wasm boundary.
Boot and load a ROM. The module is built with MODULARIZE, so loading pokemini_core.js defines a PokeMiniModule() factory. Instantiate it, cwrap the shim, copy the .min image into the wasm heap and hand it over:
const Mod = await PokeMiniModule();
const pm_init = Mod.cwrap('pm_init', 'number', []);
const pm_load = Mod.cwrap('pm_load', 'number', ['number', 'number']);
const pm_frame = Mod.cwrap('pm_frame', 'void', []);
pm_init(); // PokeMini_Create + FreeBIOS + palette
const rom = new Uint8Array(await (await fetch(romUrl)).arrayBuffer());
const p = Mod._malloc(rom.length);
Mod.HEAPU8.set(rom, p);
pm_load(p, rom.length); // PokeMini_SetMINMem + hard reset
The shim surface. Everything the debugger needs is a plain C function; the wasm holds all machine state:
| Export | What it does |
|---|---|
pm_frame() | Run one whole video frame (PokeMini_EmulateFrame) and blit the 96×64 LCD into an RGBA buffer. |
pm_step() | Execute exactly one S1C88 instruction (MinxCPU_Exec) then re-sync the timers and PRC. The single-step primitive. |
pm_fb() | Pointer to the 96×64 RGBA framebuffer inside the wasm heap, painted to a 2D canvas. |
pm_read(a) / pm_write(a,v) | Side-effect-free linear bus access over BIOS / RAM / I/O latches / ROM — reads never trigger I/O. |
pm_pc() | The physical fetch address of PC, honouring the S1C88 bank (V) register. |
pm_getreg(i) / pm_setreg(i,v) | Read / write the register file: A, B, BA, HL, IX, IY, SP, PC, F, N and the bank bytes. |
pm_key(k,down) | Press or release a Pokémon Mini key (A/B/C, D-pad, Power, Shock) via PokeMini_KeypadEvent. |
Debugger integration
Wiring the wasm core into the shared in-browser debugger needed one boot shim that owns the loop, plus a new S1C88 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 runFrame(){
if (!bps.size && !wps.size) { pm_frame(); return; } // fast path
let cyc = 0;
while (cyc < 55634) { // one frame of cycles
if (bps.has(pm_pc())) { running = false; return; }
const before = snapshotWatched();
cyc += pm_step(); // one S1C88 instruction
if (watchedChanged(before)) { running = false; return; }
}
pm_render();
}
Techniques for deeper access.
- Side-effect-free reads. The hex and disassembly views read through
pm_read, which indexes BIOS, RAM, the I/O latches and ROM directly instead of routing through the hardware read path, so auto-polling a view never disturbs timers or I/O. - Direct register state.
pm_getreg/pm_setregread and write the liveMinxCPUstruct; the flag byte is surfaced as clickable Z/C/V/S/BCD/NIB/I/ID chips. - Single instruction step.
pm_stepexecutes one instruction and re-syncs the timers and PRC, so one call is one coherent step. - Execution breakpoints. Because the loop is host-owned, a breakpoint is a JavaScript
Setof physical PC values compared againstpm_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 S1C88 decoder. The Pokémon Mini CPU had no shared disassembler, so debugger/src/cpus/s1c88.js was added: the primary opcode page plus the two 0xCE / 0xCF extended pages, ported faithfully from PokeMini's own instruction tables, with .byte fall-back for raw data.
Architecture
The Pokémon Mini (2001) is the smallest Nintendo cartridge system. Its heart is an Epson S1C88-family core (the "Minx"), an 8-bit variable-length CISC CPU running at about 4 MHz, with a 96×64 monochrome LCD, a piezo buzzer, a rumble motor, a real-time clock and a shock detector.
- S1C88 CPU — registers A/B (paired as BA), the 16-bit index registers HL, X and Y, SP and a PC extended by a bank register; a one- or two-byte opcode encoding with two extended pages.
- PRC — the Program Rendering Chip draws a tile-map background and sprites into the LCD framebuffer each frame.
- Timers & IRQ — a bank of hardware timers and a priority interrupt controller drive audio, video and the keypad.
- Memory map — 4 KB BIOS at
$000000, 4 KB RAM (plus I/O latches) at$001000, and up to ~2 MB cartridge ROM from$002100.
This build boots the open FreeBIOS (bundled with PokeMini) so no copyrighted Nintendo BIOS is needed, then loads an openly-licensed homebrew demo. The whole machine lives inside the WebAssembly module, and the debugger reads it each refresh through the shim.