Track a separate IWRAM latch with known lanes and transactional updates. Sequential Thumb prefetches and IWRAM byte/halfword/word reads and writes drive only addressed lanes. Other regions and host inspection do not replace the latch. Failed instructions discard staged changes. Keep cold, refill, discontinuous-entry, IRQ, and DMA-transition history conservative. Share Thumb refill classification with nominal timing, including PC writes to fallthrough. Successful DMA and accepted machine IRQs invalidate history; failed DMA preserves it. Document source evidence, bounded scope, and remaining hardware-validation limits. Add original lane, alignment, mirror/wrap, signed/unaligned-load, mode, block-transfer, rollback, isolation, control-flow, IRQ/DMA, and nominal-cost regressions. Darwin arm64 validation: 905 workspace tests and 836 core/demo tests per debug/release profile; 39 preparation tests; native ROM windows in both profiles; ten graphics/window smoke modes; fmt, clippy, and rustdoc. Public ARM, Thumb, memory, and BIOS reports remain identical to prior passing reports and between profiles.
59 lines
4.1 KiB
Markdown
59 lines
4.1 KiB
Markdown
# Direct memory access (DMA)
|
||
|
||
Four DMA channels occupy `0x040000b0..0x040000df`. Each channel has a 12-byte register block:
|
||
|
||
| Offset | Register | Behavior |
|
||
| --- | --- | --- |
|
||
| `+0` | SAD | Write-only initial source address |
|
||
| `+4` | DAD | Write-only initial destination address |
|
||
| `+8` | CNT_L | Write-only halfword/word count |
|
||
| `+10` | CNT_H | Read/write address controls, repeat, width, timing, IRQ, and enable |
|
||
|
||
Byte, halfword, and word register writes are supported. A combined count/control write sets the count before enabling DMA.
|
||
Control masks are `0xf7e0` for DMA0–2 and `0xffe0` for DMA3.
|
||
Source addresses use 27 bits on DMA0 and 28 bits on DMA1–3.
|
||
Destination addresses use 27 bits on DMA0–2 and 28 bits on DMA3.
|
||
Initial addresses align down to the selected halfword or word width.
|
||
DMA0–2 use 14-bit counts; DMA3 uses 16-bit counts. Zero means 16,384 or 65,536 data units, respectively.
|
||
Write-only register reads return zero as a placeholder, not hardware open-bus behavior.
|
||
|
||
A rising enable bit copies the programmed addresses and count into internal transfer state.
|
||
Register writes alone do not move data. `Machine::step()` services one halfword or word at a time.
|
||
Source modes are increment, decrement, or fixed. Destination modes also include increment/reload.
|
||
Game Pak source addresses increment regardless of the selected source mode.
|
||
Writes to programmed addresses/count do not alter an active block's internal pointers or remaining count.
|
||
Disable the channel before changing its width, address modes, or start timing; live reconfiguration is not hardware-validated.
|
||
|
||
Supported triggers:
|
||
|
||
- Immediate: ready after the enabling instruction; repeat does not keep it running.
|
||
- VBlank: ready on entry to line 160.
|
||
- HBlank: ready at HBlank entry on visible lines 0–159 only.
|
||
|
||
Blanking triggers do not depend on DISPSTAT IRQ enables or forced blank.
|
||
Enabling during an existing blank period waits for the next edge.
|
||
A busy channel ignores additional edges. Pending requests are not a queue.
|
||
On repeated blanking transfers, completion reloads the programmed count and optionally the destination.
|
||
The source continues from its current position. Non-repeated completion clears the enable bit.
|
||
Clearing enable manually cancels a waiting or active transfer.
|
||
|
||
DMA0 has highest priority, followed by DMA1, DMA2, and DMA3.
|
||
A higher-priority request can interrupt a lower-priority transfer between data units.
|
||
While the system clock runs, the CPU remains paused while any channel is ready; display and timer clocks continue.
|
||
STOP freezes DMA before transfer selection, including diagnostics, and retains pending transfer state until wake-up.
|
||
Completion with local IRQ enable latches IF bits 8–11, independently of IE, IME, and CPSR.I.
|
||
CPU delivery waits until no DMA is ready. IRQ entry does not acknowledge IF.
|
||
|
||
Timing uses independent source and destination bus costs, including WAITCNT and 128 KiB ROM boundaries.
|
||
The first unit uses non-sequential accesses plus two internal cycles. Later units use sequential accesses.
|
||
Each step reports zero code cycles. Overlapping transfers read each unit after the preceding write; they are not bulk host copies.
|
||
Startup scheduling delays, channel-resumption costs, CPU fetch-state effects, and display-bus contention remain unmodeled.
|
||
|
||
Special timing modes (sound FIFO/video capture), Game Pak DRQ, and prohibited source mode 3 return `DmaError::UnsupportedControl`.
|
||
DMA reads below work RAM, including BIOS reads, return `DmaError::UnsupportedSource` rather than exposing BIOS bytes.
|
||
DMA writes to DMA registers return `DmaError::RegisterDestination`; self-modifying transfers are not supported.
|
||
Other accesses use the existing memory map, alignment checks, mirrors, and I/O write rules.
|
||
Unmapped memory and cartridge writes remain diagnostics, not hardware open-bus/latch behavior.
|
||
A failed unit changes no memory, device state, or clock. Earlier units remain committed; the failed unit remains pending.
|
||
Successful units invalidate bounded sequential Thumb IWRAM history because DMA-to-CPU latch ordering is not modeled.
|
||
Failed units preserve that history. No DMA value is substituted for a CPU open-bus read.
|