Rotozoom
Rendering & Graphics
The demoscene classic on a Super Nintendo: a texture that spins and zooms at once. Each
cell rotates and scales its screen position with fixed-point math, then samples a checker/grid
texture at the transformed coordinate. The kernel is a
Q16.16 multiply that keeps the
middle of a 64-bit product — a widening multiply-high. Runs on its own; no joypad needed.
Written in C and compiled with the llvm-mos-based
65816 toolchain (+mos-a16, 16-bit accumulator mode).
Self-running demo — the texture spins and breathes on its own.
Click the screen to focus, then watch. Tab away and it pauses.
What it is
A rotozoom rotates and scales an image every frame. Done per pixel it needs a fixed-point multiply that forms a wide product and keeps the top part:
// Q16.16 fixed-point multiply — keep the MIDDLE 32 of a 64-bit product q16mul(a, b) = (int64_t)a * b >> 16; // per cell: rotate + scale the screen coordinate, then sample u = q16mul(dx, cos*zoom) - q16mul(dy, sin*zoom) + u0; v = q16mul(dx, sin*zoom) + q16mul(dy, cos*zoom) + v0; colour = texture[u & 63][v & 63];
That "keep the high part of a wide product" is a specific thing compilers know how to do. On a chip with no multiply instruction at all, it falls back to the multiply routine — and measuring exactly what the compiler emits, rather than assuming, is the whole exercise. The picture stays bit-exact across every codegen mode.
Compiler stress-test
| Item | What it exercises |
|---|---|
| widening multiply-high | A Q16.16 fixed-point multiply forms a 64-bit product of two 32-bit numbers and keeps the middle 32 bits — the "high part of a wide product" the compiler models with a dedicated opcode. It expands to extend → multiply → shift → truncate. |
| soft multiply | The 65816 has no multiply instruction, so there is no narrower high-multiply either: the widening lowering falls back to the 64-bit multiply routine (__muldi3), with the sine/cosine scaling done by the 32-bit one (__mulsi3). Measuring this — rather than assuming a clever mul-high — is the point. |
| affine sampling | Each cell rotates and scales its screen position, then reads a procedural checker/grid texture at the transformed coordinate. Spinning and breathing the transform gives the classic demoscene "rotozoomer". |
| exact across modes | The intermediate is an explicit 64-bit value, identical on the host and the 65816, and a signed right shift is arithmetic on both compilers — so the picture is bit-exact across default, +mos-a16 and +mos-xy16. |
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 CRC 0x391B — a fold of sampled texels and raw Q16.16
multiply-highs; the gate is multiply-heavy, so give it a few seconds) live in this tab. No far
pointers — the same source passes every way: host == default == +mos-a16 ==
+mos-xy16 == bsnes-jg, -verify clean.