feat(serial): model disconnected multiplayer configuration

This commit is contained in:
0xrsydn 2026-10-07 05:02:23 +07:00
commit c5e19baed4
14 changed files with 500 additions and 44 deletions

View file

@ -1,8 +1,8 @@
# Disconnected serial subset
The core supports disconnected normal-mode transfers, external-clock waiting, and general-purpose pins.
The core supports disconnected normal-mode transfers, external-clock waiting, idle multiplayer configuration, and general-purpose pins.
Internal clocks shift pulled-high input at nominal GBA rates. No link partner is emulated.
External clock edges, multiplayer, UART, Joybus communication, and GPIO interrupts remain unsupported.
External clock edges, connected multiplayer transfers, UART, Joybus communication, and GPIO interrupts remain unsupported.
Unsupported activity remains diagnostic rather than reporting a fabricated completion.
## Registers
@ -13,13 +13,13 @@ Unsupported activity remains diagnostic rather than reporting a fabricated compl
- `SIOCNT` at `0x04000128` retains normal 8/32-bit mode, IRQ configuration, clock selection, and the output-data bit.
The retained mask is `0x508b`. The disconnected serial input is high, except when a general-purpose output drives it low.
Start bit 7 requests a transfer. Bit 0 selects external or internal clock; bit 1 selects the internal rate.
Completion or software cancellation clears start. Multiplayer/UART mode bit 13 remains unsupported.
Completion or software cancellation clears start. Multiplayer uses the separate format described below; UART remains diagnostic.
- `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.
In general-purpose mode, each input reads high through its pull-up. Each output reads its output latch.
`RCNT=0x8000` therefore reads back as `0x800f`, not `0x8000`.
Normal-mode low-byte pin readback remains unmapped rather than guessed.
Normal and multiplayer low-byte pin readback remains unmapped rather than guessed.
- `JOYCNT` permits clearing already-empty status flags. Joybus interrupt enable is unsupported.
- `JOY_RECV` and `JOY_TRANS` permit only zero writes and zero readback for reset initialization.
Nonzero writes return an explicit error. Joybus status and data-transfer side effects are not implemented.
@ -95,6 +95,52 @@ The period arithmetic follows documented GBA rates. Activation phase, mid-transf
No external pin waveform, cable, connected partner, or serial-device protocol is implemented.
Original tests cover individual shifts, batching, cancellation, IRQ gating, HALT/STOP, bus phases, DMA, capture independence, and rollback.
## Disconnected multiplayer configuration
With RCNT bit 15 clear, SIOCNT mode bits 12–13 equal to `2` select multiplayer format.
The retained control mask is `0x6f03`: baud selection, unused writable bits 8–11, mode, and IRQ enable.
This subset models an idle unit without a cable, not a parent with missing players.
- SI reads high in status bit 2, identifying a child rather than a parent.
- SD reads high in bit 3 because the local idle output is high. This does not establish connected peers.
- ID bits 4–5 read a deterministic zero placeholder. Hardware does not define the ID before a completed transfer.
Zero must not be interpreted as an assigned parent role; SI determines that role.
- Error bit 6 and busy bit 7 remain clear. No parent supplies the clock that starts a child transfer.
- Start is read-only for a child. Writing it cannot start a transfer, reset receive data, or request an IRQ.
All baud settings retain this idle behavior. Elapsed cycles, DMA, and repeated start writes cannot create a linked transfer.
No multiplayer event can wake HALT. STOP retains the configuration without advancing clocks.
When GPIO is selected, SI/SD status follows the existing GPIO pin model; multiplayer transfers still cannot run.
RCNT low-byte samples remain unmapped outside GPIO mode. Floating clock-pin timing is not guessed.
### Multiplayer data registers
`SIOMLT_SEND` at `0x0400012a` is a 16-bit latch in multiplayer format.
It shares its low byte with normal-mode SIODATA8. Normal upper-byte reads return zero and writes are ignored.
Normal 8-bit shifts change only the low byte. The hidden upper byte survives mode changes in this bounded model.
A word write to SIOCNT selects the final format before applying both SEND lanes.
`SIOMULTI0` through `SIOMULTI3` occupy halfwords at `0x04000120`, `0x04000122`, `0x04000124`, and `0x04000126`.
The first two alias SIODATA32. The last two are accessible only with multiplayer format selected, including under GPIO.
Byte, halfword, and word accesses preserve independent lanes.
Receive latches start at zero under the synthetic reset policy and retain data across mode changes.
Selecting multiplayer or writing child start does not replace them with `0xffff`, local SEND data, or invented peer data.
Receive writes follow GBATEK's R/W register description. The pinned mGBA implementation instead leaves these writes unhandled.
Physical receive-write behavior, reset values, and hidden upper-byte retention have not been independently measured.
These are bounded register-model choices, not evidence of successful reception or full firmware-reset accuracy.
### Validation and limits
Mode changes use staged serial state at the bus-completion phase.
A high-byte mode write cannot silently cancel a busy normal transfer through multiplayer's read-only start mask.
Clear start explicitly, or wait for normal completion. A completion IRQ already requested remains pending after mode selection.
Block-store preflight observes earlier mode writes and rejects later invalid accesses without committing preceding writes.
Original tests cover control masks, all baud selections, register lanes, aliases, GPIO, HALT/STOP, and ARM/Thumb/DMA stores.
Bus-phase tests cover normal completion, retryable diagnostics, block loads/stores, and mode-dependent staged reads.
There is no parent, cable topology, external clock input, multiplayer timeout, or linked-game compatibility claim.
## BIOS reset
RegisterRamReset always clears the low halfword of SIODATA32, even without bit 5.
@ -102,6 +148,8 @@ 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.
The firmware writes SIODATA8 after selecting normal format. This does not clear the retained upper multiplayer SEND byte.
Full multiplayer reset side effects remain unverified; this increment does not extend the firmware reset sequence.
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.
@ -113,8 +161,10 @@ Inactive configuration bits do not wake HALT. RCNT word accesses still reject th
- [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, MSB-first shifting, rates, pulled-high SI, start/completion, IRQ selection, and external-clock waiting.
- [GBATEK multiplayer mode](https://problemkaputt.de/gbatek-sio-multi-player-mode.htm): child start restrictions, SI/SD status, undefined pre-transfer ID, register widths, and R/W receive registers.
- [LinkRawCable at c61bf351](https://github.com/afska/gba-link-connection/blob/c61bf351f68ad2d6e1c9d72d70e21bec19adfc0b/lib/LinkRawCable.hpp): public API usage for mode selection, SEND, receive words, and separate role/readiness/ID checks. Its disconnected-cable warning is not a pin-level measurement.
- [GBATEK mode summary](https://problemkaputt.de/gbatek-sio-control-registers-summary.htm): RCNT/SIOCNT mode selection.
- [mGBA serial implementation at 3a5e34be](https://github.com/mgba-emu/mgba/blob/3a5e34be33dc7f8f707e5bc9db69e8a430046f21/src/gba/sio.c): cross-checked normal transfer-duration arithmetic and completion IRQ handling. Its no-driver scheduled completion and zero receive data are not copied; they do not establish disconnected hardware behavior.
- [mGBA serial implementation at 3a5e34be](https://github.com/mgba-emu/mgba/blob/3a5e34be33dc7f8f707e5bc9db69e8a430046f21/src/gba/sio.c): cross-checked normal transfer-duration arithmetic and completion IRQ handling. Its no-driver scheduled completion and zero receive data are not copied; they do not establish disconnected hardware behavior. Multiplayer comparison covers SI/SD defaults, receive-write disagreement, and uncertain floating SC timing.
- [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.