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).

loading core…

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

ItemWhat it exercises
widening multiply-highA 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 multiplyThe 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 samplingEach 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 modesThe 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.