Skip to content

SWI 0x16 — Diff8bitUnFilterWram

  • Entry: 0x00001333 (THUMB, real entry 0x00001332)
  • 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: reconstructs a byte stream from a first-value-plus-deltas encoding by running-sum accumulation. Uses 8-bit writes, so it is for byte-writable destinations (use SWI 0x17 for VRAM).

Parameters

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

Returns

No return value.

Clobbered registers

r0–r3. r4 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

The header word is read; bits 8–31 are the output size in bytes. Byte 0 (which in GBATEK nominally carries a type=8 nibble and a data-unit-size nibble) is not read at all — the 8-bit-vs-16-bit choice is made purely by which SWI you call. The shared header/region check runs; on failure nothing is written.

Reconstruction: - The first source byte is copied verbatim to the output and kept as the running sum. - Each subsequent source byte is a signed 8-bit delta; the running sum is sum = (sum + delta) truncated to 8 bits and stored. This repeats until the output-size counter is exhausted.

Edge cases & known bugs

  • Decompressed size 0: shared header check returns "skip"; nothing written.
  • Size 1: the first byte is written, then the size test ends the loop — exactly one byte out. Odd sizes are fully supported (unlike the Vram variant).
  • Type/data-size nibble not enforced: byte 0 is ignored; calling this SWI on 16-bit-filtered data would mis-reconstruct silently.
  • Source-region protection: source in 0x00000000–0x01FFFFFF is refused.
  • Sums wrap mod 256 (8-bit), matching how the filter was applied.

  • Hardware-confirmed (2026-07-08 anomaly tests, results/cycles_phase3_anomaly.csv): odd declared size 255 writes exactly 255 bytes; a header with type nibble 0x0 (instead of 0x8) unfilters identically.

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): 4437 cycles. Header with size 0: 87 cycles.

Open questions (need hardware verification)

  • ~~Inner-loop timing~~ — measured, see Cycle count.

GBATEK cross-reference

Matches GBATEK Diff8bit unfilter (running 8-bit sum). Adds: header byte 0 completely ignored (unit size implied by SWI number, not validated), and the source-region gate.