Skip to content

Read a button on Atari 7800

Reuse the actual machine-specific reader, with its caller, state, ownership and a diagnosed input mistake.

Build the complete caller with make -C atari-7800/patterns/assembly/input/read-action. Press fire once, keep it held, then release and press again. The piece moves on each new press and returns to its starting position after two; holding does not repeat the action. Load the cartridge produced by the Makefile in the named configuration; retain its reset/header setup.

Atari 7800 native caller after accepted input.
Captured from the running caller in the configuration below.

Take the reader

sample.inc is an inline hardware sampler: include it where the caller samples input. It has no RET/RTS and must not be called as a subroutine. It supplies the held state described below; the caller supplies previous-state storage and decides what a new press does.

The reusable reader

sample.inc
    lda $000c
    and #$80
    eor #$80
    sta current

Legacy INPT4 at $0C uses active-low bit 7; the inline sampler stores 0/$80 in current=$1904. It changes A/flags and does not read the second independent controller button.

Calculate a new-press mask as current AND NOT previous, then store current as previous on every update, including release. Test held state for continuous movement and the new-press mask for an action that should happen once. A key already held at the caller’s first sample counts as a press because previous starts at zero.

Caller storage: previous=$1901, current=$1904; turn=$1900, field clock=$1902/$1903. The sample’s display initialiser and any interrupts have their own ownership requirements; keep them with this complete example.

Change it and recognise a mistake

Add the second controller button only after handling its distinct wiring. Do not copy the 5200 bit-0 trigger mask.

The broken caller feeds held state into the action decision. Keeping the button down advances repeatedly; the native fault run reaches 32 instead of remaining at one. Restore the previous-state comparison and update previous on release as well.

Deliberately broken input/update path

no-edge.asm
; Capability caller: original input/frame service, explicit drawing and sound.
; atari-7800: untimed turns from a new fire press, with independent field work.
; Owns display/input and $1900-$1904; stack is page 1. IRQ disabled.
turns = $1900
previous = $1901
clock_ticks = $1902
current = $1904
* = $4000
start:
    sei
    cld
    ldx #$ff
    txs
    lda #7
    sta $01                   ; enter/lock 7800 mode; BIOS authentication is external
    lda #0
    sta $3c                   ; MARIA DMA off during pointer setup
    lda #>dll
    sta $2c
    lda #<dll
    sta $30
    jsr init_picture
wait_enable:
    bit $28                   ; enable DMA only during VBlank
    bpl wait_enable
    lda #$40
    sta $3c                   ; 160A, empty display lists, background visible
    lda #0
    sta turns
    sta previous
    sta clock_ticks
    sta clock_ticks+1
main:
    jsr wait_frame
    inc clock_ticks
    bne sample
    inc clock_ticks+1
sample:
    !source "../sample.inc"
    lda current
    nop
    nop
    nop
    nop
    beq no_action
    inc turns
    jsr trigger_sound
no_action:
    lda current
    sta previous
    jsr draw_picture
    jsr service_sound
    jmp main

wait_frame:
    bit $28                   ; MSTAT bit 7: leave any current VBlank
    bmi wait_frame
wait_new:
    bit $28
    bpl wait_new
    rts
irq:
    rti
!source "../picture.inc"
!source "../sound.inc"
    !align 255,0
dll:
    !for i,1,16 { !byte $0f,>$1940,<$1940 }
    !align 255,0
graphics:
    !fill 4096,$ff
    !fill $fffa-*, $ff
    !word irq,start,irq
Atari 7800 deliberately broken input caller.
Observed fault; use the working caller to repair it.

The complete caller

Working setup and integration

demo.asm
; Capability caller: original input/frame service, explicit drawing and sound.
; atari-7800: untimed turns from a new fire press, with independent field work.
; Owns display/input and $1900-$1904; stack is page 1. IRQ disabled.
turns = $1900
previous = $1901
clock_ticks = $1902
current = $1904
* = $4000
start:
    sei
    cld
    ldx #$ff
    txs
    lda #7
    sta $01                   ; enter/lock 7800 mode; BIOS authentication is external
    lda #0
    sta $3c                   ; MARIA DMA off during pointer setup
    lda #>dll
    sta $2c
    lda #<dll
    sta $30
    jsr init_picture
wait_enable:
    bit $28                   ; enable DMA only during VBlank
    bpl wait_enable
    lda #$40
    sta $3c                   ; 160A, empty display lists, background visible
    lda #0
    sta turns
    sta previous
    sta clock_ticks
    sta clock_ticks+1
main:
    jsr wait_frame
    inc clock_ticks
    bne sample
    inc clock_ticks+1
sample:
    !source "sample.inc"
    lda previous
    eor #$ff
    and current
    beq no_action
    inc turns
    jsr trigger_sound
no_action:
    lda current
    sta previous
    jsr draw_picture
    jsr service_sound
    jmp main

wait_frame:
    bit $28                   ; MSTAT bit 7: leave any current VBlank
    bmi wait_frame
wait_new:
    bit $28
    bpl wait_new
    rts
irq:
    rti
!source "picture.inc"
!source "sound.inc"
    !align 255,0
dll:
    !for i,1,16 { !byte $0f,>$1940,<$1940 }
    !align 255,0
graphics:
    !fill 4096,$ff
    !fill $fffa-*, $ff
    !word irq,start,irq

For more responsive controls, compare polling, buffering and press edges in input choices.

Verification and sources

Target: NTSC 48 KiB cartridge, reset without BIOS authentication. These callers were executed with released Emu198x 0.44.1; assembly uses Asm198x 0.0.71. The sample folder contains reproduction instructions and retained observations. The independent checker binds source, native captures and actual output; its rejection tests exercise wrong state, missing files and false audio claims.

This qualifies the named emulator/firmware path. Pitch accuracy, original hardware and other peripherals require their own observations.

Atari, 7800 Software Guide: controller/TIA interface, MARIA/MSTAT and cartridge reset; Stella audio register definitions.