Skip to content

spec(course): the FPGA course lesson specs compile, pass and assert at run time (Closes #10013) - #10014

Merged
gHashTag merged 1 commit into
masterfrom
fix/fpga-course-lesson-specs
Oct 17, 2026
Merged

gHashTag merged 1 commit into
masterfrom
fix/fpga-course-lesson-specs

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Closes #10013

The t27.ai FPGA hardware course links one spec per lesson (trinity apps/website/specs/course/course.t27, LESSON_SPECS), and trinity vendors those specs from this repo. On the Railway lab, 11 of the 27 lesson specs did not hold. This PR fixes them in .t27 only. The eight specs/tutorial/ lessons land here for the first time: they lived only in trinity, written on the unmerged t27 commit 1cd2877.

Before and after

All counts are from the Railway lab: t27c test-report (with zig 0.16.0) and t27b test --check (aarch64, under qemu). Before is trinity ee512359254bcd7438bb6a79c8a4a7f8b554b620, vendored copies. After is this branch on t27 de2cff882.

Lesson Spec Before (t27c) After (t27c) After (t27b)
1 specs/boards/wukong_v1.t27 15/15, 4 vacuous 15/15, 0 vacuous 15 PASS
2 specs/tools/tri/fpga.t27 1/1, 0 vacuous unchanged 1 PASS
3 specs/boards/xc7a100t_minimal.t27 23/23, 4 vacuous 23/23, 0 vacuous 23 PASS
4 specs/tutorial/01_values_and_types.t27 0 tests 4/4, 0 vacuous 4 PASS
5 specs/tutorial/05_widths_and_casts.t27 2/3, 1 FAIL 4/4, 0 vacuous 4 PASS
6 specs/fpga/stdlib.t27 17/17, 1 vacuous 17/17, 0 vacuous 17 PASS
7 specs/tutorial/02_functions.t27 3/3 3/3, 0 vacuous 3 PASS
8 specs/tutorial/07_tests_invariants_benches.t27 3/3 3/3, 0 vacuous 3 PASS
9 specs/tutorial/03_operators.t27 3/3 3/3, 0 vacuous 3 PASS
10 specs/tutorial/06_structs_enums_switch.t27 BLOCKED 3/3, 0 vacuous 3 PASS
11 specs/demos/hello_world.t27 BLOCKED 2/2, 0 vacuous 2 PASS
12 specs/tutorial/08_modules_and_arrays.t27 BLOCKED 3/3, 0 vacuous 3 PASS
13 specs/ternary/clocked_counter.t27 1/1 unchanged 1 PASS
14 specs/tutorial/04_control_flow.t27 BLOCKED 4/4, 0 vacuous 4 PASS
15 specs/ternary/ternary_full_adder.t27 6/6 unchanged 6 PASS
16 specs/fpga/crossopt.t27 6/6 unchanged 6 PASS
17 specs/fpga/dft.t27 17/17 unchanged 17 PASS
18 specs/fpga/partition.t27 13/13 unchanged 13 PASS
19 specs/fpga/placement.t27 BLOCKED 14/14, 0 vacuous 14 PASS
20 specs/fpga/timing.t27 25/25 unchanged 25 PASS
21 specs/fpga/cts.t27 15/15 unchanged 15 PASS
22 specs/tools/trios/tri/x7-fasm.t27 0 tests not in this repo -
23 specs/fpga/adapter.t27 3/3 unchanged 3 PASS
24 specs/tools/trios/tri/x7-writer.t27 0 tests not in this repo -
25 specs/tools/trios/tri/fpga-jtag.t27 0 tests not in this repo -
26 specs/tools/trios/tri/x7-board.t27 0 tests not in this repo -
27 specs/fpga/e2e_demo.t27 16/16 unchanged 16 PASS

Result: all 23 lesson specs held in t27 pass every test (201 tests in total) with 0 vacuous under t27c, and t27b reports the same PASS counts with 0 FAIL.

What each fix was

  • 05: narrow(0x1234) used @intCast, which fails at run time when the value does not fit. It now uses wide as u8, which truncates. narrow_checked keeps @intCast and has its own test with a value that fits. The lesson comment now explains the difference.
  • 04: the for (0..n) |i| capture is usize, so the u8 sum now casts it.
  • 06: a const bound to a switch with bare literal arms needs a type (: u8); without one, the comptime_int depends on runtime control flow.
  • 08: [_]T{...} lowers to an untyped tuple, which cannot be indexed with a runtime value. The arrays are now [N]T = [...], and the lesson says why.
  • 01: it had no tests. It now has 4, each copying the constants into a var first, because asserting on a constant folds at compile time and counts as vacuous.
  • hello_world: cast(...) is not declared; it now uses as u16.
  • placement: floorplan() did not set the struct's _dummy field.
  • wukong_v1: the vacuous tests now decode the identifiers the way a host does: IDCODE part 0x3636 and maker 0x049 (Xilinx); JEDEC maker 0x20 (Micron) and log2 capacity 24; mbit_to_bytes(128) == FLASH_BYTES; dram_capacity_known().
  • xc7a100t_minimal: the vacuous tests now go through functions: the clock period is derived from the frequency, the frequency is read back as cycles per ms, count_leds() == NUM_LEDS, and has_mac_debug().
  • stdlib: ip_kind_values was 0 == 0 and 1 == 1. It now reads IpKind.uart_tx, .gpio and .ternary_alu through kind_code().
  • ASCII: the em dashes and box-drawing characters in the tutorial comments, and the section sign in wukong_v1, are now ASCII (L3).

Checks

  • Negative controls: I planted 14 wrong expected values on the lab, one in each new or rewritten test. Each one fails exactly its target test under both t27c and t27b.
  • iverilog ratchet: I generated Verilog with gen-verilog for master and for this branch and ran iverilog -g2012 on both. The counts are unchanged: placement 6, stdlib 2 (matching tools/elab_baseline.txt), wukong_v1 0, xc7a100t_minimal 4.
  • Seals: no seals are touched; they are refreshed in the bulk re-mints.

Out of scope: lessons 22, 24, 25 and 26

These are trios tool cards, and they are not in this repo. Trinity generates them from trios with apps/website/scripts/tools-from-trios-tri.mjs, whose output is "data and carries no test block". Giving them tests means changing that .mjs generator, which the only-t27 rule does not allow (the alternative is porting the generator to t27). That is left as a follow-up. Until then, those four lessons still show 0 tests.

🤖 Generated with Claude Code

…t run time (Closes #10013)

Measured on the Railway lab at trinity ee5123592, 11 of the 27 lesson specs
the t27.ai FPGA course links did not hold: lesson 5 failed, lessons 10, 11,
12, 14 and 19 did not compile, lesson 4 had no tests, and lessons 1, 3 and 6
carried 9 vacuous tests that compared a constant with its own literal.

- specs/tutorial/01..08: the eight lessons land here from trinity (they were
  never merged in t27). 01 gains 4 tests; 04 casts the usize loop capture;
  05 narrows with `as` (truncating) and keeps @intcast for a value that fits;
  06 types the switch-bound local; 08 writes typed arrays, since `[_]T{}`
  lowers to a tuple that cannot be indexed at run time. Non-ASCII dashes in
  comments become ASCII (L3).
- specs/demos/hello_world.t27: `cast(...)` was undeclared; use `as u16`.
- specs/fpga/placement.t27: floorplan() sets the `_dummy` field.
- specs/boards/wukong_v1.t27: the IDCODE, JEDEC id, flash size and DRAM
  tests decode the identifiers at run time instead of re-reading literals.
- specs/boards/xc7a100t_minimal.t27: the clock, LED and MAC-debug tests go
  through period_ns_from_hz, cycles_per_ms, count_leds and has_mac_debug.
- specs/fpga/stdlib.t27: ip_kind_values reads the enum through kind_code()
  instead of asserting `0 == 0 and 1 == 1`.

After, on the lab: 23 of 23 lesson specs held in t27 report N/N tests
passing with 0 vacuous under t27c and the same PASS counts under t27b.
14 of 14 planted wrong values fail exactly their target test under both.
iverilog errors unchanged: placement 6, stdlib 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-17 16:19:21 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 49
PRs with All Checks Green 1
READY 0
FAILING 49
PENDING 0
NO CHECKS YET 0

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

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=e769ef021713 != 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 enabled auto-merge (squash) October 17, 2026 16:20
@gHashTag
gHashTag merged commit 2f39502 into master Oct 17, 2026
26 of 30 checks passed
gHashTag added a commit that referenced this pull request Oct 17, 2026
…#10053)

#10014 changed specs/boards/xc7a100t_minimal.t27, specs/boards/wukong_v1.t27,
specs/fpga/placement.t27 and specs/fpga/stdlib.t27 without resealing, so
check_seal_currency reported 8 STALE seals and Spec Guards and Seal Coverage
went red for every PR.

Written by `t27c seal <spec> --save && tri seals sync-twins` on the Railway
lab at d03afb0. No --update-baseline. Lab: STALE generated-code hash 0,
check_seal_coverage OK.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

specs: the FPGA course lesson specs compile, pass and assert at run time (tutorial, hello_world, placement, boards, stdlib)

1 participant