feat(serial): clock disconnected normal transfers and completion IRQs
This commit is contained in:
parent
d329c76dc3
commit
0b36ef1e24
17 changed files with 860 additions and 196 deletions
|
|
@ -544,5 +544,6 @@ Unsupported SWIs, unsupported exception vectors, and null/misaligned IRQ callbac
|
|||
The CPU reports `CpuError::UnsupportedInstruction` with `bios::UNSUPPORTED_TRAP`, rather than silently treating a service as a no-op.
|
||||
Invalid arithmetic/decompression arguments use the same CPU error type with the distinct `bios::INVALID_ARGUMENT_TRAP` instruction.
|
||||
Prior boot/service steps remain committed on failure.
|
||||
PSG wave channel 3, host audio output, serial transfers, HardReset, and serial/Game Pak STOP wake-up remain unimplemented.
|
||||
PSG wave channel 3, host audio output, connected serial links, HardReset, and serial/Game Pak STOP wake-up remain unimplemented.
|
||||
Disconnected normal serial transfers use the [bounded serial model](serial.md); cancel active transfers before BIOS serial reset.
|
||||
This subset is not sufficient for Pokémon Emerald compatibility.
|
||||
|
|
|
|||
|
|
@ -1,17 +1,19 @@
|
|||
# Disconnected serial subset
|
||||
|
||||
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.
|
||||
The core supports disconnected normal-mode transfers, external-clock waiting, 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.
|
||||
Unsupported activity remains diagnostic rather than reporting a fabricated completion.
|
||||
|
||||
## Registers
|
||||
|
||||
- `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.
|
||||
- `SIODATA32` at `0x04000120` holds the 32-bit shift register. Byte lanes and halfword accesses are supported.
|
||||
- `SIODATA8` at `0x0400012a` holds the 8-bit shift register; its upper byte reads zero.
|
||||
Each transfer shifts only its selected data register. The other register retains its value.
|
||||
- `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 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.
|
||||
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.
|
||||
- `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.
|
||||
|
|
@ -23,7 +25,7 @@ Unsupported activity remains diagnostic rather than reporting a fabricated compl
|
|||
Nonzero writes return an explicit error. Joybus status and data-transfer side effects are not implemented.
|
||||
|
||||
GPIO means general-purpose input/output. UART means universal asynchronous receiver/transmitter.
|
||||
No external serial device is connected. Elapsed cycles alone do not change serial data or generate an IRQ.
|
||||
No external serial device is connected. Only an enabled internal serial clock can shift data or generate a completion IRQ.
|
||||
Configuration that hardware accepts in other modes can still be rejected by this intentionally limited subset.
|
||||
|
||||
## External-clock waiting
|
||||
|
|
@ -36,12 +38,63 @@ Repeated start writes do not complete the request. Software can cancel it by cle
|
|||
|
||||
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.
|
||||
Selecting internal clock while an unshifted request is pending starts a fresh nominal bit period.
|
||||
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.
|
||||
|
||||
## Internal clocks and completion
|
||||
|
||||
Normal mode shifts most-significant bit first. At each nominal sampling edge, the selected register shifts left and receives a one.
|
||||
The disconnected SI input is high. Completion therefore leaves `0xff` or `0xffffffff`, without inventing peer data.
|
||||
Reads between edges expose the partially shifted value. SO waveforms and normal-mode RCNT pin samples remain unmodeled.
|
||||
|
||||
At the nominal 16,777,216 Hz system clock:
|
||||
|
||||
| SIOCNT bit 1 | Cycles per bit | 8-bit transfer | 32-bit transfer |
|
||||
| --- | --- | --- | --- |
|
||||
| 0 | 64 | 512 cycles | 2,048 cycles |
|
||||
| 1 | 8 | 64 cycles | 256 cycles |
|
||||
|
||||
The first sample occurs one full bit period after activation. Selecting internal clock for an unshifted external request uses this same rule.
|
||||
A repeated start write with unchanged width/clock fields preserves the current phase and remaining bit count.
|
||||
A width/clock change before any bit has shifted starts a fresh period. Data writes before that first bit preserve the phase.
|
||||
Software cancellation clears progress but retains already shifted data.
|
||||
Whole-access writes merge control and data lanes before applying start/cancel behavior; byte writes remain separate accesses.
|
||||
|
||||
Completion clears start and latches IF bit 7 when SIOCNT bit 14 is enabled at the final edge.
|
||||
IE, IME, and CPSR.I gate wake-up or delivery, not request latching. Clearing IF acknowledges the request.
|
||||
A completed request does not reassert IF without another transfer.
|
||||
HALT continues internal shifting and bounds its idle batch at serial completion. STOP freezes the bit phase and remaining count.
|
||||
Only keypad wake is implemented for STOP; serial GPIO wake still requires its missing external-input model.
|
||||
|
||||
### Bus timing and validation
|
||||
|
||||
Serial state shares the timer/audio transaction during CPU instructions, IRQ entry, and DMA units.
|
||||
Each access observes all elapsed source/data cycles through its bus-completion phase.
|
||||
A start write excludes its preceding cycles. A load excludes its trailing internal cycle.
|
||||
IF reads and acknowledgements include serial completion through that access, alongside timer requests.
|
||||
Successful steps commit serial state and requests once. Failed steps discard speculative shifts, writes, and completion IRQs.
|
||||
The display/capture scheduler does not clock serial again after that commit.
|
||||
CPU-only stepping can change registers but does not advance serial clocks.
|
||||
|
||||
Block-store preflight simulates ordered access phases on temporary timing/device copies before committing any write.
|
||||
Validation can therefore accept reconfiguration when an earlier request completes before the write reaches the bus.
|
||||
The actual transfers then execute once from the original state. Other IF sources and DMA completion flags remain independent.
|
||||
|
||||
### Bounded behavior
|
||||
|
||||
After any bit has shifted, changes to width, clock selection/rate, or the selected data register remain diagnostic while start stays set.
|
||||
Selecting GPIO during an internally clocked request also remains diagnostic. Clear start before these operations.
|
||||
IRQ-enable and idle SO configuration writes remain supported without restarting progress.
|
||||
These limits also apply to BIOS services that write serial registers; cancel active transfers before requesting serial reset.
|
||||
Unverified live reconfiguration is not silently approximated.
|
||||
|
||||
The period arithmetic follows documented GBA rates. Activation phase, mid-transfer register visibility, and exact pin edges lack physical-hardware validation.
|
||||
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.
|
||||
|
||||
## BIOS reset
|
||||
|
||||
RegisterRamReset always clears the low halfword of SIODATA32, even without bit 5.
|
||||
|
|
@ -52,15 +105,16 @@ Clearing SIOCNT cancels a pending external-clock request. Unselected serial rese
|
|||
|
||||
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.
|
||||
RCNT selection bits share the high byte. Each high-byte write replaces the complete selection, so validation needs no retained-mode shadow.
|
||||
Static RCNT mode rejection uses the complete high byte. Live-transfer validation additionally uses staged serial state.
|
||||
Mode-gating tests cover every high-byte value, previous modes, low-byte preservation, CPU stores, DMA retries, and unchanged interrupt state.
|
||||
Inactive configuration bits do not wake HALT. RCNT word accesses still reject the unmapped padding at `0x04000136`.
|
||||
|
||||
## 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, 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 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 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.
|
||||
- [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.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
Otherwise it services one ready DMA data unit, keeping the CPU paused.
|
||||
If HALT is waiting and no DMA is ready, it advances device clocks to the next event without executing CPU code.
|
||||
Otherwise, it samples the IRQ line, including the CPU's interrupt mask, then enters IRQ mode or executes one instruction.
|
||||
Each successful step advances display, timer, and audio clocks by its nominal cost.
|
||||
Each successful step advances display, timer, audio, and enabled internal serial clocks by its nominal cost.
|
||||
`Machine::last_timing()` reports separate code, data, internal, and idle cycle totals for the last successful step.
|
||||
`StepTiming::idle_cycles` counts device-clock cycles during HALT; it does not count CPU work.
|
||||
IRQ entry is a separate step; the vector instruction runs on the following step.
|
||||
|
|
@ -15,7 +15,7 @@ Entry charges the discarded incoming-state PC+8/PC+4 fetch and the ARM vector pa
|
|||
DMA resume can make the discarded fetch non-sequential. Missing discarded bytes do not prevent IRQ entry.
|
||||
See [refill timing](../research/refill-fetch-timing.md) for history effects and remaining limits.
|
||||
A device event during a step can trigger IRQ entry once no DMA is ready and CPU masks allow delivery.
|
||||
Timer and sound accesses use ordered bus-completion phases. Other device writes still take effect before their bulk clock update.
|
||||
Timer, sound, and serial accesses use ordered bus-completion phases. Other device writes still take effect before their bulk clock update.
|
||||
`StepKind::Dma { channel }` identifies a DMA unit. `StepKind::HaltIdle` identifies one bounded HALT clock advance.
|
||||
`StepKind::StopIdle` identifies a stopped system with no clock progress.
|
||||
The other step kinds remain `Instruction` and `IrqEntry`.
|
||||
|
|
@ -31,15 +31,18 @@ Timer-start writes do not count preceding cycles. Timer-stop writes count throug
|
|||
Block transfers preserve distinct word phases; combined reload/control writes merge at one phase, with reload bytes first.
|
||||
|
||||
The transaction also owns timer IF bits. Reads see overflows through the current access; acknowledgements clear earlier timer requests.
|
||||
A later internal cycle can raise an acknowledged timer request again. Non-timer IF bits retain their existing behavior.
|
||||
A later internal cycle can raise an acknowledged timer request again.
|
||||
The same transaction owns serial IF bit 7; serial completion and acknowledgement follow the same access boundaries.
|
||||
Other IF sources retain their existing behavior.
|
||||
IRQ delivery still waits until the next machine step. A committed timer request can wake HALT, but not STOP.
|
||||
|
||||
Successful steps commit timers, the shared divider phase, timer IF bits, and audio state.
|
||||
Failed steps discard staged counters, divider progress, timer/audio writes, FIFO consumption, and requests.
|
||||
Successful steps commit timers, the shared divider phase, audio/serial state, and timer/serial IF bits.
|
||||
Failed steps discard staged counters, divider progress, device writes, FIFO consumption, serial shifts, and requests.
|
||||
Display and other device clocks then advance once, without advancing timers again.
|
||||
Display and remaining devices still use the bulk scheduler. Mid-instruction display events, general bus arbitration, and IRQ synchronization delays remain unmodeled.
|
||||
[Direct Sound](audio.md) consumes selected timer overflows in the timer transaction; sound DMA requests commit at step boundaries.
|
||||
The same transaction advances both PSG pulse oscillators, the noise counter, and their shared 512 Hz sequencer independently of the general-purpose timers.
|
||||
It also advances [normal serial transfers](serial.md) with nominal internal clocks. External-clock requests cannot progress without a clock source.
|
||||
Host clock advances and HALT idle batches retain ordinary bulk timer advancement; STOP idle does not advance timers.
|
||||
|
||||
The unchanged [prefetch cancellation probe](../research/prefetch-cancellation.md) now matches both published interval totals and actual timer samples.
|
||||
|
|
@ -95,7 +98,8 @@ See [prescaler evidence and original tests](../research/timer-prescaler.md).
|
|||
Hardware startup and register-write delays are still not modeled. Writes retain the immediate bus-completion policy.
|
||||
The shared-phase tests validate this bounded model, not absolute enable/reload edges on hardware.
|
||||
Timers 0 and 1 can clock Direct Sound playback and request FIFO DMA independently of timer IRQ enable.
|
||||
Interrupt sources other than timers, display events, DMA completion, and keypad input are not implemented.
|
||||
Implemented interrupt sources are timers, display events, DMA completion, keypad input, and normal serial completion.
|
||||
Other serial modes and external serial interrupts remain unimplemented.
|
||||
|
||||
`--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`.
|
||||
|
|
@ -173,7 +177,7 @@ Wake-up does not acknowledge IF. Clearing IF after wake-up does not put the CPU
|
|||
On the next machine step, ready DMA still takes priority.
|
||||
The CPU then enters an unmasked IRQ handler or resumes the next instruction.
|
||||
|
||||
Each `HaltIdle` step advances to the earliest display edge or independently clocked timer overflow.
|
||||
Each `HaltIdle` step advances to the earliest display edge, independently clocked timer overflow, or internal serial completion.
|
||||
Display edges include every HBlank entry and scanline start. Cascaded timers receive pulses at their predecessor's overflow.
|
||||
These bounds prevent idle advances from skipping DMA triggers or wake-up events.
|
||||
They also keep frame execution bounded when no interrupt can wake the CPU.
|
||||
|
|
@ -209,7 +213,7 @@ The same selected-button OR/AND logic applies, including the empty-mask behavior
|
|||
IME and CPSR.I do not gate wake-up in this functional model.
|
||||
A matching condition already present at entry prevents a sustained stop.
|
||||
Stale IF flags alone cannot wake STOP, including an old keypad request.
|
||||
Timer, display, and DMA requests cannot wake STOP.
|
||||
Timer, display, DMA, and internal serial requests cannot wake STOP.
|
||||
|
||||
An input sample supplied while stopped updates KEYINPUT and the wake condition without setting IF.
|
||||
It does not consume the normal running-state keypad polling history.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue