Skip to content

Read a button on Master System

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

Build the complete caller with make -C sega-master-system/patterns/assembly/input/read-action. Press button 1 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.

Master System 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
    in a,($dc)
    cpl
    and $10
    ld b,a

IN ($DC), complement and mask $10 returns button 1 as 0/$10 in B. AF/B change. The caller does not change pad I/O direction mid-read.

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=$C001; turn=$C000, field clock=$C002/$C003; stack below $C3F0. 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

Combine direction/button bits into one sample before calculating edges. Light guns and paddles need different readers.

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
; Original capability caller: owns VDP, one audio channel and declared RAM.
VDP_DATA equ $be
VDP_CTRL equ $bf
TURNS equ $c000
SOUND_TICKS equ $c005
    org 0
    jp start
    defs $66-$,0
    retn
    defs $100-$,0
start:
    di
    ld sp,$c3f0
    xor a
    ld ($c000),a
    ld ($c001),a
    ld ($c002),a
    ld ($c003),a
    call init_picture
main:
    call wait_frame
    ld hl,($c002)
    inc hl
    ld ($c002),hl
    include "../sample.inc"
    ld a,($c001)
    ld a,b
    nop
    jr z,no_action
    ld a,($c000)
    inc a
    ld ($c000),a
    call trigger_sound
no_action:
    ld a,b
    ld ($c001),a
    call draw_picture
    call service_sound
    jp main
wait_frame:
    in a,($bf)
wait_new:
    in a,($bf)
    and $80
    jr z,wait_new
    ret
    include "../picture.inc"
    include "../sound.inc"
    defs $7ff0-$,0
    db "TMR SEGA"
    db 0,0,0,0,0,0,0,$4c
Master System deliberately broken input caller.
Observed fault; use the working caller to repair it.

The complete caller

Working setup and integration

demo.asm
; Original capability caller: owns VDP, one audio channel and declared RAM.
VDP_DATA equ $be
VDP_CTRL equ $bf
TURNS equ $c000
SOUND_TICKS equ $c005
    org 0
    jp start
    defs $66-$,0
    retn
    defs $100-$,0
start:
    di
    ld sp,$c3f0
    xor a
    ld ($c000),a
    ld ($c001),a
    ld ($c002),a
    ld ($c003),a
    call init_picture
main:
    call wait_frame
    ld hl,($c002)
    inc hl
    ld ($c002),hl
    include "sample.inc"
    ld a,($c001)
    cpl
    and b
    jr z,no_action
    ld a,($c000)
    inc a
    ld ($c000),a
    call trigger_sound
no_action:
    ld a,b
    ld ($c001),a
    call draw_picture
    call service_sound
    jp main
wait_frame:
    in a,($bf)
wait_new:
    in a,($bf)
    and $80
    jr z,wait_new
    ret
    include "picture.inc"
    include "sound.inc"
    defs $7ff0-$,0
    db "TMR SEGA"
    db 0,0,0,0,0,0,0,$4c

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

Verification and sources

Target: NTSC stock Master System cartridge configuration. 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.

Sega, Master System Software Reference Manual: I/O port $DC, controller interface, VDP status and PSG.