Soft-Float Mandelbrot

Fractals

The Mandelbrot setz² + c iterated to escape — computed live on a Super Nintendo in IEEE-754 single-precision float. The 65816 has no floating-point unit, so every multiply, add, subtract, divide and compare is a software-float libcall — hundreds of instructions per pixel. That is the whole point: the chunky image grinds in row by row because each fat pixel really is a flurry of __mulsf3/__addsf3. And it is bit-for-bit identical to host x86 single precision. 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 set grinds in and Mode 7 zooms it automatically. (Boot takes several seconds: the gate and the first frame are software floating point.)

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

What it is

The Mandelbrot set is the escape-time picture of iterating z ← z² + c from z₀ = 0, with c the pixel coordinate, colouring each point by how fast it flies to infinity. Every other demo in this battery does its arithmetic in fixed-point integer; this one does it in IEEE-754 single-precision float — so on the FPU-less 65816 the inner loop is nothing but soft-float libcalls:

z = (zr, zi) = 0.0f         // IEEE-754 single precision ;  c = pixel coordinate
for n in 0..maxiter:
    zr2 = zr*zr ;  zi2 = zi*zi            // two __mulsf3
    if zr2 + zi2 > 4.0f: break            // __addsf3 + __gtsf2 — escaped
    zi = (zr*zi) + (zr*zi) + ci           // __mulsf3 + __addsf3
    zr =  zr2 - zi2        + cr           // __subsf3 + __addsf3
// escape count n = pixel colour ;  EVERY op above is a soft-float call

Each pixel grinds that loop and is far-stored into a high-WRAM buffer at $7E2000 — memory only reachable through 24-bit addressing, the #320 far-pointer path (sta [dp]) — then far-loaded back into Mode 7 character VRAM. Because a full-resolution soft-float recompute would take minutes, a chunky 16×14 grid is ground a row at a time and painted in progressively, then the affine matrix spins and zoom-breathes it: the grind is the proof, the hardware is the motion.

Compiler stress-test #21 — IEEE-754 soft-float

This is the first Round 2 demo — each Round-2 entry targets a codegen corner the first twenty never execute. Here it is the entire soft-float library: with no FPU, every floating-point operation lowers to a compiler-rt libcall, a code path no fixed-point demo ever runs.

ItemWhat it exercises
No FPU — every op a libcallThe 65816 has no floating-point hardware, so each +, −, ×, ÷ and compare in the loop is a compiler-rt soft-float call: __mulsf3 (z·z, zr·zi), __addsf3/__subsf3 (the recurrence), __divsf3 (the window step), __gtsf2 (the |z|²>4 escape test), __floatsisf (pixel index → float). That whole library is otherwise untouched by the demo battery
Bit-exact differentialIEEE-754 single precision is fully specified — +, −, ×, ÷ and the comparisons are all correctly rounded — so the 65816 soft-float must equal host x86 single precision BIT FOR BIT. Verified: host == default-8bit == +mos-a16 == +mos-xy16 == gate CRC 0x4169
FMA forbidden by constructionThe one thing that could diverge host from target is fused multiply-add contraction (a·b+c fused on the host but two separate libcalls on the target). Every arithmetic op is its own statement, so no expression ever holds an a·b±c pattern to fuse — and baseline cc -O2 has no FMA instruction without -march anyway
Far high-WRAM framebufferThe 64×56 escape image lives at $7E2000 — high WRAM reachable only by 24-bit addressing, the #320 far-store/load path (sta [dp] / lda [dp]). a16-only. A 16×14 coarse grid is 4×-upscaled into it; each fat pixel is hundreds of soft-float instructions
Grind is the proofA full-resolution soft-float recompute would take minutes, so the set is ground a coarse row at a time and painted in progressively — the visible top-to-bottom crawl IS the demonstration that real software floating point is running on the console; Mode 7 then spins and zoom-breathes it

The soft-float kernel is a portable C header (examples/65816/mandel-float.h) linked into the SNES ROM, a host oracle, and the corpus differential slice alike. The gate folds two zoom windows plus a bit-exact orbit witness into corpus_result. Because single precision is fully specified, that 16-bit hash must be identical on host x86 and on the console — and it is, across every target codegen mode (default 8-bit, +mos-a16, +mos-xy16) — which holds only because the source forbids FMA contraction by giving every operation its own statement.

Written in C with the llvm-mos 65816 toolchain. Hit Verify fidelity to reproduce the build gate's WRAM assert (gate CRC 0x4169) live in this tab — the same hash the host oracle (x86 single precision) and the cycle-accurate bsnes-jg core agree on, bit for bit. The disasm gate proves the shape: __mulsf3 = 8, __add/subsf3 = 12, rep/sep = 35 — IEEE-754 soft-float in native-16 mode.