diff --git a/docs/NOW.md b/docs/NOW.md index 3e11201b8..9befee04a 100644 --- a/docs/NOW.md +++ b/docs/NOW.md @@ -1,7 +1,13 @@ -# NOW — fix(gen-zig): unused params + test bindings (2026-08-08) +# NOW — deeper net gated (2,5,3,1) + a without-Vivado open-flow refinement (2026-08-08) Last updated: 2026-08-08 +## test+docs: CI now gates a deeper [2,5,3,1] net learns; met-timing is a partial without-Vivado refinement (Refs #1764) + +- V2 (stack): added a deeper [2,5,3,1] (3-layer, 158-step) learning assertion to the generator self-test / CI learning gate -- held-out 59/60 (98%), deterministic. Extends the proven "the method scales beyond XOR" claim to a deeper+wider net +- Answered "can we do it without Vivado?": measured a partial open-flow refinement -- constrain the INTERNAL clk net to a met period (create_clock -period 50 [get_nets clk], ~20 MHz < fmax 21) and build WITHOUT --timing-allow-fail so P&R closes timing deterministically. Result: several seeds come up bit-exact at ep0 (vs glitching from the start), and seed-search still finds a fully-stable build (a met-timing seed trained XOR 4/4 all 60 epochs, saved as ax7203_MET_seed8_STABLE.bit). It does NOT kill the lottery (some seeds diverge over epochs) and more settle stays non-monotonic -- so met-timing + seed-search is the best OPEN recipe; deterministic no-seed-search still needs commercial P&R +- Free Vivado (ML Standard) supports xc7a200t but is x86 Linux/Windows only (not this macOS arm64 host). Board on generated capstone (XOR 4/4). Refs #1764 + ## fix(gen-zig): discard unused params + declare test/bench bindings (Closes #1910) - Zig gen emitted unused fn parameters (zig errors on them) and test-block bindings without declarations (the Zig twin of #1894) -- 66/68 of tri-net's legacy spec gens failed zig ast-check diff --git a/docs/SILICON_TRAINING_METHODOLOGY.md b/docs/SILICON_TRAINING_METHODOLOGY.md index 69100469f..eb272a2a6 100644 --- a/docs/SILICON_TRAINING_METHODOLOGY.md +++ b/docs/SILICON_TRAINING_METHODOLOGY.md @@ -217,6 +217,18 @@ buildable on this flow (item: MMCM places), or **commercial P&R** timing closure prototypes: cores in `scratchpad/retime/`, pipelined trainer in `scratchpad/board/bppipe/`, write/control-hardened in `scratchpad/board/bpctrl/`. +**Without Vivado — a partial open-flow refinement (measured).** Constraining the *internal* +clock net to a period nextpnr actually *meets* (`create_clock -period 50 [get_nets clk]`, +~20 MHz < the ~21 MHz fmax) and building **without** `--timing-allow-fail` makes P&R close +timing deterministically. This measurably improves the forward pass — several seeds come up +**bit-exact at ep0** (0/0.551/0.936/0.234) rather than glitching from the start — and +seed-search still finds a **fully-stable** build (a met-timing seed trained XOR 4/4 through +all 60 epochs; `scratchpad/board/bpmet/`). It does **not** eliminate the lottery (some seeds +still diverge over epochs) and more `settle` on top stays non-monotonic (item 2 holds even +here). So on the open flow, **met-timing + seed-search** is the best recipe; +deterministic no-seed-search closure still needs commercial P&R. *Free* Vivado (ML Standard, +ex-WebPACK) supports the xc7a200t but is x86 Linux/Windows only — not the macOS arm64 host. + ## Reproducibility The verification runs in CI on every pull request. The silicon build is one script diff --git a/tools/gft_backprop_microcode.py b/tools/gft_backprop_microcode.py index 18a363b0b..8b0f05838 100644 --- a/tools/gft_backprop_microcode.py +++ b/tools/gft_backprop_microcode.py @@ -438,6 +438,27 @@ def _predd(a, b): te = sum(1 for a, b, t in ted if _predd(a, b) == t) assert te >= int(0.9 * len(ted)), f"deep [2,4,3,1] held-out too low: {te}/{len(ted)}" print(f"self-test: deep [2,4,3,1] (3-layer, 2 hidden) learns nonlinear task, held-out {te}/{len(ted)} (>=90%) -- OK") + # deeper+wider: [2,5,3,1] (3-layer) generalises too -- the method scales, only the open + # silicon flow's placement marginality does not (fixed by the Vivado closure kit). + SZ = [2, 5, 3, 1] + reg, steps = gen_deep(SZ); rf = [0] * len(reg) + random.seed(3) + for l in range(1, len(SZ)): + for j in range(SZ[l]): + for k in range(SZ[l - 1]): rf[reg[f"W{l}_{j}_{k}"]] = enc(round(random.uniform(-0.8, 0.8), 3)) + rf[reg[f"b{l}_{j}"]] = enc(round(random.uniform(-0.5, 0.5), 3)) + random.seed(7); trw, tew = _ds(160), _ds(60) + def _predw(a, b): + sav = rf[:]; rf[reg["x0"]] = enc(a); rf[reg["x1"]] = enc(b); rf[reg["t0"]] = 0 + run(steps, rf); y = dec(rf[reg["y0"]]) + for i in range(len(rf)): rf[i] = sav[i] + return int(y > 0.5) + for _ in range(60): + for a, b, t in trw: + rf[reg["x0"]] = enc(a); rf[reg["x1"]] = enc(b); rf[reg["t0"]] = enc(float(t)); run(steps, rf) + te = sum(1 for a, b, t in tew if _predw(a, b) == t) + assert te >= int(0.9 * len(tew)), f"deep [2,5,3,1] held-out too low: {te}/{len(tew)}" + print(f"self-test: deep [2,5,3,1] (158 steps) learns nonlinear task, held-out {te}/{len(tew)} (>=90%) -- OK") vd = emit_verilog_deep([2, 4, 3, 1], "deep431") assert "module deep431" in vd and "for(gi=0;gi<" in vd print("emit_verilog_deep: [2,4,3,1] module generated -- OK")