Skip to content

feat: M6 — Xtensa FPU emulator proven equal to S3 silicon - #240

Merged
Yona-Appletree merged 8 commits into
mainfrom
claude/f32-m6-p6-campaign
Aug 1, 2026
Merged

feat: M6 — Xtensa FPU emulator proven equal to S3 silicon#240
Yona-Appletree merged 8 commits into
mainfrom
claude/f32-m6-p6-campaign

Conversation

@Yona-Appletree

@Yona-Appletree Yona-Appletree commented Aug 1, 2026

Copy link
Copy Markdown
Member

Plan: lp2025/2026-07-30-1745-f32-native-math
Path: /Users/yona/.photomancer/planning/lp2025/2026-07-30-1745-f32-native-math/m6-xtensa-fpu-emulator/plan.md (phases P6+P7 — M6 complete)

M6 is done. lp-xt-emu now executes the Xtensa single-precision FP subset
and every corner of its numeric behavior is either fixed by IEEE-754 or
measured on the desk ESP32-S3, replayed with no board attached, forever.

G2 — PASSED 2026-08-01. Yona: "Yeah I did look at this, I do trust it.
G2 pass."
All four leans accepted (emulator matches silicon everywhere on
the corpus incl. FSR; captured vectors sufficient as a regression oracle;
denormals recorded target-defined as full IEEE, no product decision needed;
non-default rounding modes stay refused). Full record in
m6-xtensa-fpu-emulator.md §"Review gate: G2 — PASSED 2026-08-01".

P6 — the hardware campaign

  • mksadj.s added to lp-xt-inst — the real sqrt sequence uses it; it was wrongly recorded as an unassigned slot (defect filed)
  • Harness: the toolchain's real div/sqrt sequences (objdump-derived), 15-plane estimate sweeps, helper probe grids
  • Board window: three full captures (tables / helpers / families), committed under lp-xt/lp-xt-emu/tests/fixtures/fp/captures/
  • Estimate ROMs extracted: three shared ROMs; the model reproduces all ~503M measured points exactly (exhaustive release run + CI boundary sweep)
  • Helper semantics measured & implemented: nexp01 / mksadj / mkdadj / addexp / addexpm / maddn exact incl. flags; divn.s decoded (split-exponent reassembly, class window, RNE-with-sticky) — exact on the sequence envelope (272/272), probe agreement pinned 1 387/1 536
  • Every FpPolicy field measured with a citation (17/17). Headlines: FCR.RM is honored (directed rounding implemented for add/sub/mul, refused elsewhere); denormals are fully IEEE — no flushing (Q2 dissolves); NaN = last-operand-quieted, acc-first; round.s ties-to-even; two ISA-RM claims falsified (utrunc.s negatives wrap; FSR flags work)
  • Goldens promoted with board provenance; FSR is a first-class predicted column; UNKNOWN guard flipped to assert zero; negative control proven (corrupt row → exactly one DIVERGE)

P7 — ADR, docs, cleanup, PR (this batch)

  • ADR finalized (docs/adr/2026-07-31-xtensa-fp-behavior-contract.md): Status → Accepted, G2 ratification folded in with full header fields (Supersedes/Relates), an Alternatives considered section in house style, and the two register/ABI corrections M7's early implementation (PR feat: hardware float on the S3 — f32 VInsts and Xtensa lowering (M7 P1–P2) #241 P1–P4) surfaced — f15 reserved as emitter float scratch (15/16 FRs allocatable, not 16), and != maps to oeq.s + movf (not ueq.s + movf, which is false on NaN)
  • docs/design/float.md §4: the denormal row was asserting the opposite of the measured fact (said Xtensa flushes; it doesn't) — fixed, and the NaN-bits/round-ties rows now point at the ADR's measured answer
  • Stale "unproven/in-flight FPU" docs closed out: lp-xt-emu/README.md, lp-xt-inst/README.md, lp-xt/README.md, lp-xt-fp-vectors/README.md, AGENTS.md, and the fp-fixtures READMEs — pre-campaign UNKNOWN counts, "not yet run on hardware", "no FPU executors" all updated to the zero-divergence, G2-passed state; fp_silicon_replay.rs documented for the first time
  • Cleanup sweep found and closed a real gap: mksadj.s (added by P6) was never added to the objdiff mechanical-oracle corpus (fp_subset.S) — added, objdiff now 136/136 matched (was 134/134); removed lp-xt-fp-vectors's dead probe2::vector() wrapper; indexed the mksadj defect in docs/defects/README.md (was filed but not indexed) and added the incomplete-subset class it needed
  • Verified (not assumed) test_xt_fp_conformance is in clippy-fw-esp32s3's per-feature loop, and fp_conformance.rs/fp_silicon_replay.rs run under plain cargo test -p lp-xt-emu (lp-xt-emu is in default-members — no feature gate to rot)
  • Experiment repo (2026-esp32s3-experiment, separate repo/commit): FINDINGS.md, fixtures/README.md, docs/BACKPORT.md updated to stop claiming FP is unproven repo-wide

Validation

cargo test -p lp-xt-inst -p lp-xt-emu -p lp-xt-fp-vectors -p lp-emu-core -p lp-riscv-emu all green (0 failures) ·
cargo test -p lp-xt-emu --test fp_conformance --test fp_silicon_replay: 0 UNKNOWN, 5 630/5 630 AGREE, 0 DIVERGE ·
cargo test -p lp-xt-fp-vectors 18/18 · objdiff fp_subset.elf 136/136 matched, 0 mismatches ·
CI is the validation of record for this push — see checks below.

Resume notes for anyone reading this cold: p6-campaign-results.md first, then
the ADR, then fp_rom.rs's module docs.

🤖 Generated with Claude Code

Yona-Appletree and others added 4 commits July 31, 2026 19:29
The M6 P6 campaign transcribed the toolchain's real divide and square-root
sequences (objdump of esp-14.2.0 libgcc/libm — output-as-fact, no source
read) and found __ieee754_sqrtf uses mksadj.s, which lp-xt-inst wrongly
listed as an unassigned FP1 slot. Decode/encode/disasm/roundtrip/golden
added; the emulator classifies and refuses it like the other divide-step
helpers until their semantics are measured.

Plan: 2026-07-30-1745-f32-native-math/m6-xtensa-fpu-emulator (P6)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… sweeps, helper probes

The harness now runs the toolchain's REAL divide and square-root sequences
(transcribed from objdump of esp-14.2.0 libgcc __divsf3 / libm
__ieee754_sqrtf — output-as-fact) instead of skipping the F5 pseudo-ops;
sweeps the estimate ROMs over 15 (sign, exponent) planes including the
denormal/inf/NaN classes, with a run cap so a non-step-function plane
aborts loudly instead of drowning the capture; and gains a 'helpers' mode:
const.s 0..15 plus characterization grids for
nexp01/mksadj/mkdadj/addexp/addexpm/maddn/divn (madd.s runs the identical
grid as the contrast row). The grids live in lp-xt-fp-vectors::helpers so
both sides regenerate them, with their own pinned fingerprint.

Host side: fp_capture parses TABLE/T/END-table sweeps (with the same
truncation-and-count teardown discipline as the family rows), CONST rows,
and the helpers fingerprint.

Plan: 2026-07-30-1745-f32-native-math/m6-xtensa-fpu-emulator (P6)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… corner

The P6 campaign's implementation half. Every FpPolicy field is now measured
with a citation; the full 5630-vector corpus agrees with the desk S3
capture bit for bit — result AND FSR columns, zero divergence — and the
captures are committed as boardless replay fixtures.

- fp_rom.rs: the three estimate ROMs read off silicon (recip/div shared
  128-entry, rsqrt/sqrt odd+even 64-entry; every run of all 60 RLE sweeps
  reproduces exactly, ~503M points verified exhaustively in release), plus
  the measured helper semantics: nexp01 (normalize-negate by parity),
  mksadj/mkdadj (split exponent encoders, floor-halving arithmetic and a
  result-class channel), addexp/addexpm (pure bit ops), and divn — the
  reassembly step: 8-bit sign-extended exponent excess decomposed as
  8k+p, A = 32k_r + (k_t mod 32), class window at A-384, RNE with exact
  sticky, +2^(A-50) on exact cancellation.
- float_math.rs: FCR.RM is HONORED (F1: 1944/1944 directed-mode rows match
  IEEE) — directed rounding implemented for add/sub/mul, refused loudly
  where unmeasured; denormals fully IEEE (no flush either direction); NaN
  rule last-operand-quieted with acc-first priority for the accumulate
  ops; utrunc.s negative wrap (RM FALSIFIED); round.s ties-to-even; FSR
  flags modeled throughout (RM's no-flags claim FALSIFIED).
- Corpus: FSR is now a first-class predicted column; goldens promoted with
  full board provenance; the UNKNOWN guard flipped — zero UNKNOWN rows,
  and the negative control (corrupted row -> exactly one DIVERGE) proven.
- fp_silicon_replay.rs: tables/helpers/families captures replayed on every
  test run, no board; divn probe agreement pinned at 1387/1536 with the
  off-envelope remainder documented for the queued round-2 probe grids.

Plan: 2026-07-30-1745-f32-native-math/m6-xtensa-fpu-emulator (P6)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The ADR records the measured contract corner by corner — including the two
RM falsifications (utrunc.s negatives, FSR flags) — with a Remains
Unverified section that states the negative space. Draft: P7 finalizes it
after G2. Defect entry for the mksadj.s instruction-model gap the campaign
caught.

Plan: 2026-07-30-1745-f32-native-math/m6-xtensa-fpu-emulator (P6)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Yona-Appletree
Yona-Appletree changed the base branch from claude/f32-m6-p5-campaign-harness to main August 1, 2026 05:45
Yona-Appletree and others added 4 commits August 1, 2026 07:41
…P6's stale docs

P7 (M6's close-out): the ADR drafted in P6 is now Accepted (G2 passed
2026-08-01) — full header fields, the G2 ratification folded in, the two
register/ABI corrections M7's early implementation surfaced (f15 reserved
emitter scratch; `!=` maps to oeq.s+movf not ueq.s+movf), and an
Alternatives-considered section in house style.

docs/design/float.md's denormal row asserted the opposite of what the
campaign measured (ESP32-S3 does NOT flush denormals — full IEEE); fixed,
and pointed the NaN-bits/round-ties rows at the ADR now that Xtensa has a
measured answer for each.

lp-xt-emu/README.md, lp-xt-inst/README.md, lp-xt/README.md,
lp-xt-fp-vectors/README.md, AGENTS.md, and the fp fixtures READMEs still
described the FP work as unproven/in-flight (pre-campaign UNKNOWN counts,
"not yet run on hardware", "no FPU executors") — updated to the measured,
zero-divergence, G2-passed state, with fp_silicon_replay.rs documented for
the first time.

Closed a real coverage gap found in the sweep: `mksadj.s` (added by P6,
docs/defects/2026-07-31-mksadj-missing-from-fp-subset.md) was never added to
the objdiff mechanical-oracle corpus (fp_subset.S), so its encoding sat
outside the mechanical check the rest of the subset gets. Added it;
objdiff now reports 136/136 matched (was 134/134), zero mismatches.

Plan: 2026-07-30-1745-f32-native-math/m6-xtensa-fpu-emulator (P7)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…r wrapper

Cleanup sweep (P7): docs/defects/2026-07-31-mksadj-missing-from-fp-subset.md
was filed at fix time but never added to the registry index or given a
class-vocabulary entry — added `incomplete-subset` (the class: an external
tool's enumerated opcode assignment is wrong, and only the tool's own output
falsifies it) and indexed the entry.

lp-xt-fp-vectors' helpers::probe2::vector() was unused outside its own
definition — the device harness and fp_silicon_replay.rs both call
probe2::probe() directly — and its body stuffed a fake
`op: HelperOp::DivnS` discriminant with a "placeholder, unused" comment.
Removed; the now-unused `use super::HelperVector` import went with it.

Plan: 2026-07-30-1745-f32-native-math/m6-xtensa-fpu-emulator (P7)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…mance harness

Small follow-up to the P7 doc pass: the `just fwtest-xt-fp-esp32s3` example
block showed family/tables invocations but not `helpers`, even though the
harness has supported it since P6 (divide-step helpers + probe2).

Plan: 2026-07-30-1745-f32-native-math/m6-xtensa-fpu-emulator (P7)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Yona-Appletree Yona-Appletree changed the title feat: M6 P6 — the Xtensa FPU silicon conformance campaign feat: M6 — Xtensa FPU emulator proven equal to S3 silicon Aug 1, 2026
@Yona-Appletree
Yona-Appletree marked this pull request as ready for review August 1, 2026 15:09
@Yona-Appletree
Yona-Appletree merged commit fd08717 into main Aug 1, 2026
11 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant