Build the complete caller with make -C memotech-mtx/patterns/assembly/input/read-action. Press Space 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. Enter the generated DATA/POKE loader through stock BASIC, then RUN; USR takes over until reset.

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
ld a,$7f
out ($05),a ; select column 7, active-low column drive
in a,($06) ; Space is bit 8 of the 10-bit return: high bit 0
cpl
and 1
ld b,aOUT ($05),$7F selects keyboard column 7; IN ($06) supplies the high part of its return. Space is active-low bit 0 of that read. B receives 0/1; AF/B change.
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=$DF01; turn=$DF00, field clock=$DF02/$DF03; stack below $F7F0. 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
Preserve the read/write distinction and column drive. This direct reader takes over the keyboard configuration rather than consuming a BASIC character.
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
; Original capability caller: owns VDP, one audio channel and declared RAM.
VDP_DATA equ $01
VDP_CTRL equ $02
TURNS equ $df00
SOUND_TICKS equ $df05
; Entered from stock MTX BASIC using POKE and USR. Takes over until reset.
org $e000
start:
di
ld sp,$f7f0
xor a
ld ($df00),a
ld ($df01),a
ld ($df02),a
ld ($df03),a
in a,($02)
xor a
out ($02),a
ld a,$80
out ($02),a ; R0 legacy graphics
xor a
out ($02),a
ld a,$81
out ($02),a ; R1 display and VDP IRQ disabled
call init_picture
main:
call wait_frame
ld hl,($df02)
inc hl
ld ($df02),hl
include "../sample.inc"
ld a,($df01)
ld a,b
nop
jr z,no_action
ld a,($df00)
inc a
ld ($df00),a
call trigger_sound
no_action:
ld a,b
ld ($df01),a
call draw_picture
call service_sound
jp main
; AF clobbered; caller exclusively owns status/control-port latch.
wait_frame:
in a,($02)
wait_new:
in a,($02)
and $80
jr z,wait_new
ret
include "../picture.inc"
include "../sound.inc"
The complete caller
Working setup and integration
; Original capability caller: owns VDP, one audio channel and declared RAM.
VDP_DATA equ $01
VDP_CTRL equ $02
TURNS equ $df00
SOUND_TICKS equ $df05
; Entered from stock MTX BASIC using POKE and USR. Takes over until reset.
org $e000
start:
di
ld sp,$f7f0
xor a
ld ($df00),a
ld ($df01),a
ld ($df02),a
ld ($df03),a
in a,($02)
xor a
out ($02),a
ld a,$80
out ($02),a ; R0 legacy graphics
xor a
out ($02),a
ld a,$81
out ($02),a ; R1 display and VDP IRQ disabled
call init_picture
main:
call wait_frame
ld hl,($df02)
inc hl
ld ($df02),hl
include "sample.inc"
ld a,($df01)
cpl
and b
jr z,no_action
ld a,($df00)
inc a
ld ($df00),a
call trigger_sound
no_action:
ld a,b
ld ($df01),a
call draw_picture
call service_sound
jp main
; AF clobbered; caller exclusively owns status/control-port latch.
wait_frame:
in a,($02)
wait_new:
in a,($02)
and $80
jr z,wait_new
ret
include "picture.inc"
include "sound.inc"For more responsive controls, compare polling, buffering and press edges in input choices.
Verification and sources
Target: MTX500 PAL, stock BASIC DATA/POKE/USR entry. 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.
Memotech, MTX Series Operator’s Manual/technical description: keyboard matrix, sound I/O and USR; TI SN76489A data manual.