Search › A-Z › M › Missile Command
Missile Command
Missile Command (Atari, 1980), designed by Dave Theurer, is the trackball defence classic in which you fire from three missile bases to protect six cities from an accelerating rain of ballistic missiles, smart bombs and bombers. This build runs the original Atari board in the browser: a MOS 6502 driving a bitmapped raster display, with the original ROMs. It boots straight into attract mode, the demo defending its cities under the falling missiles, 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 bitmap frame buffer, and set execution breakpoints and write watchpoints.
Runs on: Web browser
Missile Command Online Emulator
Play Missile Command using JavaScript directly in your browser.
Controls
Configurations
| Configuration | Emulator | Machine | OS | Legal | |
|---|---|---|---|---|---|
| Missile Command | Missile Command | Missile Command | grey | Open ⛶ |
Machine emulated
The Missile Command arcade board (Atari, 1980) is a single MOS 6502 at 1.25 MHz driving a bitmapped raster display: a 256×231 frame buffer held directly in the RAM the CPU shares with the video hardware, three colour bits per pixel from an eight-entry palette. Designed by Dave Theurer, it became one of Atari's biggest hits, its trackball crosshair and three-base defence a defining Cold-War arcade experience. The unusual "MADSEL" hardware lets the 6502 plot individual pixels through (zero-page,X) instructions whose pointer is a pixel address.
Chips
Notes
Embedding
Missile Command is a single MOS 6502 at 1.25 MHz (10 MHz / 8) driving a bitmapped raster display: 256×231 visible pixels, three colours per pixel from an eight-entry palette. 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 / bitmap video / palette hardware, and the original Atari program ROMs, driven from a host-owned loop so the debugger can control it.
Boot. The 12 KB of program ROM loads at $5000–$7FFF. The board only decodes 15 address bits (global mask $7FFF), so the 6502's reset vector at $FFFC folds down to $7FFC; the CPU starts at $7B4B and drops straight into attract mode:
var m = new MissileMachine(); // loads ROM, builds 6502 + bitmap video
m.reset(); // pulls the reset vector at $FFFC (-> $7FFC -> $7B4B)
// one frame: 4 IRQ slices (~240 Hz), clocked off 32V, then render the bitmap
for (var s = 0; s < 4; s++) { m.tickTrackball(); m.cpu.irq(); runCycles(4800); }
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:
| Member | Kind | What it does |
|---|---|---|
m.cpu.step() | method | Fetch, decode and run one 6502 instruction; returns its cycle count. The single-step primitive. |
m.cpu.irq() | method | Request the maskable interrupt -- the ~240 Hz tick (32V, four assertions per 60 Hz frame) that drives the game. |
m.renderTo(ctx,w,h) | method | Draw the current frame: walk the 256×231 bitmap out of RAM, resolve each 3-bit pixel through the palette, and blit it to the canvas. |
m.dbgRead(a) / m.memWrite(a,v) | method | Side-effect-free read and the CPU write path -- what the debugger's memory views read and poke. |
m.setInput(id,down) | method | Drive a control (trackball up/down/left/right, the three base fires, coin, start) into the input latches. |
m.cpu.a/x/y/sp/pc/flags | field | The live 6502 registers, read and written directly. |
Video. RAM $0000–$3FFF is the frame buffer: 256 lines of 64 bytes, 4 pixels per byte. The bottom 32 lines carry a scattered 3rd colour bit. Each frame the loop runs one display's worth of 6502 (four IRQ slices), then renders the bitmap straight from that RAM; the zero page and stack live in the top, undisplayed, lines exactly as on the real board.
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. window.EMU_BOOT.transport exposes the controls the shared debugger calls:
- pause / resume / isPaused -- stop or restart the
requestAnimationFrameloop. - 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
Setof 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 -- every framebuffer / RAM write funnels through one
poke(); it flags a hit when a watched address is written and the loop pauses on it. Registers are ordinary JavaScript and the RAM map is exposed side-effect-free (the POKEY RNG and the VBLANK bit are computed only on the live read path, never ondbgRead).
Extending the core for MADSEL. Missile Command's video is the interesting bit: the game plots pixels with LDA/STA (zero-page,X), and the hardware's "MADSEL" logic reinterprets that operand access as a pixel address into video RAM (a read-modify-write that changes just the addressed pixel). We reproduce it with a one-flag extension to Fake6502: indx() raises cpu.madsel after computing the 16-bit pointer, and the machine's read/write callback consumes it on the single operand access that follows, routing it through vramMadRead/vramMadWrite (2 colour bits at addr>>2, plus the scattered 3rd bit for the bottom of the screen). A neat trick for this hardware: put a write watchpoint on a frame-buffer byte and single-step -- you catch the exact instruction that lights a pixel, whether it arrived by a direct RAM store or a MADSEL plot.
The plug-in (missilecmd-debug.js) reads these hooks and calls EmuKit.defineMachine with the 6502 register set bound to the shared mos6502 disassembler, three memory chips (the CPU bus, the program ROM and the bitmap frame buffer), and an on-screen gamepad (trackball D-pad + three base fires + coin/start).
Architecture
Missile Command (Atari, 1980) is a raster board unlike its tilemap siblings: a single MOS 6502 at 1.25 MHz painting a full bitmap. 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. Partial address decode is modelled by masking every normal access to 15 bits, which folds the CPU vectors into ROM. - Video -- a 256×231 bitmap held in RAM
$0000–$3FFF(64 bytes per line, 4 pixels per byte, 2 colour bits packed as bit p and bit p+4). The bottom 32 lines gain a 3rd colour bit stored in a scattered low-RAM region. Colour is an eight-entry write-only palette RAM (1 bit each of R, G, B). - MADSEL -- the pixel plotter:
(zp,X)operand accesses are re-routed to a pixel-addressed video path (vramaddr = pixaddr >> 2) with per-pixel read-modify-write masks, exactly as the board's write-mask PROM dictates (computed analytically here and verified against the dumped PROM). - Bus / I/O -- the frame-buffer RAM, two 8-way DIP banks (game options via the POKEY pot pins, pricing at
$4A00), the trackball counter port and its direction lines, the three fire buttons, coin/start latches, the CTRLD / flip-screen output latch, and the POKEY (random-number register modelled; its 4-voice audio is synthesised -- see the Sound notes). - ROMs -- 12 KB of 6502 program (six 2 KB mask ROMs) plus a 32-byte write-mask PROM (reproduced analytically).
The one piece of timing the game truly needs is its IRQ, clocked off 32V about four times per 60 Hz frame; the host loop reproduces exactly that -- four IRQ slices per frame -- and renders the bitmap at the end of each frame.
Sound
Missile Command's board makes sound with a single Atari POKEY (C012294) 4-voice audio chip. This core emulates no sound hardware (the CPU core just returns cycle counts; there is no mixed-audio buffer to reuse), so we take the authored-synthesis route (Pattern S): a from-scratch POKEY is written in missilecommand-pokey.js and driven from the CPU's own register writes.
The chip. Each POKEY voice has an 8-bit frequency divider (AUDF) and a control byte (AUDC: 4-bit volume, a volume-only DC mode, a pure-tone bit and a distortion select). Three free-running polynomial counters — poly4 (period 15), poly5 (31) and the big poly9 (511) / poly17 (131071), selected by the global AUDCTL — are sampled by each voice at its divided rate; that is what turns into Missile Command's launch whistles (pure tones), the incoming-missile buzz (poly4) and the explosion roar (poly17 noise). AUDCTL also picks each voice's clock base (the 1.25 MHz board clock, or the derived 64 kHz / 15 kHz), and joins voice pairs into 16-bit counters for the low rumbles.
Where it is hooked. The board decodes the POKEY at $4000–$400F; the machine's write path now routes those register writes straight into the chip (pokey.write(addr & 0x0f, data)) instead of discarding them. (The real board — and this core's I/O decode — has exactly one POKEY, not two; the constructor is reusable, so a multi-POKEY board would just instantiate one per chip and sum them.)
Rate & pitch. The chip is generated directly at EmuAudio.sampleRate: for each output sample it advances by 1250000 / sampleRate base clocks (a fractional accumulator), so no resampling is needed and the pitch is correct. Each video frame the run-loop renders Math.round(EmuAudio.sampleRate / 60) stereo sample-pairs, packs them as interleaved-stereo Int16 (POKEY is mono, duplicated to L and R) and calls EmuAudio.push().
Mute contract. window.EMU_BOOT.transport exposes isMuted() / setMute() delegating to the shared EmuAudio sink; audio starts muted (browsers block audio before a gesture) and the shell's Sound/Mute button unmutes it from a real click.
Caveat. Missile Command's attract mode is silent by design because it never sets a POKEY voice volume; insert a coin and press Start (keys, or the on-screen Coin/Start controls) to play, where the launches and explosions drive the POKEY.