Duff Dissolve

Algorithms & Data

One image dissolving into the next on a Super Nintendo, each tile copied by the notorious Duff's device — a switch whose case labels land in the middle of a loop body. The switch and the loop back-edge interlace into irreducible control flow — a branch tangle a structurizer can't untangle. 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 — one image dissolves into the next in scattered bursts.

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

What it is

Duff's device is a famous trick for unrolling a copy loop: you handle the remainder by jumping into the middle of the unrolled body. The switch picks the entry point and the loop carries on from there — the case labels sit inside the loop:

switch (count % 8) {
    case 0: do { *to++ = *from++;   // ← the loop body...
    case 7:      *to++ = *from++;
    case 6:      *to++ = *from++;
    ...                             //   ...and the switch's
    case 1:      *to++ = *from++;   //      cases land INSIDE it
           } while (--n > 0);
}

Because the switch jumps into the loop, the two overlap in a way that can't be rewritten as clean nested blocks — irreducible control flow. Here it copies image tiles in a scattered order, dissolving one picture into the next. The whole tangle stays bit-exact across every codegen mode.

Compiler stress-test

ItemWhat it exercises
switch into a loopThe case labels of the switch fall in the middle of a do/while loop body. On entry the switch jumps straight to the right case, then the loop back-edge carries execution around — the two interlace.
irreducible CFGThat interlacing is control flow that cannot be rewritten as clean nested if/while blocks — an irreducible graph. Compilers that rely on a structurizer choke on it; a direct branch lowering must handle the tangle. No other demo in the battery exercises it.
branch meshOn the 65816 the tangle lowers to a dense mesh of branches — 19 jmp targets and 19 bne back-edges in the corpus slice — with zero arithmetic libcalls (the /8 and %8 fold to shift and mask). The differential proves every branch resolves identically across default-8-bit, +mos-a16 and +mos-xy16.
dissolveThe device drives the visuals: each frame reveals three more tiles in a scattered (bit-reversed) order, each tile's bytes copied by the unrolled loop — one image dissolving into the next, then the pattern flips (diagonal bands ⇄ concentric rings).

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 0x5531 — a fold of Duff-copied buffers of every length 1–40) live in this tab. No far pointers — the same source passes every way: host == default == +mos-a16 == +mos-xy16 == bsnes-jg, -verify clean.