Space Invaders (1980)#
Space Invaders — Rick Maurer, Atari — was the first officially licensed arcade game to land on a home console, and it changed everything. It was the 2600’s killer app: the cartridge people bought the console in order to play, widely credited with roughly quadrupling hardware sales in 1980 and turning the VCS from a curiosity into a phenomenon. Maurer’s port is also a quiet masterclass in TIA economy — it fills the screen with marching aliens using astonishingly little hardware. The disassembly here was produced from the cartridge with DiStella.
The headline trick isn’t procedural worlds or scrolling terrain — it’s sprite arithmetic: a whole formation of invaders conjured from just two player objects.
The shape of the program#
The frame loop is the ordinary one this book teaches. The remarkable part is the kernel, where two sprites become a battlefield:
Starting — and restarting#
START is the only place the hardware acts on its own, and it does exactly one thing. On power-up (or whenever the 6507’s RESET line is pulled), the CPU’s built-in reset sequence reads a 16-bit address from the reset vector at $FFFC/$FFFD and jumps there — that’s the 98 FE at the very end of the ROM, pointing at START ($FE98). That is all it does: it does not clear RAM, set the stack, or zero the TIA. Power-up memory is garbage, so the first job — in code — is to make the machine known:
START: CLD
SEI
LDX #$00
TXA
LFE9D: STA VSYNC,X ; X wraps $00→$FF: zero all 128 bytes of RAM (and the TIA)
INX
BNE LFE9D
DEX ; X = $FF
TXS ; stack pointer = $FF
JSR LFEB2 ; build the formation, lives, score…The console “Game Reset” button is a different animal — it is not a hardware reset. It never vectors through $FFFC and never interrupts the CPU; it is simply bit D0 of the SWCHB register. The running program has to notice it. Space Invaders polls the switch in its main loop and, on a press, calls the same init routine power-up used:
LF694: LDA SWCHB
AND #$03 ; Reset = D0, Select = D1 (both active-low)
CMP #$02 ; %10 = Reset pressed, Select up
BNE LF6A3
JSR LFEB2 ; → restart the gameSo the split is clean: the power-up jump is hardware (read two bytes at $FFFC, go); everything after it — clearing memory, and the Reset button itself — is software. Leave out the SWCHB poll and the Reset button does nothing at all. (The 6507 also exposes no NMI or IRQ pins, so the other two vectors are dead weight — which is why all three simply point at $FE98.)
Two shots, and a mystery#
There’s a piece of folklore as old as the cartridge: hold Game Reset as you switch the console on — power and reset at the same instant — and your cannon can fire two shots at once, a second laser leaving the gun before the first has cleared. Players have passed the trick around for forty years; what nobody has cleanly pinned down is why.
The place to hunt is the split just above. A real power-up runs START, which scrubs all 128 bytes of RAM before LFEB2 builds a fresh game. The Game Reset button jumps straight to LFEB2 — it rebuilds the formation, lives, and score, but never re-runs that RAM-clearing loop. So any variable LFEB2 doesn’t itself write keeps whatever it held a moment before. Catch the machine in the seam between those two paths — Reset asserted while power-on garbage is still sitting in memory — and the byte meant to gate your fire (only one missile aloft at a time) can come up in a state the game never planned for, and a second shot slips through.
That’s the shape of an answer, not the answer. Exactly which byte, and why power-and-reset-together lands it just so, is the kind of thing you settle only by reading the disassembly with the question in hand. Like Cosmic Ark’s starfield, it’s an accidental behavior living in the gap between a hardware reset and the software meant to finish the job — and a standing invitation to go solve it.
36 invaders from two sprites#
A row in the arcade game is six invaders across. The 2600 has two player objects. So how does a single scanline band show six aliens?
The answer is NUSIZ. Maurer sets both NUSIZ0 and NUSIZ1 to $06 — the “three copies, medium spacing” mode — so each player draws three evenly-spaced images instead of one. Three from P0 plus three from P1 makes six invaders per row from two objects, and it costs only the two register writes:
LF1F2: STA NUSIZ1 ; $06 = three copies, medium → 3 invaders
LF1FA: STA NUSIZ0 ; $06 = three copies, medium → 3 moreThat handles one row across. To stack the rows down the screen, the kernel does sprite multiplexing — and here is the part worth sitting with. The TIA has only two player objects in the entire machine. There is never a frame where 36 invaders exist in hardware. At any single instant the beam is painting one scanline, and on that line the chip holds just P0 and P1 (tripled by NUSIZ) — six sprites, no more. The rows above are already painted and gone; the rows below haven’t happened yet. The formation only looks simultaneous because your eye fuses a frame the beam draws one line at a time.
So the same two objects are reused for every rank. As the beam falls past each row, the kernel re-arms GRP0/GRP1 with that row’s graphics and marches on. And because the formation is a rigid grid that moves as a block, the two players are positioned horizontally once per frame — between rows the kernel swaps only the pictures, never the positions. Same two sprites, re-dressed on the fly. Six across × the rows down = the full formation — 36 invaders out of two objects. Those same two players are then reused yet again, in their own bands, for the mothership gliding across the top and your cannon at the bottom.
There’s a second sleight-of-hand inside the row itself. The three copies of a player would normally be identical — same graphics, repeated. But the kernel rewrites GRP0/GRP1 mid-scanline, six times, landing each write just before the beam reaches the next copy:
LDA ($EE),Y → GRP0 ; column 1's picture
LDA ($F0),Y → GRP1 ; column 2's
LDA ($F2),Y → GRP0 ; column 3's
LDA ($F4),Y → GRP1 ; column 4's
LDA ($F6),Y → GRP0 ; column 5's
TXA → GRP1/GRP0; column 6'sSo NUSIZ sets the slots and the just-in-time rewrites give each slot its own bitmap — that’s how all six aliens in a row can differ (and animate). It is the single best demonstration in this book of the sprite chapter’s two big multipliers stacked together: copies (horizontal) and multiplexing (vertical).
And the reuse doesn’t stop at the formation. As the beam crosses each zone of the screen, the kernel re-dresses those same two players for a different job — flipping NUSIZ back to a single copy (LDA #$00 / STA NUSIZ0) above and below the swarm. Read top to bottom, one frame morphs P0 and P1 three times:
| Band (top → bottom) | NUSIZ | What P0 & P1 are |
|---|---|---|
| top | $00 — single | the mothership gliding across |
| middle | $06 — three copies | the 36 invaders, re-armed per row |
| bottom | $00 — single | you — the cannon |
Saucer, then armada, then your ship — the same two objects changing costume line by line. There are never more than two players in the machine; there only ever appear to be.
Wait — Player 0 is shooting at Player 0? Follow that last idea to its conclusion: the command ship at the top and your cannon at the bottom are the same player object — one set of TIA registers, repainted in two different bands of the frame. So when your shot connects with the mothership, it is, in hardware, a collision with the very object that is your ship. What keeps that from being a bug is timing. The TIA’s collision latches don’t know who anything is — only that an overlap happened — so the kernel reads each band’s latch and then wipes it (
STA CXCLR) before the next band begins. A hit caught up top is filed as “mothership,” a hit caught down low as “you,” even though it’s the identical object both times. The chip genuinely cannot tell the saucer from your cannon; only when on the screen the hit registered tells them apart. On the 2600, identity is temporal, not physical — “the mothership” and “you” aren’t two things, they’re one actor at two moments of the beam’s trip down the screen.
How a hit invader disappears#
When you shoot an invader, it can’t simply be recolored away: the three copies of a player share one color register per scanline, so there’s no way to tint just one of them into the background. Instead, the game hides it at the graphics level — and reuses the very same mid-line rewrite machinery above.
Each row carries a 6-bit “alive” bitmap (one bit per column, stored at $92–$97 and initialized to $3F = 00111111, all six present). When a shot connects, the game clears that invader’s bit. Then, just before drawing the row, the kernel walks the six bits and builds the six column graphics-pointers — alive → the invader bitmap, dead → a pointer to blank $00 graphics:
LF0A5: LDA.w $0092,Y ; this row's alive bitmap → $F8
STA $F8
LDX #$F4
LF0AE: LSR $F8 ; shift out one invader's bit
BCC LF0B9 ; bit = 0 (destroyed) → blank it
LDA LFCD6,Y ; bit = 1 (alive) → real graphics pointer
...
LF0B9: LDA #$00 ; destroyed → point this slot at blank graphics
LF0BD: STA $FA,X ; store this column's pointer (fills $EE…$F8)The destroyed invader’s slot is still there — NUSIZ faithfully manufactures all three copies of the player every line — but that slot is now fed an empty bitmap, so it paints all-zero pixels and shows nothing. Gone, mechanically, is just “still drawn, drawing nothing.” It’s the same trick as the per-column rewrite, with the degenerate case (blank) standing in for a dead alien.
The whole cast, with two left over#
With the players spoken for, the rest of the screen is built from the remaining TIA objects:
| Object | Role |
|---|---|
| Player 0 + Player 1 | the invaders — each tripled (NUSIZ=$06) and multiplexed down the rows; reused for the mothership and your cannon |
| Ball / Missiles | the shots — your laser climbing, the invaders’ bombs falling (ENABL/RESBL/HMBL reposition them each frame) |
| Playfield | the shields, plus the ground line and score area (PF0/PF1/PF2) |
Every pixel traces back to those few registers — but the shields are worth a second look, because they’re the one thing on screen that isn’t a sprite.
The shields: the one thing that isn’t a sprite#
Every actor — the swarm, the saucer, your cannon, every shot — is one of the TIA’s five movable objects. The barricades are not. They belong to the chip’s other, completely separate graphics system: the playfield. And that shows up two ways.
They’re chunky. A playfield “pixel” is four times the width of a sprite pixel and low-res — exactly why the bunkers look blocky next to the crisp invaders. The playfield is the 2600’s tool for structures (walls, mazes, scores), and a row of shields is a textbook use; the three separate bunkers come from rewriting the playfield mid-scanline, an asymmetric playfield.
They erode because they live in RAM. A sprite’s graphics sit in ROM — you can’t shoot a hole in ROM. The shield pattern is read through a pointer into a RAM buffer (LDA ($EE),Y / STA PF0), so when a shot or bomb lands, the game clears the matching bits in that buffer and the next frame’s playfield simply draws the chewed-up shape. Destructible cover falls straight out of “the playfield reads from mutable memory.”
So the real picture is two graphics systems, not one:
| System | Pixels | Source | In Space Invaders |
|---|---|---|---|
| 5 movable objects — P0, P1, M0, M1, Ball | sharp, freely positioned | ROM graphics | invaders / mothership / cannon, shots, bombs |
| 1 playfield — PF0/PF1/PF2 | chunky, low-res | a RAM buffer (so it can erode) | the shields (+ ground, score) |
Every actor on the board is the two players wearing costumes; the only thing that isn’t a sprite is the blocky, breakable wall you crouch behind. Nothing is wasted.
The march, counted in decimal#
The formation’s horizontal position lives in a BCD accumulator updated during VBLANK. Each step adds a small velocity to the position with the CPU in decimal mode:
SED
LF4E1: LDA $E8,X ; formation position (low)
CLC
ADC $F6,X ; + velocity
STA $E8,X
...
CLDWhen the column reaches a screen edge, the velocity flips sign and the whole formation drops a row — the relentless left-right-down sweep that defines the game. Keeping the position in BCD makes the on-screen movement line up cleanly with the decimal bookkeeping the rest of the game uses (lives, score).
This accumulator is also a textbook case of a limitation Adventure leans on hard: the TIA has no register that reports an object’s horizontal position, so a game that needs to know where something is across the screen — and to notice when it hits an edge — has to keep that number itself. Space Invaders keeps it in BCD; the march is that bookkeeping made visible.
Faster as they fall#
The game’s signature tension is that the aliens speed up as you destroy them. In the original arcade machine this was a famous accident — fewer invaders meant less for the draw loop to do, so the survivors were updated more often and appeared to accelerate. Maurer preserves the feel on the 2600: as the ranks thin, the formation’s march quickens, so the last lonely invader skitters across the screen at a panic-inducing clip. It’s emergent difficulty — a curve that nobody had to design, falling straight out of “draw what’s left.”
One cartridge, 112 games#
Flip the Game Select switch and Space Invaders becomes something else. The cartridge holds 112 variations off a single 4 KB ROM — moving shields, invisible invaders, zig-zagging bombs, fast bombs, and a full slate of two-player modes. The variation number simply gates a handful of feature flags that the one shared kernel reads while it runs; the display loop doesn’t fork, it just consults a few bits. It’s a lesson in reuse: one engine, a table of toggles, a hundred-plus distinct games.
Why read it#
Pitfall! and River Raid impress by generating a world. Space Invaders impresses by doing the opposite — taking the TIA’s tiniest cast and making it look like a hundred things at once. Read it for the NUSIZ copies + multiplexing combination that turns two sprites into a 36-alien wall (there is no cleaner example), for the BCD march and its accidental speed-up, for the 112-in-one trick that wrings a hundred games from one kernel, and for a forty-year-old mystery — the power-on-plus-Reset two-shot glitch, still waiting in the disassembly for someone to explain it cleanly. And read it for what it was: the cartridge that sold the machine this whole book is about.
Read the source. This teardown is drawn from a DiStella disassembly of the Space Invaders cartridge (Rick Maurer’s game, © 1980 Atari). Disassemble your own copy with
distella -a -sto follow along — see the Toolchain chapter.