Skip to content

Joystick Reading

Read Amiga joystick using the JOY1DAT register with XOR decoding for up/down directions.

Code status: the maintained reader is reused by executed Amiga callers. The surrounding movement examples are adapters; they need their own state, bounds and frame wait. The named callers establish physical port 2 under their A500 configuration, not every peripheral.

Overview

Read joystick input from the custom chip register JOY1DAT. The Amiga uses quadrature encoding, requiring an XOR operation to decode vertical movement. Horizontal directions are read directly from specific bits. This pattern provides smooth, continuous movement.

Calling contract

Set A5 to $DFF000, configure CIA-A bit 7 as an input and own physical joystick port 2. Include framework/input-to-sound/input.inc once in writable memory. read_controls returns the held controls in D0.W and controls: up $0100, down $0001, left $0200, right $0002, Fire $0010. It changes D0/D1 and condition codes; other registers survive. Only the low word of D0 is defined.

Keep the horizontal bits from the original JOYDAT sample. The XOR with its shifted copy decodes the vertical bits; applying it to the whole result can turn leftover counter bits into false horizontal input. Physical port 1 uses JOY0DAT and CIA-A bit 6 for Fire; physical port 2 uses JOY1DAT and bit 7.

Code

input.inc
; Digital joystick in physical port 2 (JOY1DAT), fire on CIA-A bit 7.
; A5=$dff000; caller owns the port and configures CIA-A bit 7 as input.
; Output controls: up=$0100, down=$0001, left=$0200, right=$0002, fire=$0010.
; Clobbers D0/D1 and CCR; state must be in writable RAM. Other registers survive.
read_controls:
    move.w $00c(a5),d0
    move.w d0,d1
    lsr.w #1,d1
    eor.w d0,d1
    and.w #$0101,d1       ; decoded vertical bits only
    and.w #$0202,d0       ; retain original horizontal bits
    or.w d1,d0
    btst #7,$bfe001
    bne.s input_no_fire
    or.w #$0010,d0
input_no_fire:
    move.w d0,controls
    rts
controls: dc.w 0

Usage:

68000 assembly
            lea     CUSTOM,a5           ; Set up custom chip base

mainloop:
            bsr     wait_vblank
            bsr     read_controls       ; D0 = directions

            ; Check directions using BTST
            btst    #8,d0               ; Up?
            beq.s   .no_up
            sub.w   #MOVE_SPEED,player_y
.no_up:
            btst    #0,d0               ; Down?
            beq.s   .no_down
            add.w   #MOVE_SPEED,player_y
.no_down:
            btst    #9,d0               ; Left?
            beq.s   .no_left
            sub.w   #MOVE_SPEED,player_x
.no_left:
            btst    #1,d0               ; Right?
            beq.s   .no_right
            add.w   #MOVE_SPEED,player_x
.no_right:
            bra     mainloop

Trade-offs

Aspect Cost
CPU Not measured for this caller; include the selected input, drawing and scheduling costs
Memory Assemble the selected routines and caller to obtain code and state sizes
Limitation No edge detection (continuous input)

When to use: Games with smooth, continuous movement (shooters, racing).

When to avoid: Grid-based games where you want single-step movement per press.

How It Works

The Amiga joystick uses quadrature encoding (like a mouse). The JOY1DAT register returns:

  • Bits 1 and 9: Directly indicate right and left
  • Bits 0 and 8: Require XOR decoding for down and up

The XOR decode formula:

Code
decoded = (raw AND $0202) OR ((raw XOR (raw >> 1)) AND $0101)

This converts the quadrature signals into simple direction flags.

Direction Bit Reference

Bit Direction Check
8 Up btst #8,d0
0 Down btst #0,d0
9 Left btst #9,d0
1 Right btst #1,d0

Fire Button

The fire button is read from CIA-A PRA ($BFE001), not the custom chips. The two joystick ports map to different bits:

Bit Port Common use
6 Physical port 1 (JOY0DAT) Mouse / second joystick
7 Physical port 2 (JOY1DAT) Primary joystick
68000 assembly
            btst    #7,$bfe001          ; Physical port 2 fire (active low)
            beq.s   fire_pressed        ; Branch if pressed

Use bit 6 with JOY0DAT for physical port 1. Configure the corresponding CIA-A direction bit as input without disturbing the other port bits. Commodore-Amiga’s Hardware Reference Manual, third edition, chapter 8, Controller Port Interface, describes the controller registers; its Fire Button section assigns bits 6 and 7 to ports 1 and 2 respectively.

Port 0 (mouse port) reading

To read the mouse / second joystick on port 0, use JOY0DAT ($DFF00A) instead of JOY1DAT:

68000 assembly
JOY0DAT     equ $00a            ; Joystick port 0 / mouse data

read_port0:
            move.w  JOY0DAT(a5),d0
            move.w  d0,d1
            lsr.w   #1,d1
            eor.w   d0,d1
            and.w   #$0101,d1
            and.w   #$0202,d0
            or.w    d1,d0               ; Keep original horizontal bits
            rts

Reading the mouse rather than a joystick yields delta values via the same quadrature encoding — different decode logic if you want pixel-precise mouse movement, but for “two-player digital joystick” the same decode works.

Patterns: VBlank Game Loop

Vault: Commodore Amiga