Bitfields

Ciphers & Bit Tricks

A 65816 instruction decoder on a Super Nintendo, packing eight fields into one 32-bit word — and two of them straddle byte boundaries. Reading or writing a field that crosses a byte edge needs multi-byte shift and mask, the kind of bit-twiddling a compiler has to get exactly right. The decoded fields colour a scrolling map. Runs automatically; no joypad needed. Written in C and compiled with the llvm-mos-based 65816 toolchain (+mos-a16, 16-bit accumulator mode).

loading core…

Self-running demo — decoded instruction fields colour a scrolling map.

Click the screen to focus, then watch. Tab away and it pauses.

What it is

Disassemblers store one row per opcode: what it does, how it's addressed, how long it is, how many cycles it takes. To keep the table tiny, all of that is bit-packed into a single 32-bit word:

opcode:8  mode:3  len:2  group:5  cycles:4  flags:7  rmw:1
|--------byte 0--------|-----byte 1-----|----byte 2----|-byte3-|
                              ^group crosses bit 16   ^flags crosses bit 24

The group and flags fields don't fall on byte boundaries, so pulling them out — or writing them without clobbering the neighbours — takes shifting and masking across two bytes. Here the decoded fields colour a scrolling grid. It stays bit-exact across every codegen mode.

Compiler stress-test

ItemWhat it exercises
packed fieldsA 65816 instruction descriptor squeezes eight fields into one 32-bit word: opcode, addressing mode, length, group, cycle count, flags, read-modify-write. Bit-packing is how real disassembler tables stay small.
straddling bytesTwo of the fields don't line up with byte boundaries: group sits across bit 16, flags across bit 24. Reading or writing them needs shifting and masking across two bytes — the multi-byte extract/insert the compiler must get exactly right.
extract + insertWriting a straddling field is a read-modify-write that must not disturb its neighbours; reading it is a shift-and-mask across bytes. The gate folds every field back out, so a cross-byte corruption would show up immediately.
bit-exactPure shift, and, or — no multiply, no divide. The gate decodes 128 synthetic opcodes and folds every field; host == default == +mos-a16 == +mos-xy16 == bsnes-jg, byte for byte.

Written in C with the llvm-mos 65816 toolchain and verified against bsnes-jg (and MAME where the SPC700 IPL is present). Hit Verify fidelity to reproduce the build gate's WRAM assert (gate hash 0x31D7 — a fold of 128 decoded instruction words) live in this tab. No far pointers — the same source passes every way: host == default == +mos-a16 == +mos-xy16 == bsnes-jg, -verify clean.