Newton Floor
Rendering & Graphics
A checkerboard floor rushing toward the horizon on a Super Nintendo — a chip with
no divide instruction. The 1/z depth that makes the perspective work is
computed by Newton-Raphson
refinement: a convergent loop that uses only multiplies. 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 — the checkerboard floor scrolls toward the horizon.
Click the screen to focus, then watch. Tab away and it pauses.
What it is
Perspective needs division: an object at depth z shrinks by 1/z. But
the 65816 can't divide — so this computes the reciprocal the way a hardware divider does
internally, by iterative refinement:
x = seed(m); // rough first guess
repeat 4 times:
x = x * (2 - m * x); // each pass DOUBLES the correct digits
// x now equals 1/m — computed with only multiplies
Start with a rough guess, then each pass of x = x*(2 - m*x) doubles the accuracy.
Four multiplies-only passes give a full 16-bit reciprocal — which becomes the 1/z
depth of a checkerboard floor. It stays bit-exact across every codegen mode.
Compiler stress-test
| Item | What it exercises |
|---|---|
| no divide | The 65816 has no divide instruction at all. This computes 1/z the way hardware dividers do internally — Newton-Raphson refinement, which uses only multiplies and a subtract. Zero divide library calls appear in the compiled code. |
| quadratic convergence | Each iteration x = x*(2 - m*x) roughly doubles the number of correct bits, so four passes nail a 16-bit reciprocal from a crude linear seed. It is the canonical fixed-point refinement loop. |
| fixed-point | Everything is 32-bit Q15/Q16 integer arithmetic — the products are sized to fit 32 bits exactly (no 64-bit, no float), so the result is bit-identical on the host and on all three codegen modes. |
| perspective floor | The reciprocal gives the 1/z depth mapping for a scrolling checkerboard floor: near rows spread wide, far rows compress toward the horizon. host == default == +mos-a16 == +mos-xy16 == bsnes-jg. |
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 0x044A — a fold of the Newton reciprocal over a sweep
of inputs) live in this tab. No far pointers — the same source passes every way: host == default
== +mos-a16 == +mos-xy16 == bsnes-jg, -verify clean.