SWI 0x0C — CpuFastSet¶
- Entry:
0x00000BC4(ARM) - Status: verified (hardware-checked 2026-07-08: cycle counts and return values measured on real GBA via the worker ROM)
Summary¶
High-speed memory copy or fill in fixed blocks of eight 32-bit words
(32 bytes) using LDMIA/STMIA. Only 32-bit units are supported. Because it
always moves whole 8-word blocks, the length should be a multiple of 8 words;
non-multiples are rounded up (see edge cases).
Parameters¶
| Reg | In | Meaning |
|---|---|---|
| r0 | u32 | Source address (word aligned). For fill, points to the fill word. |
| r1 | u32 | Destination address (word aligned). |
| r2 | u32 | Control word (see below). |
Control word (r2) bit layout¶
| Bits | Meaning |
|---|---|
| 0–20 | Word count. |
| 24 | 0 = copy (source advances), 1 = fill (source word fixed). |
Unit size is always 32-bit; there is no datasize bit.
Returns¶
None. Memory at r1 is modified.
Clobbered registers¶
r2–r9, sl (r10), ip (r12) used internally; r4–r9/sl restored from the pushed frame. r0/r1 advance during copy. r2, r3, ip destroyed.
Hardware audit (2026-07-08, canary r4–r12 + CPSR snapshot): caller-visible clobbers: r0/r1 advanced past the source/destination end; r2 (count) preserved; r3 garbage (0x0F080000 observed). r2, r4–r12, r13, and CPSR (flags and mode) came back bit-identical on every tested path. r11/r12 are explained by the SWI dispatcher (it pushes {r11, r12, lr} — see 10_irq_boot_and_iwram.md) and CPSR by the SPSR restore on return; r2 and r4–r10 must be preserved or restored by the routine itself — where a static note above claims r2 is destroyed, the hardware disagrees at the caller level. Raw data: results/clobber_audit_pass2.csv.
Algorithm¶
- Compute byte length =
(count bits 0–20) × 4. - Call the shared guard routine at
0x00000BA4(same as CpuSet): zero-length aborts, and a source below0x02000000is rejected. - Compute end pointer
sl = dest + bytelen. - Decode bit 24:
- Fill: load one source word into r2, copy it into r3–r9 (eight identical
registers), then loop
STMIA r1!, {r2..r9}whiler1 < sl. - Copy: loop
LDMIA r0!, {r2..r9}thenSTMIA r1!, {r2..r9}whiler1 < sl.
Each iteration transfers exactly 8 words (32 bytes).
Edge cases & known bugs¶
- Count not a multiple of 8: the loop condition is only
r1 < end. Since each pass writes a full 8-word block, the routine keeps writing complete blocks until the destination pointer reaches or passesend. It therefore rounds the count up to the next multiple of 8 words, overwriting up to 7 words past the requested region (and, in copy mode, reading up to 7 words past the source end). Callers must size buffers accordingly. Hardware-verified: a copy with count=12 wrote exactly 16 words; sentinel values beyond word 16 were untouched. - Count 0: aborted by the guard, nothing written.
- Source below 0x02000000: aborted by the guard (BIOS-region protection).
-
Alignment: addresses must be word-aligned; misalignment is force-aligned by the CPU (LDM/STM ignore the low two address bits).
-
BIOS-source guard hardware-confirmed (2026-07-08 anomaly tests,
results/cycles_phase3_anomaly.csv): src=0x100returns in 86 cycles with the destination untouched.
Cycle count¶
Hardware-measured net CPU cycles (worker-ROM harness, TM0/TM1 cascade at F/1,
13-cycle baseline subtracted; identical across 3 runs — see
02_hardware_verification_checklist.md § Measurement setup).
| Operation | Buffers | Cycles |
|---|---|---|
| copy, n=8 | EWRAM→EWRAM | 196 |
| copy, n=64 | EWRAM→EWRAM | 917 |
| copy, n=256 | EWRAM→EWRAM | 3389 |
| fill, n=64 | EWRAM | 532 |
| copy, n=64 | IWRAM→IWRAM | 277 |
| copy, n=12 (not a multiple of 8) | EWRAM→EWRAM | 299 |
EWRAM copy slope ≈12.9 cycles/word (≈103 per 8-word LDM/STM block); the same 64-word copy in IWRAM costs 277. The n=12 case wrote exactly 16 words (readback-verified — see Edge cases).
Open questions (need hardware verification)¶
- Confirm the round-up overshoot on real hardware for a non-multiple-of-8 count.
- Exact semantics of the shared
0x0E000000source-region guard.
GBATEK cross-reference¶
Agrees with GBATEK (8-word blocks, bit 24 fill, 32-bit only). Clarifies the documented "must be multiple of 8 words" constraint: a non-multiple is rounded up and overshoots, it is not truncated.