feat(input): implement KEYCNT keypad interrupt control
Add a dependency-free keypad state machine in gba-core, map KEYCNT, latch IF bit 12, and wake HALT through the existing interrupt gates. Sample complete CPU/DMA control writes once so transient byte values cannot create false requests. Document the mGBA-style polling policy and its unverified hardware retrigger limits. Cover every button-state/selection pair, register masks, repeated requests, byte/word writes, failed-store isolation, DMA priority, ARM/Thumb IRQ return, BIOS IntrWait, and retained BIOS reset state. Follow the restructured workspace and modular documentation. Validated on Darwin arm64: workspace and core/demo tests pass in debug and release, with Clippy, rustdoc, ten native window smoke tests, and terminal demos passing.
This commit is contained in:
parent
7d396fea35
commit
597b02881b
14 changed files with 710 additions and 21 deletions
|
|
@ -61,6 +61,7 @@ The repository is a Cargo workspace with three crates:
|
|||
| `crates/gba-core/src/video/sprites/pipeline.rs` | Two prepared row buffers, cycle40 events, and bounded capture-disabled advancement |
|
||||
| `crates/gba-core/src/video/sprites/budget.rs` | Nominal per-row work allowance, partial canvas prefixes, and independent arithmetic tests |
|
||||
| `crates/gba-core/src/input.rs` | Platform-independent GBA button state |
|
||||
| `crates/gba-core/src/input/keypad.rs` | KEYCNT mask, OR/AND matching, and keypad IRQ sampling history |
|
||||
| `crates/gba-demos/src/graphics_demo.rs` | Original ARM bitmap program and shared bounded frame runner |
|
||||
| `crates/gba-demos/src/tile_demo.rs` | Original ARM tile/sprite program, palettes, tiles, maps, and OAM image |
|
||||
| `crates/gba-demos/src/affine_demo.rs` | Shared ARM background program builder and Mode 2 assets |
|
||||
|
|
@ -84,6 +85,7 @@ The repository is a Cargo workspace with three crates:
|
|||
| `crates/gba-core/tests/timers.rs` | Timer rules, interrupt registers, and a cycle-by-cycle reference |
|
||||
| `crates/gba-core/tests/machine.rs` | Device IRQ entry/return, clock policy, and I/O failure atomicity |
|
||||
| `crates/gba-core/tests/timing.rs` | WAITCNT fields, bus costs, and timer/IRQ timing integration |
|
||||
| `crates/gba-core/tests/keypad.rs` | Keypad register widths, IRQ sampling, CPU/DMA ordering, HALT wake-up, diagnostics, and BIOS IntrWait |
|
||||
| `crates/gba-core/tests/graphics.rs` | Video memory, rendering, KEYINPUT, and CPU-driven graphics integration |
|
||||
| `crates/gba-core/tests/tiles.rs` | Mode 0 registers, maps, palettes, composition, diagnostics, and CPU tile/sprite demo |
|
||||
| `crates/gba-core/tests/affine_backgrounds.rs` | Affine registers, maps, transforms, bitmap sampling, composition, and CPU demo |
|
||||
|
|
|
|||
|
|
@ -166,8 +166,8 @@ Bit 7 runs after the selected RAM clears:
|
|||
Timer counter reads retain the stopped count until a later enable loads the cleared reload value.
|
||||
This is normal timer-register behavior, not a host-side replacement of device state.
|
||||
Read-only display status and VCOUNT continue to reflect the advancing display clock.
|
||||
GREENSWAP, KEYINPUT/button state, POSTFLG, and BIOS IRQ communication words are not reset.
|
||||
Keypad interrupt control is not implemented. Bit 7 covers only the listed supported registers.
|
||||
GREENSWAP, KEYINPUT/button state, KEYCNT, POSTFLG, and BIOS IRQ communication words are not reset.
|
||||
Bit 7 covers only the listed registers. A later matching input sample can request keypad IRQ again after IF acknowledgement.
|
||||
|
||||
Without bit 7, device configuration remains unchanged except for DISPCNT.
|
||||
IRQ delivery stays CPU-masked during the call. The service restores the caller's mask on return.
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ Mapped input/output (I/O) registers:
|
|||
| --- | --- | --- |
|
||||
| `0x04000100` + `4*n` | Timer n counter/reload | Reads the counter; writes the separate reload value |
|
||||
| `0x04000102` + `4*n` | Timer n control | Prescaler, count-up, local IRQ enable, and start/stop |
|
||||
| `0x04000130` | KEYINPUT | Ten active-low button bits; read-only |
|
||||
| `0x04000132` | KEYCNT | Button selection, keypad IRQ enable, and OR/AND condition |
|
||||
| `0x04000200` | IE | Enables selected interrupt sources; bits 0–13 are writable |
|
||||
| `0x04000202` | IF | Latches requests; writing 1 clears the corresponding bit |
|
||||
| `0x04000204` | WAITCNT | Configures first/second ROM access wait states; unused bits read as zero |
|
||||
|
|
@ -61,7 +63,7 @@ Byte, halfword, and word accesses are supported for this register subset.
|
|||
|
||||
Timer startup delays and shared prescaler phase are not modeled.
|
||||
The provisional timer model resets its private prescaler phase on enable or clock-source changes.
|
||||
Audio events, STOP, and interrupt sources other than timers, display events, and DMA completion are not implemented.
|
||||
Audio events, STOP, and interrupt sources other than timers, display events, DMA completion, and keypad input are not implemented.
|
||||
|
||||
`--timer-demo` executes original ARM code that configures Timer 0, IE, and IME.
|
||||
The timer overflows after 16 supplied cycles and enters the original handler through vector `0x18`.
|
||||
|
|
@ -70,6 +72,59 @@ The demo ends after 21 steps and 153 nominal cycles with one handler call, using
|
|||
These counts test the timing model; they are not hardware timing measurements.
|
||||
Its test handler deliberately changes r2 and r10; it does not implement the Nintendo BIOS calling convention.
|
||||
|
||||
## Keypad interrupt control
|
||||
|
||||
`KEYCNT` resets to zero and stores only bits selected by `0xc3ff`:
|
||||
|
||||
| Bits | Meaning |
|
||||
| --- | --- |
|
||||
| 0–9 | Select A, B, Select, Start, Right, Left, Up, Down, R, and L |
|
||||
| 10–13 | Unused; read as zero |
|
||||
| 14 | Enable keypad interrupt requests |
|
||||
| 15 | Zero: OR condition; one: AND condition |
|
||||
|
||||
OR matches when any selected button is pressed.
|
||||
AND matches when every selected button is pressed; unselected pressed buttons do not prevent a match.
|
||||
An empty selection never matches OR and always matches AND.
|
||||
|
||||
A matching enabled sample can latch IF bit 12, independently of IE, IME, and CPSR.I.
|
||||
Changing input or disabling KEYCNT does not clear an existing request.
|
||||
Software acknowledges IF by writing bit 12 as one.
|
||||
IE bit 12 gates HALT wake-up. IME and CPSR.I gate IRQ delivery, not wake-up or request latching.
|
||||
Ready DMA units still take priority over CPU IRQ entry.
|
||||
The original BIOS IntrWait can consume keypad events through the normal IRQ callback contract.
|
||||
|
||||
### Sampling policy and limits
|
||||
|
||||
The current functional model follows mGBA's polling behavior, not a verified hardware edge detector:
|
||||
|
||||
- Each `Memory::set_buttons` call samples the input, including repeated identical values.
|
||||
- Each successful write touching KEYCNT samples after the complete register update.
|
||||
- OR requests on every matching enabled sample, so another identical input sample can reassert an acknowledged request.
|
||||
- AND remembers the complete pressed-button snapshot and suppresses an identical matching sample.
|
||||
- A different matching snapshot requests again, including changes to unselected buttons.
|
||||
- An enabled nonmatching sample clears that history. Disabled samples retain it.
|
||||
- Newly selected buttons are removed from the remembered snapshot before testing a control write.
|
||||
A newly selected held button can therefore cause another AND request.
|
||||
- Reads, KEYINPUT-only writes, IF acknowledgement, and clock advancement do not sample the keypad.
|
||||
|
||||
This policy makes IRQ generation depend on input sampling, not only on elapsed emulated time.
|
||||
Host input calls consume no emulated cycles and do not modify CPU registers.
|
||||
They can wake HALT immediately; `Machine::step` subsequently samples the IRQ line.
|
||||
The desktop demos currently supply frame-based input snapshots.
|
||||
Physical key-event timing, switch bounce, exact hardware retrigger rules, and synchronization delays remain unverified.
|
||||
STOP still returns a diagnostic; this change does not implement STOP wake-up.
|
||||
|
||||
Byte writes merge with the untouched KEYCNT byte.
|
||||
Halfword writes, and word writes at KEYINPUT, evaluate the final KEYCNT value once.
|
||||
They do not generate requests from temporary byte-by-byte values.
|
||||
The lower half of a word write remains a read-only KEYINPUT write.
|
||||
CPU, DMA, and host/debug writes use the same path.
|
||||
Failed writes and failed block stores leave control, IRQ history, pending flags, and HALT state unchanged.
|
||||
|
||||
The current BIOS SoftReset and RegisterRamReset subset preserve KEYCNT and button state.
|
||||
RegisterRamReset bit 7 still acknowledges IF, but a later matching input sample can request keypad IRQ again.
|
||||
|
||||
## HALT and power-control registers
|
||||
|
||||
Writing HALTCNT with bit 7 clear requests HALT. Bits 0–6 are ignored.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ Rendering behavior implemented in `crates/gba-core/src/video/`, plus button inpu
|
|||
`GREENSWAP` at `0x04000002` exchanges the green channels of adjacent pixel pairs when bit zero is set.
|
||||
`KEYINPUT` at `0x04000130` exposes ten active-low buttons. Unused bits read as zero; writes are ignored.
|
||||
`Memory::set_buttons(Buttons)` supplies pressed-high host input. The I/O layer converts it to active-low register bits.
|
||||
`KEYCNT` and keypad IRQs are not implemented; accesses to KEYCNT return unmapped-memory diagnostics.
|
||||
`KEYCNT` at `0x04000132` selects buttons, OR/AND matching, and keypad interrupt enable.
|
||||
Input samples and control writes can latch IF bit 12 and wake HALT without advancing the clock.
|
||||
See [keypad interrupt control](timers-irq.md#keypad-interrupt-control) for the sampling policy and limits.
|
||||
|
||||
Video RAM starts at `0x06000000` and contains 96 KiB.
|
||||
Its 128 KiB mirror layout repeats the final 32 KiB in offsets `0x18000..0x1ffff`.
|
||||
|
|
|
|||
|
|
@ -45,7 +45,11 @@ Hardware references used for the core:
|
|||
- [NanoBoyAdvance composition](https://github.com/nba-emu/NanoBoyAdvance/blob/master/src/nba/src/hw/ppu/merge.cc), reviewed for palette lookup and horizontal mosaic after sprite preparation.
|
||||
- [mGBA window renderer](https://github.com/mgba-emu/mgba/blob/master/src/gba/renderers/video-software.c), reviewed for inverted bounds and vertical edge flags.
|
||||
- [NanoBoyAdvance window implementation](https://github.com/nba-emu/NanoBoyAdvance/blob/master/src/nba/src/hw/ppu/window.cc), reviewed for persistent vertical flags, four-cycle horizontal comparisons, offscreen columns, and end-edge precedence.
|
||||
- [GBATEK keypad input](https://problemkaputt.de/gbatek-gba-keypad-input.htm).
|
||||
- [GBATEK keypad input](https://problemkaputt.de/gbatek-gba-keypad-input.htm), for KEYINPUT/KEYCNT fields and selected-button OR/AND matching.
|
||||
- [mGBA keypad sampling](https://github.com/mgba-emu/mgba/blob/master/src/gba/gba.c) and [control writes](https://github.com/mgba-emu/mgba/blob/master/src/gba/io.c), reviewed for repeated OR requests, AND snapshot suppression, and newly selected held keys.
|
||||
- [NanoBoyAdvance keypad implementation](https://github.com/nba-emu/NanoBoyAdvance/blob/master/src/nba/src/hw/keypad/keypad.cc), compared for control access widths; its AND/retrigger behavior differs from the chosen polling model.
|
||||
- [mGBA keypad timing issue](https://github.com/mgba-emu/mgba/issues/2490), for frontend frame-based input timing limits.
|
||||
- [Tonc hardware interrupts](https://gbadev.net/tonc/interrupts.html), for keypad source enable and IF/IE bit 12.
|
||||
- [GBATEK memory mirrors and video byte writes](https://problemkaputt.de/gbatek-gba-unpredictable-things.htm).
|
||||
- [GBATEK GBA memory map and bus widths](https://problemkaputt.de/gbatek-gba-memory-map.htm).
|
||||
- [GBATEK GBA DMA transfers](https://problemkaputt.de/gbatek-gba-dma-transfers.htm).
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ Update this file when a feature lands or a limit is removed.
|
|||
- Alpha blending, brightness increase/decrease, and semi-transparent sprites using five-bit color arithmetic.
|
||||
- 96 KiB video RAM, 1 KiB palette RAM, and 1 KiB object attribute memory, with mirrors and byte-write behavior.
|
||||
- Active-low `KEYINPUT` for all ten GBA buttons, independent of the window library.
|
||||
- `KEYCNT` selection and OR/AND matching, keypad IRQ latching, and HALT wake-up through IE bit 12.
|
||||
- Original ARM graphics demo that uses DMA, BIOS VBlank waiting, and a ROM-side IRQ callback.
|
||||
- Sixteen active 32-bit CPU registers, with ARM7 mode-specific register banks.
|
||||
- User, System, Supervisor, IRQ, FIQ, Abort, and Undefined modes.
|
||||
|
|
@ -95,7 +96,8 @@ Horizontal window comparators retain four-cycle event history.
|
|||
Sprite rows prepare one line ahead with a whole-row cycle40 sample and nominal per-row work limits.
|
||||
Individual fetch timing, hardware-accurate work cutoffs, video-bus contention, and per-pixel color composition remain unimplemented.
|
||||
There is no sound or cartridge save support.
|
||||
Mapped I/O covers DMA, timers, interrupts, WAITCNT, display control/status, background control/scroll/affine registers, window/effect registers, KEYINPUT, POSTFLG, and HALTCNT.
|
||||
Mapped I/O covers DMA, timers, interrupts, WAITCNT, display control/status, background control/scroll/affine registers, window/effect registers, KEYINPUT/KEYCNT, POSTFLG, and HALTCNT.
|
||||
Keypad IRQs use a documented polling model; hardware retrigger edges and asynchronous input timing remain unverified.
|
||||
The presentation framebuffer is separate from emulated video RAM.
|
||||
All named graphics demos connect desktop input and rendering to the emulated CPU. The default display test remains host-generated.
|
||||
The executable does not accept ROM files yet.
|
||||
|
|
@ -110,7 +112,7 @@ Writes to cartridge addresses return errors instead of modeling cartridge hardwa
|
|||
|
||||
1. Validate CPU behavior with public ARM7TDMI test programs before claiming instruction compatibility.
|
||||
2. Refine nominal timing with a fetch pipeline, Game Pak prefetch, per-access device updates, and verified timer/IRQ delays.
|
||||
3. Add keypad interrupt control and remaining device registers; extend BIOS reset coverage as sound/serial support becomes available.
|
||||
3. Validate keypad retrigger behavior with hardware tests and add remaining device registers; extend BIOS reset coverage as sound/serial support becomes available.
|
||||
Add STOP and remaining DMA device modes with verified timing and wake-up behavior.
|
||||
4. Replace nominal sprite work limits with verified individual fetch timing; add background fetch timing and per-pixel composition.
|
||||
5. Expand graphics, audio, cartridge loading, and saves before testing Emerald compatibility.
|
||||
|
|
|
|||
|
|
@ -148,6 +148,10 @@ Frame tests verify consecutive VBlank events, step limits, error handling, and i
|
|||
Graphics tests check CPU-generated pixels, movement, edge clamping, opposite directions, colors, and reset behavior.
|
||||
Video tests cover mirrors, byte-write rules, RGB555 layout, backdrop, forced blank, green swap, and unsupported modes.
|
||||
Input tests cover all 1,024 button combinations, read-only KEYINPUT behavior, keyboard mapping, and focus loss.
|
||||
Keypad tests compare every button-state/selection pair with independent per-button OR/AND logic.
|
||||
They check all KEYCNT values, byte merging, complete-word sampling, empty masks, and repeated request behavior.
|
||||
Integration tests cover CPU/DMA writes, interrupt masks, HALT wake-up, ARM/Thumb IRQ return, and original BIOS IntrWait.
|
||||
Failed-store tests check register, IRQ-history, CPU, and clock preservation. BIOS reset tests verify retained KEYCNT state.
|
||||
The bounded graphics frame runner is checked for instruction errors and timeouts.
|
||||
Timing tests cover every ROM wait-state setting, access width, ROM window, and 128 KiB boundary handling.
|
||||
Instruction timing tests cover arithmetic, shifts, branches, transfers, block operations, multiply, and exception returns.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue