Skip to content

fpga: wasm_module -- the wasm binary container law: LEB128, header, section walk (refs #11781) - #11864

Merged
gHashTag merged 1 commit into
masterfrom
lane/fpga-wasm-module
Oct 23, 2026
Merged

gHashTag merged 1 commit into
masterfrom
lane/fpga-wasm-module

Conversation

@gHashTag

Copy link
Copy Markdown
Collaborator

The container law for the WASM line: LEB128 unsigned/signed (the spec appendix's own vectors), the magic+version header, the section walk with the truncation refusal (the end sentinel). The consumers: wasm_interp.t27's loader (reads), the future emitter (writes) — the round-trip on the same structures is the law.

6/6 tests, 0 FAIL, 0 vacuous. The sleb32 accumulates in i64 and wraps (the spec's own method — the i32-domain sign-extension shifted the accumulator wrong; found and fixed by the spec's own vectors).

phi^2 + 1/phi^2 = 3 | TRINITY

…e header, the section walk (refs #11781, the wasm_interp loader's read side)
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-23 17:43:53 UTC

Summary

Status Count
Total Open PRs 32
PRs with Failing Checks 28
PRs with All Checks Green 4
READY 3
FAILING 28
PENDING 0
NO CHECKS YET 0

These columns do not partition: 3 + 28 + 0 + 0 = 31, and there are 32 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=5aec047d42ec != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@gHashTag
gHashTag merged commit aa18695 into master Oct 23, 2026
30 of 36 checks passed
@tri-claw

tri-claw Bot commented Oct 23, 2026

Copy link
Copy Markdown

Summary by t27-bees

Checked by the t27 compiler

t27c parse, parse-complete and typecheck on each changed .t27 file at b6c4c48. Nothing was generated, built or run. A pass means the file is well formed, not that it is right.

  • specs/fpga/wasm_module.t27: parses and typechecks.

Read by the model

This PR introduces the WebAssembly module container law: LEB128 (unsigned/signed), the magic+version header, and a section walker that refuses truncated sections. It's the binary format foundation for wasm_interp.t27's loader and a future emitter.

Worth a look

  • specs/fpga/wasm_module.t27:58 (uleb_read) — On overlong LEB128 (shift > 63), the loop breaks and returns a partial value/n instead of signaling an error. Malformed input silently yields a wrong integer and a byte count that doesn't reach the terminator.
  • specs/fpga/wasm_module.t27:85 (sleb32_read) — Same overlong issue: if shift >= 64 the loop breaks, then the sign-extension logic runs on whatever b and shift remain. The shift < 64 guard prevents UB from (-1 as i64) << shift, but the returned value is still a partial decode with no error indication.
  • specs/fpga/wasm_module.t27:70 (uleb_write) — No bounds check on dst; the caller must guarantee enough space (max 10 bytes for u64). The tests pass because they use fixed arrays, but production use could write out of bounds.
  • specs/fpga/wasm_module.t27:129 (next_section) — r.value is u64 but cast to u32 in the returned SectionRef.size. A section size > 4 GiB truncates silently; the truncation check r.value > src.len - payload only catches sizes exceeding the remaining buffer, not the u32 overflow.
  • specs/fpga/wasm_module.t27:108 (header_ok) — Hardcodes version bytes (1,0,0,0) instead of using the VERSION constant. Inconsistent with the declared constant, though functionally identical for MVP.

Read: 1 files, +221 -0, the whole diff. Head b6c4c48. Model: openai-compatible/nvidia/nemotron-3-ultra-550b-a55b. Commands: @t27-bees review | summary | help | pause | resume. Free for every repository.

github-actions Bot pushed a commit that referenced this pull request Oct 25, 2026
…b split that turns fpga-lint green (Closes #12051) (#12059)

* elab baseline: rows for wasm_module 6 and wasm_opcodes 149, the two law tables that landed without rows (Closes #12051)

Both reached master without rows (#11864, #11867), so the ratchet read them as NEW and the fpga-conformance step has been red on master since (run 40109127962: 431 against 276; 276 + 6 + 149 = 431, no other module moved). The note under the notes mark records the measured shape of each count: one ROWS line with 149 unsized zeros, and src_len unbound in 4 fns plus the 2 condition lines derived from them. No bless, no spec change, no gate change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fpga(hdmi_grab): one home per character and the libc tail to specs/t27os, so fpga-lint and the elab ratchet pass (Refs #12171, Refs #12051)

fpga-lint has been red on master since #10949 landed hdmi_grab (2026-10-22):
gen-verilog copies a t27 char literal verbatim, Verilog reads '0 as an unsized
literal, and yosys stopped at line 88 of hdmi_grab.v. Behind that line the same
file carried its libc host part (getenv, fork, execve, fopen, main), which
cannot be Verilog either, so a compiler fix alone would have moved the error,
not removed it. #12171 keeps the compiler side open; this is the spec side.

- specs/fpga/hdmi_grab.t27: the ten characters the checker compares bytes
  against are consts (CH_0 .. CH_SP), one home each; no char literal is left.
  The host tail (HG_BUF/HG_LIST/HG_CMD/HG_PATH, hg_cat, hg_env, hg_sh,
  hg_slurp, hg_path, main) left the file. test-report: 14 tests, 14 pass,
  0 vacuous.
- specs/t27os/hdmi_grab_main.t27 (new, module T27osHdmiGrabMain): that host
  tail, verbatim, importing hg_* / V_PASS / CH_0 from fpga::hdmi_grab by use,
  the way plist_main.t27 imports install/release. t27c gen splices the
  imports into one .zig (use_resolve.rs); zig build-exe -lc builds it (1.9 MB
  binary, no diagnostics). Two tests on the two helpers it adds (frame path,
  byte copy): 2 pass, 0 vacuous.
- tools/elab_baseline.txt: hdmi_grab 57 -> 5 (431 -> 379), note dated
  2026-10-25. The 5: 4 x pixel_at taken by use from vga_text_core (gen-verilog
  binds no imports) and 1 x nd_len, an unsized array param (#2410).

Measured on the regenerated hdmi_grab.v with a master-equivalent t27c:
yosys -p "read_verilog -sv -DSIMULATION hdmi_grab.v; hierarchy -top
fpga_hdmi_grab" exits 0; grep -c "\$signed('" = 0; iverilog -g2012
-DSIMULATION: 5 error lines without the summary line, as the ratchet counts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
github-actions Bot pushed a commit that referenced this pull request Oct 25, 2026
… frame_main that writes each run's frame to a PPM (Closes #12203) (#12270)

* elab baseline: rows for wasm_module 6 and wasm_opcodes 149, the two law tables that landed without rows (Closes #12051)

Both reached master without rows (#11864, #11867), so the ratchet read them as NEW and the fpga-conformance step has been red on master since (run 40109127962: 431 against 276; 276 + 6 + 149 = 431, no other module moved). The note under the notes mark records the measured shape of each count: one ROWS line with 149 unsized zeros, and src_len unbound in 4 fns plus the 2 condition lines derived from them. No bless, no spec change, no gate change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fpga(hdmi_grab): one home per character and the libc tail to specs/t27os, so fpga-lint and the elab ratchet pass (Refs #12171, Refs #12051)

fpga-lint has been red on master since #10949 landed hdmi_grab (2026-10-22):
gen-verilog copies a t27 char literal verbatim, Verilog reads '0 as an unsized
literal, and yosys stopped at line 88 of hdmi_grab.v. Behind that line the same
file carried its libc host part (getenv, fork, execve, fopen, main), which
cannot be Verilog either, so a compiler fix alone would have moved the error,
not removed it. #12171 keeps the compiler side open; this is the spec side.

- specs/fpga/hdmi_grab.t27: the ten characters the checker compares bytes
  against are consts (CH_0 .. CH_SP), one home each; no char literal is left.
  The host tail (HG_BUF/HG_LIST/HG_CMD/HG_PATH, hg_cat, hg_env, hg_sh,
  hg_slurp, hg_path, main) left the file. test-report: 14 tests, 14 pass,
  0 vacuous.
- specs/t27os/hdmi_grab_main.t27 (new, module T27osHdmiGrabMain): that host
  tail, verbatim, importing hg_* / V_PASS / CH_0 from fpga::hdmi_grab by use,
  the way plist_main.t27 imports install/release. t27c gen splices the
  imports into one .zig (use_resolve.rs); zig build-exe -lc builds it (1.9 MB
  binary, no diagnostics). Two tests on the two helpers it adds (frame path,
  byte copy): 2 pass, 0 vacuous.
- tools/elab_baseline.txt: hdmi_grab 57 -> 5 (431 -> 379), note dated
  2026-10-25. The 5: 4 x pixel_at taken by use from vga_text_core (gen-verilog
  binds no imports) and 1 x nd_len, an unsized array param (#2410).

Measured on the regenerated hdmi_grab.v with a master-equivalent t27c:
yosys -p "read_verilog -sv -DSIMULATION hdmi_grab.v; hierarchy -top
fpga_hdmi_grab" exits 0; grep -c "\$signed('" = 0; iverilog -g2012
-DSIMULATION: 5 error lines without the summary line, as the ratchet counts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fpga(wasm_fb): a 320x200 palette framebuffer in the video raster, and frame_main that writes each run's frame to a PPM (Closes #12203)

Three files:

- specs/fpga/wasm_fb.t27 (module fpga_wasm_fb): a 320x200 u8 framebuffer FB
  and a 256-entry u32 palette PAL, scaled 2x into the 640x400 band at rows
  40..439 of the 640x480 raster (40 black rows above and below, black at
  x >= 640). pal_default is a 16-step ramp per colour group, fb_test_pattern
  paints 20x12 blocks and a gradient below, frame_pixel_at picks the
  framebuffer or the text raster. The single pixel_at call site is
  frame_pixel_at.
- specs/t27os/frame_main.t27 (module T27osFrameMain): a host program that
  writes the 640x480 frame to a P6 PPM after every run (FRAME_OUT, default
  /tmp/t27_frame.ppm). FRAME_MODE=title runs hg_check and exits 1 on any
  verdict but PASS; FRAME_MODE=pattern paints the pattern and skips hg_check;
  a bad mode, an unopenable path or a short write exits 2.
- tools/elab_baseline.txt: new row `wasm_fb 2` and a dated note, 379 -> 381.

Measured:

- t27c test-report wasm_fb.t27: 8 of 8 pass, 0 vacuous.
- t27c test-report frame_main.t27: 2 of 2 pass, 0 vacuous.
- iverilog -g2012 -DSIMULATION on the gen-verilog output: exactly 2 lines,
  `No function named pixel_at` (the use-taken name, same class as hdmi_grab)
  and its derived `Unable to elaborate condition expression`. That is the
  wasm_fb 2 row.
- yosys read_verilog -sv + hierarchy -top fpga_wasm_fb: exit 0.
- frame_main built with zig 0.16.0; the title run exits 0 with hg_check
  verdict 0 (PASS); the pattern run exits 0; both PPMs are 921615 bytes
  (15 header + 640*480*3), and they differ.
- ffmpeg converts both PPMs to PNG, 640x480 each.

Nothing here is flashed to a board.

No hand-written code in another language; the baseline is a data file.
Refs #9367; see Trinity-S-AI-DNA/trinity-fpga#917

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
github-actions Bot pushed a commit that referenced this pull request Oct 25, 2026
…lk, function table, exports, data segments (Closes #12201) (#12278)

* elab baseline: rows for wasm_module 6 and wasm_opcodes 149, the two law tables that landed without rows (Closes #12051)

Both reached master without rows (#11864, #11867), so the ratchet read them as NEW and the fpga-conformance step has been red on master since (run 40109127962: 431 against 276; 276 + 6 + 149 = 431, no other module moved). The note under the notes mark records the measured shape of each count: one ROWS line with 149 unsized zeros, and src_len unbound in 4 fns plus the 2 condition lines derived from them. No bless, no spec change, no gate change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fpga(hdmi_grab): one home per character and the libc tail to specs/t27os, so fpga-lint and the elab ratchet pass (Refs #12171, Refs #12051)

fpga-lint has been red on master since #10949 landed hdmi_grab (2026-10-22):
gen-verilog copies a t27 char literal verbatim, Verilog reads '0 as an unsized
literal, and yosys stopped at line 88 of hdmi_grab.v. Behind that line the same
file carried its libc host part (getenv, fork, execve, fopen, main), which
cannot be Verilog either, so a compiler fix alone would have moved the error,
not removed it. #12171 keeps the compiler side open; this is the spec side.

- specs/fpga/hdmi_grab.t27: the ten characters the checker compares bytes
  against are consts (CH_0 .. CH_SP), one home each; no char literal is left.
  The host tail (HG_BUF/HG_LIST/HG_CMD/HG_PATH, hg_cat, hg_env, hg_sh,
  hg_slurp, hg_path, main) left the file. test-report: 14 tests, 14 pass,
  0 vacuous.
- specs/t27os/hdmi_grab_main.t27 (new, module T27osHdmiGrabMain): that host
  tail, verbatim, importing hg_* / V_PASS / CH_0 from fpga::hdmi_grab by use,
  the way plist_main.t27 imports install/release. t27c gen splices the
  imports into one .zig (use_resolve.rs); zig build-exe -lc builds it (1.9 MB
  binary, no diagnostics). Two tests on the two helpers it adds (frame path,
  byte copy): 2 pass, 0 vacuous.
- tools/elab_baseline.txt: hdmi_grab 57 -> 5 (431 -> 379), note dated
  2026-10-25. The 5: 4 x pixel_at taken by use from vga_text_core (gen-verilog
  binds no imports) and 1 x nd_len, an unsized array param (#2410).

Measured on the regenerated hdmi_grab.v with a master-equivalent t27c:
yosys -p "read_verilog -sv -DSIMULATION hdmi_grab.v; hierarchy -top
fpga_hdmi_grab" exits 0; grep -c "\$signed('" = 0; iverilog -g2012
-DSIMULATION: 5 error lines without the summary line, as the ratchet counts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fpga(wasm_module): load a whole .wasm image: LEB128 pairs, section walk, function table, exports, data segments (Closes #12201)

The loader walks one module held in a [SRC_MAX]u8 array plus an explicit
src_len and returns a ModuleDesc: per-function code ranges and locals
vectors, the import function count, exports (name offset, length, kind,
index), data segments as (destination, source offset, length) triples,
memory and table limits, the start function, and the global and element
payload ranges. Failures are named codes: ERR_BAD_MAGIC, ERR_BAD_VERSION,
ERR_TRUNCATED, ERR_TOO_MANY, ERR_MALFORMED, ERR_UNSUPPORTED. Never
indexes past the array.

LEB128 u32, s32 and s33 readers return a (value, n) struct under the
5-byte limit. No new function takes a slice; the existing uleb_read and
sleb32_read stay. Struct locals born in loops and branches are declared
once at the top of the function body and assigned inside, because
gen-verilog hoists only top-level locals.

15 new tests (21 in the spec): the spec appendix LEB vectors, four
hand-encoded modules with offsets counted by hand, and the four error
codes.

Refs #9367; see Trinity-S-AI-DNA/trinity-fpga#917

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@gHashTag
gHashTag deleted the lane/fpga-wasm-module branch October 26, 2026 03:46
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