Skip to content

SWI 0x17 — Diff8bitUnFilterVram

  • Entry: 0x0000135D (THUMB, real entry 0x0000135C)
  • Status: verified (hardware-checked 2026-07-08: cycle counts measured and output round-trip-verified on real GBA via the worker ROM)

Summary

Reverses an 8-bit difference filter into a 16-bit-only destination. It computes the same running-sum reconstruction as SWI 0x16 but buffers two reconstructed bytes and writes them as one halfword.

Parameters

Reg In Meaning
r0 ptr Source address pointing at the 4-byte header.
r1 ptr Destination address (halfword-aligned, halfword-writable).

Returns

No return value.

Clobbered registers

r0–r3. r4–r7 saved/restored.

Hardware audit (2026-07-08, canary r4–r12 + CPSR snapshot): caller-visible clobbers: r0/r1 advanced past stream/output; r3 = 0x170 leftover. 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

Header handling as in SWI 0x16 (size in bits 8–31; byte 0 not inspected). The first source byte becomes the running sum and is placed in the low byte of the 16-bit accumulator. Each subsequent delta is added (mod 256) to the running sum; the result is placed into the accumulator's low then high slot alternately. When a pair is complete the halfword is stored and the accumulator cleared, keeping all writes 16-bit.

Edge cases & known bugs

  • Decompressed size 0: shared header check returns "skip"; nothing written.
  • Odd size: because stores occur only on completed pairs, an odd final reconstructed byte is left pending in the accumulator and is never written. Callers should keep the output size even (typical for VRAM assets).
  • Type/data-size nibble not enforced (byte 0 ignored); the 8-bit vs 16-bit unit is chosen by SWI number, not validated against the header.
  • Source-region protection: source in 0x00000000–0x01FFFFFF is refused.
  • Running sum wraps mod 256.

  • Odd-size drop hardware-confirmed (2026-07-08 anomaly tests, results/cycles_phase3_anomaly.csv): declared size 255 wrote bytes 0–253; byte 254 was never written (sentinel intact).

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).

256-byte output (EWRAM): 5847 cycles (≈1.3× the Wram variant).

Open questions (need hardware verification)

  • Whether shipped assets ever use an odd size here (would drop the last byte).

GBATEK cross-reference

Matches GBATEK Diff8bit unfilter. Adds the halfword-buffering description and the dropped-final-byte behaviour on odd sizes, plus the source-region gate.