SearchA-ZB › Bubble Bobble

Bubble Bobble

1986 Arcade Grey · Taito ROMs Online

Bubble Bobble (Taito, 1986) is the classic cooperative platformer in which Bub and Bob, two bubble-blowing dragons, clear 100 single-screen stages by trapping enemies in bubbles and popping them. This build is a from-scratch emulation of the arcade board in the browser: three Zilog Z80 CPUs — a main and a sub CPU sharing the work RAM, plus a sound Z80 — driving the Taito sprite hardware and a RAM palette. It boots straight into attract mode, the on-screen tutorial and demo playing out, and is wired to the emulators.org in-frame debugger so you can single-step the main Z80, read and write the registers and memory, and set execution breakpoints and write watchpoints.

Zilog Z80 core (DrGoldfire/Z80.js, MIT) ↗

Visit the official site ↗

Runs on: Web browser

Bubble Bobble Online Emulator

Play Bubble Bobble using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
Bubble BobbleBubble BobbleBubble BobblegreyOpen ⛶
Bubble Bobble (redux)Bubble BobbleBubble BobblegreyOpen ⛶

Machine emulated

The Bubble Bobble arcade board (Taito, 1986) carries three Zilog Z80s: a main CPU and a sub CPU, both at 6 MHz, that share the work RAM (the main CPU runs the game framework, the sub CPU handles object movement), plus a sound Z80 at 3 MHz driving a YM2203 and a YM3526. There is no tilemap — every character and sprite lives in one RAM region, scanned through a video-timing PROM and coloured through a 256-entry RAM palette. This build emulates the "Bobble Bobble" bootleg variant, whose protection MCU is replaced by a PAL and whose main-CPU interrupt comes straight from vblank.

Chips

Notes

Embedding

Bubble Bobble is the 1986 Taito arcade machine: three Zilog Z80 CPUs -- a main and a sub CPU at 6 MHz that share the work RAM, plus a sound Z80 at 3 MHz -- driving a 256×224 raster. This build is a from-scratch JavaScript emulation of the Bobble Bobble bootleg board (the version whose protection MCU is replaced by a PAL, so the main-CPU interrupt comes straight from vblank). The three CPU cores are Molly Howell's MIT-licensed Z80.js; the board itself is a port of MAME's taito/bublbobl.cpp, driven from a host-owned loop.

Boot. Constructing the machine fetches the ROMs, decodes the 4-bit-plane character set, resets the three Z80s and starts the loop; the board comes up in attract mode:

var m = new BubbleBobble({ canvas, romBase, manifest });
m.boot();                              // fetch ROMs, decode GFX, reset 3 Z80s, run
// each animation frame runs one 59.18Hz field of all three CPUs, then draws

The machine object. Everything the host and debugger need is a field or method on the machine:

MemberKindWhat it does
m.main / m.sub / m.soundfieldThe three Z80 cores. m.main is the CPU that runs the game and the one the debugger targets; getState()/setState() read and write its registers.
m.dbgRead(a) / m.dbgWrite(a,v)methodSide-effect-free read of the main 64K bus and the CPU write path -- what the debugger's memory views read and poke.
m.setInput(id, down)methodDrive a control (left, right, jump, fire, coin, start1, start2, and the player-2 pad) into the input ports.
EMU_BOOT.transportfieldThe pause / resume / step / breakpoint / watchpoint surface the shared debugger drives (see below).

Video. Bubble Bobble has no tilemap: every character and sprite lives in one RAM region, walked once per frame through the video-timing PROM exactly as the hardware scans it, and coloured through a 256-entry RAM palette (12-bit RGB). The renderer draws into a 256×256 buffer and blits the visible 256×224 window to the canvas.

Debugger integration

Because the whole board is ordinary JavaScript and the host owns the run loop, the debugger's controls need no changes to the CPU core: the loop can pause, single-step and check breakpoints between any two instructions. window.EMU_BOOT.transport maps the shared debugger onto the main Z80 (the CPU that runs the game):

  • pause / resume / isPaused -- stop or restart the requestAnimationFrame loop.
  • stepInsn(n) -- run exactly n main-Z80 instructions. The main CPU spends almost every cycle idling in a one-byte wait loop (JR $ at 0x01ED) with all real work in the vblank ISR, so -- like MAME's own single-step -- stepping off that spin honours the pending vblank interrupt and drops straight into the handler, keeping single-step productive.
  • step(n) -- advance n whole 59.18 Hz fields of all three CPUs.
  • breakpoints -- a Set of PC values checked before each main-CPU instruction; a match pauses before the instruction runs.
  • watchpoints -- the main CPU's single memory-write path flags a hit when a watched address is written, and the loop pauses on it.

Registers are read live from the core's getState() and written back through setState() (A F B C D E H L, BC DE HL, IX IY SP PC I R, and the S Z H P/V N C flags). Memory reads use dbgRead, which returns the program ROM, the banked ROM window, the video/object RAM and the palette without touching the I/O latches, so inspecting memory never disturbs the sound handshake or the protection PAL. The one extension to the vendored core is a get_iff1() accessor, so the host can honour a held IRQ line without a full state copy before every instruction. The plug-in (bubblebobble-debug.js) feeds all of this to EmuKit.defineMachine and reuses the shared z80 disassembler at /debugger/src/cpus/z80.js.

Architecture

The Bubble Bobble board (Taito, 1986) carries three Z80s and, on the original, a 6801U4 microcontroller for protection and coinage. This build emulates the Bobble Bobble bootleg, where the MCU is replaced by a small PAL (IC43) and the main-CPU interrupt is taken straight from vblank:

  • Main CPU -- Z80 at 6 MHz. 32 KB program ROM at 0x0000, a 16 KB banked ROM window at 0x8000, then the shared video / object / work RAM and the RAM palette. Runs in interrupt mode 1 (a vblank RST 38h each field). This is the CPU the debugger targets.
  • Sub CPU -- a second Z80 at 6 MHz that shares the work RAM at 0xE000–0xF7FF and does object handling; it is held in reset by the main CPU until the board is ready, then released through the bank-switch latch.
  • Sound CPU -- a third Z80 at 3 MHz driving a YM2203 and a YM3526, fed commands through two active-low semaphores and an NMI. (Audio itself is stubbed in this build; the CPU still runs so the handshake the main CPU polls stays live.)
  • IC43 PAL -- the bootleg's replacement for the protection MCU, at 0xFE00–0xFE83; its exact XOR logic is reproduced from MAME.
  • Video -- no tilemap: characters and up to ~256 sprites share one RAM region, scanned through a 256-byte video-timing PROM (a71-25.41) and coloured through a 256-entry 12-bit RAM palette. The 4-bit-plane GFX ROMs are decoded once at boot.

The bank-switch register at 0xFB40 selects the ROM bank and, in its upper bits, resets the sub CPU, enables the display and flips the screen -- the sequence the host loop reproduces every field.