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.
4.1 KiB
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.