Skip to content
Game 0 Unit 12 of 15 1 hr learning time

Reading the Joystick

Input on the C64 is another PEEK. The joystick port is memory at 56320: read it and each direction is one bit, cleared when the stick is pushed. Decode the bits with AND, and a ball moves under your hand.

80% of Meet C64 BASIC

Everything so far has been output — to the screen, to the SID. Now the other direction: input. The C64 has no joystick keyword, the same way it had no sound keyword. The joystick is wired into memory, at address 56320, and you read it the way you read any byte: with PEEK. One address holds all five switches — up, down, left, right, and fire — packed into the bits of a single number.

Milestone 1 — read the port

PEEK(56320) returns the joystick's state as a number. Print it in a loop and watch it change as the stick moves:

10 PRINT CHR$(147)
20 PRINT PEEK(56320)
30 FOR T=1 TO 40
40 NEXT T
50 GOTO 10

With nothing pushed, it reads 127:

A C64 screen showing the number 127 at the top, the joystick at rest.
PEEK(56320) reads the joystick port. At rest it's 127 — every direction switch is off. Push the stick and the number drops.

Here's the twist: a switch reads as 0 when pressed, not 1. The port sits "all ones" at rest and a pushed direction clears its bit. So the number goes down as you push: 126 for up, 125 for down, 123 for left, 119 for right. This is called active-low, and it's how most hardware switches report.

Milestone 2 — decode the directions

Each direction is one bit of that number: up is 1, down is 2, left is 4, right is 8, fire is 16. To test one, use AND to mask out the rest — if the result is 0, that switch is pressed:

10 J=PEEK(56320)
20 PRINT CHR$(147)
30 IF (J AND 1)=0 THEN PRINT "UP"
40 IF (J AND 2)=0 THEN PRINT "DOWN"
50 IF (J AND 4)=0 THEN PRINT "LEFT"
60 IF (J AND 8)=0 THEN PRINT "RIGHT"
70 IF (J AND 16)=0 THEN PRINT "FIRE"
80 FOR T=1 TO 250
90 NEXT T
100 GOTO 10

J AND 8 keeps only the right-bit of the reading; =0 means it was cleared, so the stick is pushed right. Run it and push the stick:

A C64 screen showing the word RIGHT, with the joystick pushed right.
One AND per direction turns the packed number into words. Push right and the right-bit clears, so J AND 8 is 0 — and the program knows.

AND is how you read one bit out of many. Each direction has its own bit, so each gets its own line — and because they're separate bits, two at once (up and right, a diagonal) both read as pressed.

Milestone 3 — move a ball

Put it together with Unit 9's screen memory: read the stick, change a row and column, and POKE a ball into the new cell. Erase the old position first, and the ball moves under your hand:

10 PRINT CHR$(147)
20 POKE 53281,0
30 X=20:Y=12
40 J=PEEK(56320)
50 POKE 1024+Y*40+X,32
60 IF (J AND 1)=0 AND Y>0 THEN Y=Y-1
70 IF (J AND 2)=0 AND Y<24 THEN Y=Y+1
80 IF (J AND 4)=0 AND X>0 THEN X=X-1
90 IF (J AND 8)=0 AND X<39 THEN X=X+1
100 POKE 1024+Y*40+X,81
110 POKE 55296+Y*40+X,1
120 GOTO 40

Line 50 erases the ball's old cell with a space; lines 60–90 nudge X and Y by the stick (each guarded so the ball can't leave the screen); lines 100–110 draw the ball — screen code 81, a filled circle — in white at its new cell. GOTO 40 does it forever:

A black C64 screen with a single white ball above and right of centre.
Read the stick, move the ball, POKE it to the screen — the whole loop of a game in eight lines. Push up and right, and the ball goes up and right.

That loop — read input, update position, draw — is the heart of every game ever written. You now have all three parts on the C64: a stick to read, numbers to change, and a screen to draw on.

When it doesn't work

  • The number never changes. Read 56320 (control port 2), the port nearly all games use. Port 1 is 56321, and it's shared with the keyboard — start with 56320.
  • Your IF never fires. Remember it's active-low: test (J AND bit) = 0 for pressed, not = 1. A pushed switch reads as zero.
  • The ball left the screen, then ?ILLEGAL QUANTITY ERROR. A POKE ran past the screen. Guard each move so X stays 039 and Y stays 024, as the milestone does.
  • Two directions don't both register. They will — each is a separate bit. If not, check you tested each with its own AND, not one combined number.

Before and after

You started able only to send things out and finished reading a control in — the joystick, one PEEK of address 56320, decoded a bit at a time with AND, then wired to a ball you move. The idea underneath: input on the C64 is memory too — the joystick is a byte at 56320, active-low, one bit per switch.

Try this

  • Fire to change colour. When (J AND 16) = 0, poke a different colour into the ball's colour cell.
  • Faster, slower. Add a FOR T=1 TO 20: NEXT delay inside the loop and watch the ball ease off; shorten it and it races.
  • Wrap instead of stop. When X passes 39, set it to 0 — the ball reappears on the left.

What you've learnt

  • The joystick is memory at 56320; read it with PEEK.
  • Switches are active-low0 means pressed. At rest the port reads 127.
  • Each direction is one bit: up 1, down 2, left 4, right 8, fire 16 — decoded with AND.
  • Read input, update, draw in a loop is the shape of every game.

What's next

The ball moves when you push — but it sits still when you don't. In Unit 13 we give a shape a life of its own: an animation loop that moves it every frame, bounces it off the edges, and meets the flicker that sends C64 game-writers reaching for assembly.