Library — math32

SkillDev tools

math32 IEEE single float library: multi-CPU layout (asm/z80, asm/8085, asm/8080, asm/gbz80), products math32*.lib including ez80_z80 / gbz80, rounding policy, div=restoring / inv=NR, force rebuild. Use when editing libsrc/math/float/math32 or A/B float divide/mul.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Library — math32 skill

What this skill tells your AI

The instructions your AI receives, as published by z88dk/z88dk in .agents/skills/library-math32/SKILL.md and read by ahel’s review.

Home: libsrc/math/float/math32/. Docs of record: libsrc/math/float/math32/readme.md. Link via --math32 (-lmath32@{ZCC_LIBCPU}).

0b. Math32 multi-CPU float library (layout + policy)

Home: libsrc/math/float/math32/. Products: math32.lib (plain z80) plus math32_{z80n,z180,ez80_z80,r2ka,kc160,8085,8080,gbz80,…}.lib. Link via --math32 (-lmath32@{ZCC_LIBCPU} — e.g. 8085 → math32_8085, 8080 → math32_8080, gbz80 → math32_gbz80, ez80_z80 → math32_ez80_z80; no separate --math32_8085 flag).

Layout

TreeRole
asm/z80/Z80-family cores; shared by z80n/z180/ez80_z80/r2ka/… when the lst points here
asm/8085/Stack-only 8085 cores (no EXX / IX / IY); extended opcodes + synthetics. After rl de, test exp with inc d/dec d — RDEL does not write Z
asm/8080/Stack-only 8080 cores (original ISA; no 8085 extras). ld hl,sp+n; park HL
asm/gbz80/Stack-only Game Boy cores (ld hl,sp+*, bit 7 leading-one; no cheap ex)
c/z80/, c/8085/, c/8080/, c/gbz80/Higher functions (C → precompiled asm); 8080/8085/gbz80 higher via sccz80 only
newlibfiles_*.lstWhich modules land in each product (newlibfiles_ez80_z80.lst, newlibfiles_gbz80.lst, …)

CPU-specific = same operation name, different ISA file (same one-op-per-file map as §0). Do not invent a second taxonomy for 8085 / gbz80.

eZ80 Z80-mode product (mlt)

eZ80 Z80-mode has the same mlt encodings as Z180 (ED 4C/5C/6C/7C). math32_ez80_z80.lib is built from newlibfiles_ez80_z80.lst, which selects the Z180 mantissa helpers (f32_z180_mulu_* / f32_z180_sqr_*).

Those helpers are gated:

IF __CPU_Z180__ | __CPU_EZ80__ | __CPU_EZ80_Z80__
Assemble asDefine set
-mz180__CPU_Z180__
-mez80 (ADL)__CPU_EZ80__
-mez80_z80__CPU_EZ80_Z80__

Do not build eZ80 from @newlibfiles_z80.lst alone: the plain-Z80 helpers are IF __CPU_Z80__ only and assemble empty on -mez80_z80. Suite gate: test/suites/mathtest_math32_ez80_z80.bin.

Rounding policy (do not mix casually)

ClassPolicy (current math32)
mul / sqr / div / poly / sqrt packIEEE RNE on residual below the kept mantissa
add / subDigi jam-sticky: lost align/overflow bits → OR 1 into mant LSB; pack has no RNE residual

Long add chains (e.g. n-body energy) are sensitive to add rounding: jam keeps second-energy error ~1e−6 class; full RNE-on-add has been measured to worsen E1 (~5e−5 class) at higher cost. Prefer matching z80 and 8085 policy even when engines are not bit-identical.

Divide / inverse (current policy)

OpAlgorithmNotes
div / m32_fsdivRestoring 24-bit mantissaz80 + 8085 + 8080 + gbz80 cores; z80n/z180/ez80_z80 share z80 asm/z80/f32_fsdiv.asm
inv / m32_fsinvNewton–RaphsonSlower than div for a reciprocal. HW mul helps inv only
invsqrt / m32_fsinvsqrtQuake seed + 3× NRStill the fastest 1/sqrt. Do not replace with 1.0/sqrt
math16Same split: restoring asm_f16_div, NR asm_f16_inv

Do not reintroduce NR trampoline fsdiv = fsinv+fsmul without A/B proof. Docs: math32/readme.md § div/inv; measurement: z88dk-tooling § A/B.

In C higher functions (c/m32_*.c):

NeedWriteDo not write
Reciprocal 1/n1.0/x (restoring div)m32_invf(x)
Inverse square rootm32_invsqrtf(x)1.0/m32_sqrtf(x)

pow(x, -1) / sinh / cosh / tanh / atan recip / asinh / acosh use divide. pow(x, -0.5) keeps m32_invsqrtf.

IEEE bit punning: use union float_long from c/m32_math.h (float f; int32_t l). Do not invent a local uint32_t union. Assign NAN_* / INFINITY_* as (int32_t)NAN_NEG_F32 so zsdcc does not warn on unsigned→signed.

Micro-opt patterns that port

PatternIdeaNotes
Implicit-1 CFld a,255 / add a,h → CF=(exp≠0) instead of or a / jr Z / scf~8–9 T per unpack; works on Z80 and 8085
Z80 non-callee stack loadpop + 3×push vs hl=sp+2 walk~8 T; 8085 stack-slot paths already different
Hot tiny helpersInline 2–4 insn jam sticky at call sitesSaves call/ret; size often net-neutral or smaller
Unused stack padDrop frame slots only after proving no SP offsets still use themRemeasure; fix every sp+N comment

Callee linkage: float helpers that pop a return address + stack args must be call’d, not bare jp (floor/ceil class bugs). Keep that rule when editing pack/add glue.

sccz80 + newlib: plain names vs *_fastcall (issue #3061)

math32.lib products are assembled with -D__CLASSIC. Under that flag, lm32/c/sccz80/{sin,sqrt,log,…}.asm expose stack-arg bridges for plain names; the DEHL entry is *_fastcall (defc sin_fastcall = _m32_sinf).

ConsumerWhat must happen
Classic include/math/math_math32.h#define sin(x) sin_fastcall(x) (and peers) — already correct
Newlib sccz80 + --math32Same remaps under __MATH_MATH32 in include/_DEVELOPMENT/proto/math.h, then make -C include/_DEVELOPMENT common/math.h
SDCCSingle-arg __DPROTO already emits #define sin(a) sin_fastcall(a) — OK without the sccz80 block
math48 default newlibPlain sin is true DEHL (cm48_sccz80_sin) — do not force math32 remaps off math48

Without the newlib remaps, sccz80 marks plain sin as __z88dk_fastcall and emits call sin with DEHL, but the linked object is the stack bridge (ignores DEHL). Symptom: hotspots show zero m32_fsinv / m32_fsinvsqrt / m32_fsmul32x32 entry hits, TIMER “too fast” (e.g. Whetstone ~15 KWIPS vs ~11), wrong numerics. Map proof of a healthy build: sin_fastcall / sqrt_fastcall present; app .asm shows callsin_fastcall not callsin.

Do not “fair up” classic vs newlib by adding bench-only invsqrt() optims to one side only (n-body). Align source (1.0/sqrt vs half invsqrtf16) and remeasure both products after header fixes.

Higher-function C regen (c/Makefile)

Z80 higher funcs: make -C libsrc/math/float/math32/cc/z80/*.asm (SDCC). 8085: make -C …/c 8085c/8085/*.asm (sccz80 only). 8080: make -C …/c 8080c/8080/*.asm (sccz80 only). gbz80: make -C …/c gbz80c/gbz80/*.asm (sccz80 only). make clean must only remove C-derived objects — never wipe hand-written peers in the same dir (math16: keep cm16_sccz80_*.asm under c/8085/).

Measure / rebuild / wiki: methodology-measure (§ math32 rebuild, benches, classic/newlib A/B, wiki bold rules). Docs of record: libsrc/math/float/math32/readme.md, support/benchmarks/*/readme.txt.


Force rebuild (multi-CPU)

Math32 / multi-CPU float libs (force rebuild)

Sources: libsrc/math/float/math32/ (per-CPU under asm/z80/, asm/8085/, …). Shared Z80-family add lives in asm/z80/d32_fsadd.asm and is assembled into each of math32.lib, math32_z80n.lib, math32_z180.lib, math32_ez80_z80.lib, math32_r2ka.lib, math32_kc160.lib, … Changing that file requires rebuilding every product that lists it, not only math32_8085.lib.

cd libsrc/math/float/math32
# force one object + relink (example: 8085 add)
rm -f obj/8085/math/float/math32/asm/8085/f32_fsadd.o ../../../math32_8085.lib
z88dk-z80asm -d -I"$ZCCCFG/.." -O=obj/8085/x/x/x -I.. -m8085 -D__CLASSIC \
  @newlibfiles_8085.lst
TYPE=8085 z88dk-z80asm -d -I"$ZCCCFG/.." -I.. -m8085 \
  -x../../../math32_8085 @math32.lst
cp -f ../../../math32_8085.lib ../../../lib/clibs/   # or: make -C libsrc install

# Z80-family products that share asm/z80/d32_fsadd.asm (repeat per CPU)
for cpu in z80 z80n z180 ez80_z80 r2ka kc160; do
  case $cpu in
    z80) lst=newlibfiles_z80.lst; lib=math32; masm=z80 ;;
    ez80_z80) lst=newlibfiles_ez80_z80.lst; lib=math32_ez80_z80; masm=ez80_z80 ;;
    *) lst=newlibfiles_${cpu}.lst; lib=math32_$cpu; masm=$cpu ;;
  esac
  rm -f obj/$cpu/math/float/math32/asm/z80/d32_fsadd.o ../../../$lib.lib
  z88dk-z80asm -d -I"$ZCCCFG/.." -O=obj/$cpu/x/x/x -I.. -m$masm -D__CLASSIC @$lst
  TYPE=$cpu z88dk-z80asm -d -I"$ZCCCFG/.." -I.. -m$masm -x../../../$lib @math32.lst
  cp -f ../../../$lib.lib ../../../lib/clibs/
done

Or: make -C libsrc/math/float/math32 then install all math32*.lib into lib/clibs/. After install, delete suite/bench .bin/.map before remeasure.

Prove the object is current: z88dk-z80nm lib/clibs/math32_8085.lib | rg 'f32_fsadd|ay16_njam'. For eZ80: z88dk-z80nm lib/clibs/math32_ez80_z80.lib | rg 'm32_mulu_32h|f32_z180'.


Related

  • Half float: library-math16
  • Measure / A/B: methodology-measure
  • Newlib headers (math remaps): library-newlib · edit proto then regenerate
  • 8085 cores: cpu-8085 · 8080: cpu-8080 · gbz80: cpu-gbz80
  • Z180 / eZ80 Z80-mode mlt: cpu-z180
  • Issue class: z88dk #3061 (classic vs newlib Whetstone)
  • Suite: test/suites/math (test_math32*.bin, including test_math32_ez80_z80.bin)

Signals

GitHub stars
1k
Forks
206
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
library-math32
Source
github.com/z88dk/z88dk