Skip to content

Controller Reading

Read the NES controller by strobing and shifting 8 button bits into a variable. Simple, reliable, standard approach.

Taught in Game 1, Unit 2 controllerinputjoypadbuttons

Overview

Read the standard NES controller by writing to the strobe register, then reading 8 bits serially. Each bit represents one button: A, B, Select, Start, Up, Down, Left, Right. This is the standard approach used by virtually every NES game.

Code

; =============================================================================
; CONTROLLER READING - NES
; Read controller 1 via serial interface
; Taught: Game 1 (Neon Nexus), Unit 2
; CPU: ~80 cycles | Memory: ~20 bytes
; =============================================================================

JOYPAD1   = $4016               ; Controller 1 port
JOYPAD2   = $4017               ; Controller 2 port

; Button masks
BTN_A      = %10000000
BTN_B      = %01000000
BTN_SELECT = %00100000
BTN_START  = %00010000
BTN_UP     = %00001000
BTN_DOWN   = %00000100
BTN_LEFT   = %00000010
BTN_RIGHT  = %00000001

.segment "ZEROPAGE"
buttons:   .res 1               ; Current button state

.segment "CODE"

; Read controller and store button state
; Output: buttons variable contains all 8 button states
read_controller:
    ; Strobe the controller
    lda #1
    sta JOYPAD1
    lda #0
    sta JOYPAD1

    ; Read 8 buttons into 'buttons' variable
    ldx #8
@read_loop:
    lda JOYPAD1
    lsr a                       ; Bit 0 -> Carry
    rol buttons                 ; Carry -> buttons
    dex
    bne @read_loop

    rts

Usage:

main_loop:
    jsr read_controller

    ; Check specific buttons
    lda buttons
    and #BTN_A
    bne @a_pressed

    lda buttons
    and #BTN_UP
    beq @no_up
    ; Handle up pressed
    dec player_y
@no_up:

    lda buttons
    and #BTN_DOWN
    beq @no_down
    ; Handle down pressed
    inc player_y
@no_down:

    jmp main_loop

@a_pressed:
    ; Handle A button
    jmp main_loop

Trade-offs

AspectCost
CPU~80 cycles
Memory~20 bytes code, 1 byte variable
LimitationReads controller 1 only

When to use: Any NES game needing player input. This is the standard approach.

When to avoid: None - this pattern works for all games.

How It Works

  1. Write $01 then $00 to $4016 to “strobe” the controller
  2. This latches the current button state inside the controller
  3. Read $4016 eight times - each read returns one button in bit 0
  4. Button order: A, B, Select, Start, Up, Down, Left, Right
  5. Use LSR and ROL to shift each bit into your variable

Button Bitmask Reference

BitButtonMask
7A$80
6B$40
5Select$20
4Start$10
3Up$08
2Down$04
1Left$02
0Right$01

Patterns: NMI Game Loop

Vault: NES