CORDIC Rotator

Motion & Curves

sin, cos and atan computed on a Super Nintendo with CORDICshift-and-add only, no multiply and no divide. A rotating hand sweeps a ring of CORDIC-computed unit vectors, and a live atan2 reads its angle straight back. 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 — the hand rotates automatically.

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

What it is

CORDIC (COordinate Rotation DIgital Computer) rotates a vector toward a target angle using nothing but shifts, adds and a small table of pre-computed angles — the classic way to do trigonometry on hardware with no multiplier. Each iteration rotates by ±atan(2⁻ⁱ), which is just x ± (y >> i); after 15 unrolled steps the vector has converged and its coordinates are the cosine and sine of the angle:

x = 1/An ; y = 0 ; z = angle           // rotation mode (sin/cos)
for i in 0..15:
    if z >= 0: x -= y>>i ; y += x>>i ; z -= atan[i]
    else:      x += y>>i ; y -= x>>i ; z += atan[i]
// (cos, sin) = (x, y)            — no × and no ÷ anywhere

The hand sweeps a full circle by folding the angle into one quadrant (sign-and-swap, still no multiply), and the bottom HUD runs the vectoring form of the same engine — atan2 — to recover the hand's angle from its (cos, sin) and prints it back (ANGLE 137 / ATAN2 137 OK).

Compiler stress-test #12 — the multiply-free one

Every other demo in this gallery leans on the 32-bit math libcalls (__mulsi3, __udivmodsi4). This one is the deliberate opposite: its gate is inverted — it asserts those libcalls are absent. That's a genuinely different shape of code for the compiler to get right.

ItemWhat it exercises
No __mulsi3CORDIC is shift-and-add only — there is NO multiply in the sin/cos/atan core. The disasm gate asserts ZERO __mulsi3 (every other demo asserts its presence)
No __divsi3No divide either: each microrotation is x ± (y >> i), a constant-shift add. Zero __divsi3 / __udivmodsi4 / variable-shift libcalls in the whole gate object
Constant-folded tablesThe 15 unrolled rotations have compile-time-constant indices, so each atan(2⁻ⁱ) table entry folds into an immediate adc/sbc operand — no rodata table even appears
rep/sepNative 16-bit accumulator brackets under +mos-a16; 252 occurrences across the unrolled rotation + vectoring sweeps (the values route through the Imag16 zero-page pair as int16)
Q2.14 fixed-pointEvery angle/value is a raw int16 (value = raw / 16384), kept inside int16 the whole way so host (32-bit int) and target (16-bit int) compute bit-identical results

The CORDIC core is a portable C header (examples/65816/cordic16.h) linked into the SNES ROM and a host oracle alike. The gate asserts corpus_result — a 16-bit rotate-XOR CRC over a full-circle sweep of both the rotation (sin/cos) and vectoring (atan2) paths — is identical on host and target.

Written in C with the llvm-mos 65816 toolchain. Hit Verify fidelity to reproduce the build gate's WRAM assert (gate CRC 0x4D41) live in this tab — the same hash the host oracle and the cycle-accurate bsnes-jg core agree on. The disasm gate proves the shape: __mulsi3 = __divsi3 = 0, rep/sep = 252, adc/sbc = 143 — shift-add only, no arithmetic libcalls.