Pong (a minimal teardown)#

Where Combat and Pitfall! are feats of compression — huge games squeezed into tiny ROMs — this Pong is the opposite lesson: the irreducible minimum, the smallest thing that is still a complete VCS game. It’s a clean, modern implementation by Lucas Avanço, built on Kirk Israel’s “thin red line” tutorial and the Stella Programmer’s Guide — not Atari’s 1977 cartridge, but all the better for reading, because there’s nothing in it that isn’t essential.

Strip a 2600 game down to the studs and this is what’s left. It’s the best possible thing to read right after the basics.

The shape of the program#

Pong’s structure isn’t like the frame loop this book teaches — it is that loop, with no embellishment at all:

Three VSYNC lines, a VBLANK where the game thinks, a kernel where it draws, thirty overscan lines, repeat. That’s the whole architecture — exactly the frame structure chapter, running a real game. If you understand this diagram, you understand the spine of every game in the analysis section; the others just hang more on it.

Two paddles and a ball#

Pong is the game the TIA’s movable objects were practically named for. The two paddles are the two players — drawn from GRP0 and GRP1, each as a solid bar about 30 scanlines tall, their vertical positions in Player0Pos / Player1Pos. The ball is the ball — the TIA’s ball object (ENABL), nudged horizontally with HMBL. No multiplexing, no flicker, no copies: three objects, used for exactly what they’re for.

The kernel: draw by comparing#

ScanLoop is a single-line kernel — the simplest kind — running once per visible scanline for all 191 of them. Each line, it asks the only question a kernel ever asks: is any object lit here? It compares the current scanline to each paddle’s vertical range to decide whether to draw its GRP, and to the ball’s range to decide whether to enable it. That’s the whole trick of putting a sprite at a vertical position — there is no Y register, only which scanlines you choose to draw on, and this is that idea in its barest form.

Ball physics in a handful of bytes#

The entire ball simulation lives in a few zero-page bytes:

  • Vertical: YPosBall is the height; DirectionBall (up or down) flips when the ball reaches the Top or Down boundary — a bounce off the ceiling and floor.
  • Horizontal: BallLeftRight holds the fine-motion nibble fed to HMBL ($10 one way, $F0 the other), and it’s flipped when the ball strikes a paddle.
  • Scoring the miss: the collision latches do the refereeing — CXP0FB / CXP1FB for ball-meets-paddle (bounce), and CXBLPF for ball-meets-back-wall (a point against the player who missed).

A bouncing ball, in maybe a dozen bytes of state and three collision checks. This is where the Collisions chapter stops being abstract.

No score, just lives#

There’s no scoreboard at all — instead each player has a stock of lives (LifePlayer0 / LifePlayer1, starting at 30), and missing the ball costs one; reach zero and it’s EndGame. It’s a small reminder that a score is a design decision, not a hardware requirement — the very thought experiment the Scoreboard page opens with (“imagine Pong without a scoreboard”), here taken literally.

Why read it#

Pong is the floor. Two players, one ball, four screen regions, three collision latches — and a complete, playable game. Read it first to see the skeleton bare, or read it after Combat and Pitfall as a palate cleanser that reminds you what all that ingenuity is built on. Everything bigger is this loop, elaborated.

Read the source. Lucas Avanço’s Pong (after Kirk Israel’s “thin red line”), on GitHub at johnidm/asm-atari-2600 → pong.asm.