SearchA-ZC › Centipede

Centipede

1981 Arcade Open source · Public domain Online

Centipede (Atari, 1981), designed by Ed Logg and Dona Bailey, is the trackball arcade classic in which you defend a mushroom field against a centipede that descends the screen and splits into fragments each time you shoot a segment, dodging spiders, fleas and scorpions. This build runs the original Atari board in the browser: a MOS 6502 driving a raster character-and-sprite video system, with the original ROMs. It boots straight into attract mode, the demo game playing itself across the mushroom field, and is wired to the emulators.org in-frame debugger so you can single-step the 6502, read and write the registers and the whole memory map, watch the playfield and motion-object RAM, and set execution breakpoints and write watchpoints. A sibling configuration boots Millipede (Atari, 1982) on the same 6502 raster core.

Read more ↗

Visit the official site ↗

Runs on: Web browser

Centipede Online Emulator

Play Centipede using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
CentipedeCentipedeCentipedegreyOpen ⛶
MillipedeCentipedeCentipedegreyOpen ⛶

Machine emulated

The Centipede arcade board (Atari, 1981) is a single MOS 6502 at 1.512 MHz driving a raster video system: a 32×30 tilemap of 8×8 characters plus 16 8×16 hardware motion objects (sprites), multiplexed over the RAM it shares with the CPU. Designed by Ed Logg and Dona Bailey (one of the first arcade games co-designed by a woman), it was a huge hit and drew a large new audience with its trackball control. Its 1982 sequel Millipede runs on an evolved version of the same board.

Chips

Notes

Embedding

Centipede is a single MOS 6502 at 1.512 MHz driving a raster video system: a 32×30 tilemap of 8×8 characters plus 16 8×16 motion objects (sprites), multiplexed over the RAM it shares with the CPU. This build vendors a self-hosted machine (no CDN): a JavaScript port of Mike Chambers' public-domain Fake6502 core, our model of the Atari bus/video/palette hardware, and the original Atari ROMs, driven from a host-owned loop so the debugger can control it.

Boot. The 8 KB of program ROM loads at $2000–$3FFF. The board only decodes 14 address bits (global mask $3FFF), so the 6502's reset and IRQ vectors at $FFFC/$FFFE fold down into the top of that ROM; the CPU starts and drops straight into attract mode:

var m = new CentipedMachine('centipede'); // loads ROMs, builds 6502 + video
m.reset();                          // pulls the reset vector at $FFFC (-> $3FFC)
// one frame: 4 IRQ slices (~240 Hz), then render the tilemap + sprites
for (var s = 0; s < 4; s++) { m.tickTrackball(); m.cpu.irq(); runCycles(6300); }
m.renderTo(ctx, W, H);

The machine is plain objects. Everything the host and debugger need is a field or method on the machine or its CPU:

MemberKindWhat it does
m.cpu.step()methodFetch, decode and run one 6502 instruction; returns its cycle count. The single-step primitive.
m.cpu.irq()methodRequest the maskable interrupt -- the ~240 Hz tick (4 per frame, clocked off the vertical counter) that drives the game.
m.renderTo(ctx,w,h)methodDraw the current frame: build the 256×240 tilemap+sprite image, then rotate it 270° into the portrait canvas.
m.dbgRead(a) / m.memWrite(a,v)methodSide-effect-free read and the CPU write path -- what the debugger's memory views read and poke.
m.setInput(id,down)methodDrive a control (left/right/up/down trackball, fire, coin, start1) into the input latches.
m.cpu.a/x/y/sp/pc/flagsfieldThe live 6502 registers, read and written directly.

Video. Each frame the loop runs one display's worth of 6502 (four IRQ slices), then walks the 960-byte playfield RAM as a 32×30 character map and the 16-entry motion-object RAM as 8×16 sprites, resolving colours through the write-only palette RAM, and strokes the 256×240 image (rotated 270° for the vertical monitor) onto the canvas.

Debugger integration

The debugger drives a host-owned run loop: because the 6502 interpreter runs one instruction at a time, the loop can pause, single-step and check breakpoints between any two instructions -- no changes to the CPU core are needed. window.EMU_BOOT.transport exposes the controls the shared debugger calls:

  • pause / resume / isPaused -- stop or restart the requestAnimationFrame loop.
  • stepInsn(n) -- call cpu.step() exactly n times and redraw, so a single step advances the PC by one instruction.
  • step(n) -- advance n whole frames (each with its four IRQ slices).
  • breakpoints -- a Set of PC values. When non-empty the loop runs instruction-by-instruction and pauses before executing a watched address; when empty it runs a frame at speed, so an idle debugger costs nothing.
  • watchpoints -- the machine's memWrite is the single write path; it flags a hit when a watched address is written and the loop pauses on it. Because the 6502's registers and the whole RAM map are ordinary JavaScript, registers are read and written directly and memory is exposed side-effect-free (the trackball counter, POKEY RNG and VBLANK bit are computed only on the live read path, never on the debugger's dbgRead).

The plug-in (centiped-debug.js) reads these hooks and calls EmuKit.defineMachine with the 6502 register set bound to the shared mos6502 disassembler, four memory chips (the CPU bus, the program ROM, the playfield tilemap RAM and the motion-object RAM), and the on-screen gamepad. A neat trick for this hardware: point the Motion-object RAM hex window at the sprite base and single-step -- the 16 objects are laid out as four planes of 16 bytes (code/flip, Y, X, colour), so you can watch the game move a centipede segment by poking one X byte.

Architecture

Centipede (1981) and Millipede (1982) are Atari raster boards: a single MOS 6502 at 1.512 MHz with a character-mapped playfield and hardware motion objects. Modelled here as plain JavaScript objects:

  • CPU -- a port of Fake6502 (NMOS 6502 with BCD, which the score uses), reaching memory only through the machine's memRead/memWrite, so the bus and I/O live in one place. The board's partial address decode is modelled by masking every access to 14 bits (Centipede) or 15 bits (Millipede), which is what folds the CPU vectors into ROM.
  • Video -- a 32×30 tilemap of 8×8 characters (codes $40–$7F, X/Y flip in the top two bits) drawn from a 4 KB 2-bit-planar character ROM, plus 16 8×16 motion objects from the same ROM. Colour comes from a tiny write-only palette RAM whose sprite entries are an unusual per-pen indirection (a 2-bit field per pen selects one of four colours); a pen mask makes the unused fields transparent.
  • Bus / I/O -- 1 KB work RAM, the playfield and sprite RAM, two DIP-switch banks, the trackball counter ports (a 4-bit up/down counter with a latched direction/sign bit), the coin/start/fire latches, POKEY (random-number register modelled; sound stubbed) and the output latch (screen flip, coin counters).
  • ROMs -- 8 KB of 6502 program (Centipede) or 16 KB (Millipede) plus a 4 KB character/sprite ROM.

The one piece of timing the game truly needs is its IRQ, clocked off the vertical counter four times per ~60 Hz frame (about 240 Hz); the host loop reproduces exactly that -- four IRQ slices per frame -- and renders the tilemap and sprites at the end of each frame.