Step 1 of 5 · Reading · ~3 min
Read
Display & Input
FX0A: Blocking Key Wait
Every other CHIP-8 instruction finishes in one step. FX0A does not: it means "stop here until the player presses a key, then put that key's number in VX". Title screens, "press any key" prompts and menus all use it. After this lesson your emulator can block on it without freezing everything else.
Why this one is awkward
A loop that sits inside the instruction and waits for the keypad would work in a toy, but the emulator has other jobs between instructions: the 60 Hz timers must keep ticking, the screen must keep being shown, and the host must keep delivering key events. If the CPU spins inside FX0A, none of that runs, so the key event that would end the wait can never arrive.
The fix is to make the wait a state instead of a loop. The instruction records which register is waiting and returns at once. While that state is set, the CPU does nothing when asked to step; everything else carries on.
state: waiting = none | waiting = register X
execute FX0A: waiting = X (PC already points at the next instruction)
step(): if waiting, return (the instruction after FX0A does not run yet)
key event: if waiting, finish: V[X] = key, waiting = none
Fetch advanced PC before FX0A ran, so when the wait ends the program simply continues with the next instruction. Nothing needs rewinding.
A trace with different material
ROM: F30A 6401 (wait for a key into V3, then V4 = 1)
RUN 5 FX0A runs, the machine is now waiting; the other 4 steps do nothing
KEY 9 waiting ends at once: V3 = 9
RUN 1 6401 runs: V4 = 1
RUN n still counts n instructions of CPU time; the steps spent waiting are simply wasted, which is what a real CPU spinning on a key would do. A TICK during the wait still counts the timers down.
Which key counts?
Only a key pressed after the wait began. If the player is still holding the key that dismissed the previous screen, FX0A must not return instantly with it; that is how a title screen gets skipped by accident. The harness delivers presses as KEY k events, so the rule is: a KEY event during the wait finishes it, and keys that were already down are ignored.
The release quirk
Some interpreters finish the wait on a key press, and some (the original COSMAC VIP did) only when that key is let go again. The harness switches between them with WAITFOR PRESS (the default) and WAITFOR RELEASE. In release mode the wait remembers the first key pressed during it and finishes when UP arrives for that same key; a key released that was never pressed during the wait does nothing.
Common mistakes
- Spinning inside the instruction, so timers and key events stop.
- Re-executing
FX0Aover and over by rewinding PC; it works until a held key satisfies it instantly. - Taking a key that was already down when the wait began.
- Storing the key in the wrong register, or in V0 every time.
- Letting the CPU run on while waiting.
Your exercise
The starter has the harness, WAITFOR, and every earlier instruction. You write FX0A itself and the key-press and key-release hooks that end a wait.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…