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).
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
| Item | What it exercises |
|---|---|
| packed fields | A 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 bytes | Two 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 + insert | Writing 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-exact | Pure 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.