Multi-Base Clock
Big Numbers
One number, counting up, shown in four bases at
once — decimal, dozenal (base 12), hexadecimal and sexagesimal (base 60, like clock minutes and
seconds) — plus a 64-bit odometer. Turning a number into digits of a given base needs the quotient
and the remainder at each step, which the standard library's div() hands back
together as a little struct. 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 same instant ticks in four bases at once.
Click the screen to focus, then watch. Tab away and it pauses.
What it is
To write a number in another base you repeatedly divide by the base and keep the remainders — those are the digits. The standard library gives you both at once:
div_t d = div(n, base); // quotient AND remainder, in ONE call digit = d.rem; // ...returned together as a two-field struct n = d.quot; // repeat to peel off the next digit
div() returns a div_t — a struct holding the quotient and the remainder —
by value. Returning a struct from a function is a distinct calling-convention path, and underneath
it drives the compiler's divide-with-remainder. The four read-outs all show the same instant. It
stays bit-exact across every codegen mode.
Compiler stress-test
| Item | What it exercises |
|---|---|
| div_t by value | The standard library div() returns a small struct — quotient and remainder together — by value. Returning an aggregate from a function is its own calling-convention path, separate from returning a single number, and this is the first demo to exercise it. |
| divide + remainder | Converting a number to another base needs both the quotient and the remainder at each step. div() computes them once; underneath, that is the compiler's divide-with-remainder routine, reading the remainder back from a scratch slot on the stack. |
| lldiv for 64-bit | The odometer at the bottom is a 64-bit number, split with lldiv() — the long-long version, which returns a bigger struct and drives the 64-bit divide-with-remainder. |
| width discipline | div() operates on int, which is 16-bit on the 65816 but 32-bit on the host — so the four-base counter is kept under 32768 to stay identical on both. lldiv()'s long long is 64-bit everywhere, so the odometer is always safe. |
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 0x371A — a fold of base conversions in four bases plus a
64-bit odometer, each cross-checked by reconstructing the value) live in this tab. No far pointers —
the same source passes every way: host == default == +mos-a16 ==
+mos-xy16 == bsnes-jg, -verify clean.