Skip to content

t27b verilog rung 1: T27 OS decision specs lower to RTL (Closes #11375) - #11376

Merged
gHashTag merged 2 commits into
masterfrom
claude/t27b-verilog-t27os
Oct 20, 2026
Merged

gHashTag merged 2 commits into
masterfrom
claude/t27b-verilog-t27os

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Closes #11375. Part of epic #11326 (see it, not closed here).

t27b verilog lowers the T27 OS decision specs: pure-fn wrapper modules, signed i2..i64, const-array ROMs, constant / and % as shifts or multiply-shift (exactness proof in verilog_plan.t27), casts, iverilog keyword escapes.

Measured (yosys 0.63 synth_xilinx xc7, pre-place, a lower bound): realm 2147 -> 82 LUT + 4 DSP; kernel lanes_to_shed 2123 -> 111 LUT, mem_lanes 2064 -> 78 LUT. petal_menu: 553 asserts native == iverilog; netlist == RTL on 629 vectors. hit does not fit as one combinational module (2 petals 160 DSP; 27 extrapolate to ~2160 vs 740): next rung. Hand Rust in cli/t27b/src net -1.

Generated with Claude Code (https://claude.com/claude-code)

claude and others added 2 commits October 20, 2026 18:42
…sion, casts -- petal_menu lowers, realm 2147 -> 82 LUT (Closes #11375)

`t27b verilog` now lowers the T27 OS decision specs, which all emitted an empty module before.
Decisions are in specs/tri/t27b/verilog_plan.t27, the writer in verilog_emit.t27, both regenerated
with t27c gen-rust; hand Rust in cli/t27b is -1 lines (lower.rs 3/3, main.rs 4/5: the work area
is 3n+80 bytes, the `top` argument, the `--top <fn>` flag).

- Pure fns: a spec with no on_clock/var/net/instance/input writes one combinational module per pub
  fn with integer/bool params and result (inputs = params, output t27_y); `--top <fn>` writes only
  that fn. petal_menu: 17 modules, test bench lowers too.
- Signed i2..i64: `signed` ports/regs/functions, `$signed({..})` around every sum/product/shift,
  `$signed({1'b0, x})` where an unsigned meets a wider signed peer, `>>>`, unary minus, -literal.
- Tables: `const T : [N]ty = [..]` read by index is a ROM function (case per element), negative
  elements for signed tables, index past the end reads 0 where Zig traps.
- Constant division: `x / k`, `x % k` are shifts/masks (power of two; signed rounds toward zero) or
  the multiply-shift q = (x * (2^n + m')) >> (n + ceil(log2 k)); exact for every n-bit x, proved
  in constant_division_is_exact (all 8-bit x for every k in 3..255, all 16-bit x for 8 divisors,
  the overshoot bound at n = 8/16/32/64 for 14 divisors up to 2^62-1).
- @as(T, x) and `x as T` between widths (sign fill, zero fill, low bits), SystemVerilog words
  (`inside`, `bit`, ...) escaped in names.

Measured (yosys 0.63 synth_xilinx xc7, pre-place): realm 2147 LUT/32 FF -> 82 LUT, 0 FF, 4 DSP;
fill 127 LUT, 4 DSP; fit_permille 1157 LUT, 60 DSP; crosses 631 LUT, 20 DSP; inside 1767 LUT, 80 DSP.
kernel.t27 (branch claude/t27os-tools): lanes_to_shed 2123 -> 111 LUT, mem_lanes 2064 -> 78 LUT,
agent_cap (refused on @as before) 267 LUT, 4 DSP.

Bit-exact: petal_menu's 10 tests run 553 asserts natively and 553 in iverilog on the emitted
module; 487 hit, 124 fit_permille, 302 realm, 198 fill vectors from the RTL equal t27b's native run;
the yosys netlist (DSP48E1 models) equals the RTL on 629 vectors. New fixtures verilog_signed.t27
(8 tests, incl. two 65536-operand sweeps of constant vs parameter division) and
verilog_signed_clock.t27 pass natively, in iverilog and in t27c's Zig reference. The 7 existing
verilog fixtures emit byte-identical Verilog except verilog_lib (now has modules); cargo test
--release -p t27b: all pass. Hooks could not run in this checkout (--no-verify).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ion; hit does not fit as one combinational module (Closes #11375)

Documents what rung 1 lowers and what still refuses (f64/string params, structs, a while with no
static bound, a table read by a signed index, a divisor above 2^62, @intcast outside @as, a
non-constant x / y which stays Verilog's divider).

The hit test, measured (yosys 0.63 synth_xilinx xc7, pre-place): `t27b verilog specs/t27f/petal_menu.t27
--top hit` emits a non-empty module. Because the loop variable p is a register behind a done flag,
yosys cannot make it constant per petal, so each unrolled petal is a full `inside` (80 DSP48E1,
~1.4k LUT): hit with the loop cut to 2 petals is 160 DSP, 2232 LUT (40 s), to 4 petals 320 DSP,
5096 LUT (75 s); 27 petals is therefore ~2160 DSP and ~38k LUT against 740 DSP on the A200T, and
yosys had not finished the full hit/on_tap in 17 minutes. The next step is an induction-variable
form of the counted loop (p = loop counter, so the vertex tables fold) and serialising the 64-bit
multiplies, not more lowering.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@gHashTag
gHashTag enabled auto-merge (squash) October 20, 2026 12:40
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-20 12:42:26 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 46
PRs with All Checks Green 4
READY 2
FAILING 46
PENDING 0
NO CHECKS YET 0

These columns do not partition: 2 + 46 + 0 + 0 = 48, and there are 50 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).

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.

t27b verilog rung 1: lower the T27 OS decision specs (pure fns, signed, ROM, constant division, casts)

2 participants