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.
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:
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:
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:
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
IFnever fires. Remember it's active-low: test(J AND bit) = 0for pressed, not= 1. A pushed switch reads as zero. - The ball left the screen, then
?ILLEGAL QUANTITY ERROR. APOKEran past the screen. Guard each move soXstays0–39andYstays0–24, 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: NEXTdelay inside the loop and watch the ball ease off; shorten it and it races. - Wrap instead of stop. When
Xpasses 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-low —
0means pressed. At rest the port reads127. - Each direction is one bit: up
1, down2, left4, right8, fire16— decoded withAND. - 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.