feat(serial): retain disconnected external-clock requests

This commit is contained in:
0xrsydn 2026-10-07 03:58:04 +07:00
commit d329c76dc3
9 changed files with 299 additions and 22 deletions

View file

@ -65,9 +65,10 @@ The repository is a Cargo workspace with three crates:
| `crates/gba-core/tests/pulse_sound/channel2.rs` | Channel 2 mapping, register gaps, independent state, shared clocks, and sum-before-rounding mixing |
| `crates/gba-core/tests/direct_sound.rs` | FIFO lanes/reset, signed mixing, timer selection, DMA refill, and HALT/STOP |
| `crates/gba-core/src/memory/audio_step_tests.rs` | Audio access phases, shadow validation, and CPU/DMA failure rollback |
| `crates/gba-core/src/io/inactive.rs` | Disconnected serial initialization with explicit unsupported-activity validation |
| `crates/gba-core/src/io/inactive.rs` | Disconnected serial registers, external-clock waiting, and unsupported-activity validation |
| `crates/gba-core/tests/inactive_devices.rs` | Device masks, wave RAM, GPIO pull-ups, serial data, and failed CPU/DMA write isolation |
| `crates/gba-core/tests/serial_control.rs` | RCNT mode gating, inactive bits, byte/halfword lanes, CPU/DMA diagnostics, and interrupt isolation |
| `crates/gba-core/tests/serial_external.rs` | External-clock waiting, cancellation, HALT/STOP, ARM/Thumb/DMA starts, and atomic diagnostics |
| `crates/gba-core/src/io/timer_step.rs` | Staged timer/audio state, divider phase, timer IF bits, and sound refill requests at ordered CPU/DMA bus phases |
| `crates/gba-core/src/memory/timer_step_tests.rs` | Timer access phases, coherent lanes, cascades, IF ordering, rollback, DMA, idle, and clock ownership |
| `crates/gba-core/src/display.rs` | Display clock, scanline status, comparison edges, and display IRQ events |

View file

@ -1,7 +1,7 @@
# Disconnected serial initialization subset
# Disconnected serial subset
The core supports idle normal-mode data registers and disconnected general-purpose pins.
It does not support link transfers, multiplayer, UART, Joybus communication, or external serial interrupts.
The core supports normal-mode data registers, disconnected external-clock waiting, and general-purpose pins.
It does not support internally clocked transfers, external clock edges, multiplayer, UART, Joybus communication, or external serial interrupts.
Unsupported activity remains diagnostic rather than reporting a fabricated completion.
## Registers
@ -9,8 +9,9 @@ Unsupported activity remains diagnostic rather than reporting a fabricated compl
- `SIODATA32` at `0x04000120` is a four-byte latch in the supported normal-mode subset.
- `SIODATA8` at `0x0400012a` retains its low byte; its upper byte reads zero.
- `SIOCNT` at `0x04000128` retains normal 8/32-bit mode, IRQ configuration, clock selection, and the output-data bit.
The retained mask is `0x500b`. The disconnected serial input is high, except when a general-purpose output drives it low.
Transfer-start bit 7 and multiplayer/UART mode bit 13 return explicit errors.
The retained mask is `0x508b`. The disconnected serial input is high, except when a general-purpose output drives it low.
Start bit 7 can latch when clock-source bit 0 is clear. Software clears bit 7 to cancel the request.
Setting both bits 7 and 0 returns an internally-clocked-transfer diagnostic. Multiplayer/UART mode bit 13 remains unsupported.
- `RCNT` at `0x04000134` retains mode bits, interrupt configuration, output latches, and pin directions with mask `0xc1ff`.
With bit 15 clear, bits 8 and 14 are writable latches without GPIO interrupt or Joybus effects.
With bit 15 set, bit 14 selects Joybus; otherwise bit 8 enables GPIO interrupts. Both active configurations remain diagnostic.
@ -25,12 +26,29 @@ GPIO means general-purpose input/output. UART means universal asynchronous recei
No external serial device is connected. Elapsed cycles alone do not change serial data or generate an IRQ.
Configuration that hardware accepts in other modes can still be rejected by this intentionally limited subset.
## External-clock waiting
In normal 8-bit or 32-bit mode, setting start with clock-source bit 0 clear requests externally clocked communication.
No device is connected, so no external clock edges arrive. Start remains set; data does not shift and no completion IRQ occurs.
The internal-rate selector, bit 1, does not supply clocks when bit 0 is clear.
CPU cycles, timer overflows, display events, and DMA activity cannot manufacture external serial clocks.
Repeated start writes do not complete the request. Software can cancel it by clearing start, including through BIOS serial reset.
General-purpose mode does not shift serial data. A retained external-clock start bit has no link-port effect there.
Returning to normal mode still cannot complete a transfer without external clock edges.
Selecting internal clock while start is set remains diagnostic, including after an external request.
This is a disconnected waiting model, not an implementation of a connected link or an external clock-input API.
Original tests cover both widths, rate settings, control lanes, cancellation, GPIO selection, HALT/STOP, and ARM/Thumb stores.
DMA tests distinguish its own completion IRQ from a serial IRQ. Invalid word/block stores cannot leave a partial start request.
## BIOS reset
RegisterRamReset always clears the low halfword of SIODATA32, even without bit 5.
The upper halfword remains unchanged in this functional subset.
With bit 5 selected, the firmware clears SIOCNT and SIODATA8, selects general-purpose inputs, and clears the supported Joybus reset registers.
It uses ordinary ARM bus stores, not a host-side reset bypass.
Clearing SIOCNT cancels a pending external-clock request. Unselected serial reset leaves that request pending.
Original tests cover independent byte lanes, input pull-ups, output directions, reset flag selection, and explicit unsupported operations.
Whole-access and block-store validation prevent a rejected control value from committing preceding bytes or registers.
@ -41,7 +59,8 @@ Inactive configuration bits do not wake HALT. RCNT word accesses still reject th
## References
- [GBATEK reset functions](https://problemkaputt.de/gbatek-bios-reset-functions.htm): reset flags, general-purpose selection, and the unconditional SIODATA32 side effect.
- [GBATEK normal serial mode](https://problemkaputt.de/gbatek-sio-normal-mode.htm): data widths, input status, control bits, and writable unused RCNT bits 8/14.
- [GBATEK normal serial mode](https://problemkaputt.de/gbatek-sio-normal-mode.htm): data widths, input status, writable unused RCNT bits 8/14, and external-clock slave start/wait/timeout behavior.
- [mGBA serial implementation at 3a5e34be](https://github.com/mgba-emu/mgba/blob/3a5e34be33dc7f8f707e5bc9db69e8a430046f21/src/gba/sio.c): compared normal-mode control and completion paths. Its no-driver scheduled completion does not establish disconnected external-clock hardware behavior; this core does not copy that fallback.
- [GBATEK](https://mgba-emu.github.io/gbatek/): GBA general-purpose pin directions, internal pull-ups, SI falling-edge interrupts, and the SIO mode-selection table.
- [mGBA BIOS implementation at 3a5e34be](https://github.com/mgba-emu/mgba/blob/3a5e34be33dc7f8f707e5bc9db69e8a430046f21/src/gba/bios.c): functional serial reset defaults, not copied source.

View file

@ -48,13 +48,18 @@ The original copy service still executes all its reads and writes. No ROM patch
Host writes remain strict. Reference-emulator comparisons and original tests support this bounded bus behavior.
The trace stayed local; no game code or assets were added to the repository.
Both runs pass the copy and now stop at an unsupported serial-transfer start:
The copy correction reached a serial-transfer start at PC `0x082e6e5c`.
A local register trace found RCNT zero and a SIOCNT write of `0x5084`: 32-bit mode, IRQ enabled, external clock selected.
With no connected clock source, this request must wait rather than complete on elapsed CPU cycles.
The [serial subset](../hardware/serial.md#external-clock-waiting) now retains the request without shifting data or raising a serial IRQ.
Both runs pass that request and next stop when software selects internal clock while start remains set:
```text
Steps: 426406; instructions: 424636; IRQ entries: 2; DMA units: 1768; HALT idle: 0
Nominal cycles: 1416670
PC=0x082e6e5c
unsupported serial transfer start: write 0x84 at 0x04000128
Steps: 426523; instructions: 424753; IRQ entries: 2; DMA units: 1768; HALT idle: 0
Nominal cycles: 1416980
PC=0x082e6eb8
unsupported internally clocked serial transfer: write 0x85 at 0x04000128
```
The native run captures five startup frames. These do not establish a working title screen or gameplay.
@ -69,10 +74,11 @@ Workspace debug/release tests, strict Clippy, public ARM/Thumb/memory/BIOS check
Native ROM-window tests and graphics smoke modes pass on Darwin arm64.
The pinned Pong debug/release reports match.
The next investigation is the serial-transfer start at SIOCNT (`0x04000128`).
Check RCNT mode, clock selection, disconnected-input behavior, and completion/IRQ timing before implementing a transfer model.
The next requirement is internally clocked normal serial communication, including switching from a pending external-clock request.
Implement nominal shift periods, disconnected input sampling, completion, and IRQ behavior with deterministic tests.
Keep completion consistent with HALT, STOP, instruction timing, and diagnostic rollback.
Do not invent a connected partner or immediate completion to suppress the diagnostic.
The corrected inactive RCNT write does not establish a need for GPIO interrupts.
The external-clock waiting result does not establish linked gameplay or GPIO interrupt support.
Noise now has deterministic counter clocks and shares tested length/envelope logic with the independent pulse channels.
Sweep applies only to channel 1. Direct Sound has FIFO clocks and nominal DMA requests.

View file

@ -142,7 +142,8 @@ There is no host audio output or cartridge save support.
The [audio subset](hardware/audio.md) supports Direct Sound, both PSG pulse channels, noise channel 4, idle wave channel 3 state, and instantaneous digital mixing.
It does not yet provide a continuous sample stream. Wave channel 3 playback and unverified sound-DMA pairings remain diagnostic.
PSG timing and signed mixing are nominal; hardware startup edges and analog behavior remain unverified.
The [serial initialization subset](hardware/serial.md) supports idle normal data and disconnected general-purpose pins, not active transfers.
The [serial subset](hardware/serial.md) supports normal data, disconnected external-clock waiting, and general-purpose pins.
External requests retain start/busy without completion or IRQ. Internally clocked transfers and connected links remain unsupported.
RCNT retains inactive bits 8/14 in normal mode. Effective GPIO interrupt enable and Joybus selection remain diagnostic.
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.
@ -155,7 +156,8 @@ Audio, saves, and external BIOS loading remain unavailable. ROM loading does not
A local Emerald run now completes its all-device reset and master sound enable.
It also passes the pulse/noise triggers and normal-mode RCNT configuration.
It also completes a CpuSet call to address zero through the corrected ignored BIOS-write behavior.
It next stops at an unsupported serial-transfer start (`0x04000128`, PC `0x082e6e5c`).
It also accepts an external-clock serial request without inventing clock edges or completion.
It next stops when software selects internal serial clock (`0x04000128`, PC `0x082e6eb8`).
No title-screen, gameplay, or audible-game compatibility is established.
See [the startup result](research/emerald-reset.md) for the bounded run and next investigation.
See [cartridge loading](hardware/cartridge.md) for file limits, step budgets, and exit status.