Simten

Breakout in Hardware

A complete Breakout game built entirely from logic gates, registers, and memory — a 6-pixel paddle, a bouncing ball, and 128 destructible bricks, drawn by a combinational raster scan the way a real display works. No CPU, no software, just digital circuits.

Interactive tutorial/~10 min read/Built with Simten

Steve Wozniak built the original Breakout in hardware for Atari in 1976 — no CPU, just TTL chips. Here’s what it looked like:


Paddle Input

The paddle is 6 pixels wide on the bottom row (row 15). Its center position is stored in a register, and keyboard scan codes (75 for left, 77 for right) feed into comparators that produce a movement delta: −1, 0, or +1.

The delta is added to the current position, then clamped to the range 3–28 so the paddle (center −3 to +2) always stays on the 32-wide screen. Two comparators check the boundaries, and two muxes override the result if it would go out of bounds.

This is the same pattern used in every hardware input system — a comparator bank decodes the input code, combinational logic computes the new position, and boundary clamping prevents invalid state. No if-statements, no software — just gates selecting between values.


Ball Physics & Clock Divider

The ball has four registers: X position, Y position, X velocity (1 or 255 for right/left), and Y velocity (1 or 255 for down/up). Each clock, the next position is computed by adding velocity to position.

But the ball would be impossibly fast if it moved every clock. A clock divider — a counter that counts 0, 1, 2, 3, then resets — generates an enable signal that fires once every 4 clocks. The ball’s position registers only update when this enable signal is high. The paddle runs off its own divider at twice the rate, giving the player a speed advantage.

Clock dividers are fundamental hardware. Every digital system uses them: your CPU’s peripheral bus runs slower than the core, USB runs at 12MHz from a 48MHz source, VGA timing derives from a pixel clock. Here, it’s just a counter and a comparator — when the counter equals the max value, the enable goes high and the counter resets.

Wall bouncing is handled before computing the next position. If the ball is at X=0 moving left, the velocity flips to +1 first, then the new position is computed. This prevents the ball from wrapping around to the other side of the screen.


Brick Collision

The 128 bricks fill the top four rows (Y < 4). Each one is a single bit in a DualPortRAM — 1 if the brick is alive, 0 if it has been destroyed. That one bit per cell is the entire game state for the wall.

Collision reads the RAM at the ball’s next position. If that cell is alive and in the brick rows, it’s a hit: the Y velocity flips and the same cell is written to 0, so the brick vanishes. The bounce is applied to the position on the same clock, so the ball reflects off the face of the wall instead of sinking into it — it only eats a row deeper once the bricks in front of it are gone.

One DualPortRAM does double duty. Port A serves the game logic — reading the ball’s next cell for collision and clearing hit bricks. Port B serves the picture — the raster scan reads the brick under the current pixel to decide whether to light it. The alive-bits are both the state and the image; there’s no separate structure tracking which bricks are left.


Drawing the Screen

There’s no framebuffer. Storing all 512 pixels and rewriting them every frame would burn memory and cycles on a picture the logic can regenerate for free. Instead the screen is drawn the way a real display is: a scan counter walks every pixel address in turn, and for each one, combinational logic answers a single question — is this pixel lit?

The scan_addr input splits into X (the low 5 bits, 0–31) and Y (the high bits, 0–15). Three tests run in parallel and get OR’d together into the output pixel:

Ball
scanX == ballX and scanY == ballY
Paddle
row 15, and scanX within the paddle span
Brick
Y < 4, and the brick RAM cell is alive

This is exactly how a VGA or HDMI controller feeds a monitor: one pixel per clock, computed on the fly from the current scan position. On an FPGA you wire scan_addr to the display’s timing generator and pipe pixel_out to the encoder; in the browser demo, the simulator sweeps the address and reads the pixels back.

The one thing that does need memory writes is the wall itself, and RAM has no reset line. So at power-on — and again each time you lose a ball — a small fill counter walks the 128 brick cells and writes them alive, one per clock. At the FPGA’s clock rate that whole redraw is a few microseconds: instant. The demo just fast-forwards those clocks so you see the same thing in the browser.


The Full Game

All the pieces come together: paddle input, ball physics, brick collision, and the combinational raster scan. 128 bricks across the top four rows, a ball that bounces off walls, paddle, and bricks, and a 6-pixel paddle you control with arrow keys.

Press Run and use the arrow keys to move the paddle. The ball moves every 4th clock — a hardware clock divider that gives you time to react. When the ball hits a brick, it disappears and the ball bounces back. Lose the ball and the wall redraws itself, then a fresh ball launches.

Everything you see is running on the same simulator that powers all the circuits in this blog. No CPU, no software — just gates, registers, and one DualPortRAM for the wall. And it’s all synthesizable: the exact same circuit exports to Verilog and runs on an FPGA.

Loading Breakout simulator...

The circuit uses the same fundamental building blocks as everything else on this site: registers for state, comparators for collision detection, muxes for selecting between values, and adders for position arithmetic. The raster scan is just a counter and a bank of comparators — the same on-the-fly pixel generation a VGA controller uses, scaled to a 32×16 screen.