diff --git a/docs/NOW.md b/docs/NOW.md index f3ef237e8..2d73f509e 100644 --- a/docs/NOW.md +++ b/docs/NOW.md @@ -1,7 +1,14 @@ -# NOW — feat: emit_verilog can emit the SILICON-READY variant (clk_div) (2026-08-08) +# NOW — feat: emit_verilog custom init -> GENERATED trainer TRAINS XOR ON SILICON (2026-08-08) Last updated: 2026-08-08 +## feat: emit_verilog `init=` + closed the verified-generator -> hardware loop (Refs #1764) + +- `emit_verilog` now takes an optional `init` dict (default None) that overrides the random weight init. With an XOR near-solution init, the CI-verified generator emits a microsequencer that trains XOR (29/30 epochs in the model) +- **Closed the last gap: the CI-VERIFIED GENERATOR's RTL now trains a neural net on REAL SILICON** (not the hand-written bpseq.v). `emit_verilog(2,2,1,"genbp",clk_div=16,init=XOR)` -> UART wrapper -> seed-searched openXC7 build -> flashed to the AX7203: **trains XOR to 4/4, 24/25 (and 21/22) epochs, converging y11->0.013**, forward bit-exact to the model at ep0. Artifact `board/ax7203_GENERATED_trainer_CAPSTONE.bit` +- Note: the generated trainer (TRAINABLE biases -> more microcode steps) is more timing-marginal than the lean hand-written bpseq (fixed hidden bias); needed seed 6 of {1,2,3,6,7,8} (seeds 1/2/3/7/8 diverged). Seed-search over --timing-allow-fail placements remains the working path (open-P&R can't multicycle-constrain) +- Tool-only; default emit output byte-identical (CI gate unaffected). Refs #1764 + ## feat: fold the capstone silicon fix into the verified generator (Refs #1764) - The capstone (full backprop trains XOR on live AX7203) ran on a HAND-WRITTEN board wrapper, not the CI-verified generator. This closes that gap: `emit_verilog` / `emit_verilog_deep` now take `clk_div` (default 1 = unchanged). clk_div>1 emits the SILICON-READY variant -- the exact fix that trains on silicon: register file forced to flip-flops (`ram_style=registers`, since distributed LUTRAM can't do the parallel weight init) + a /N clock-enable so the deep shared-core path gets ~clk_div x SETTLE cycles to settle (the open-source P&R can't express a multicycle constraint) diff --git a/tools/gft_backprop_microcode.py b/tools/gft_backprop_microcode.py index 43ae2e7f0..18a363b0b 100644 --- a/tools/gft_backprop_microcode.py +++ b/tools/gft_backprop_microcode.py @@ -224,7 +224,7 @@ def run(steps, rf): av = _mod(rf[a], am); bv = _mod(rf[b], bm) rf[d] = smul(av, bv) if op == "MUL" else (sadd(av, bv) if op == "ADD" else av) -def emit_verilog(n_in, n_hid, n_out, modname, clk_div=1): +def emit_verilog(n_in, n_hid, n_out, modname, clk_div=1, init=None): """Emit a synthesizable microsequencer Verilog module for the given arch. One shared GftSmul + one shared GftSadd, a register file, and a case(pc) ROM. Fully parametric interface: one x{k}i input port per input, one t{o}i target @@ -246,6 +246,8 @@ def emit_verilog(n_in, n_hid, n_out, modname, clk_div=1): for j in range(n_hid): initv[f"v{o}_{j}"] = round(random.uniform(-1.0, 1.0), 3) for j in range(n_hid): initv[f"b{j}"] = round(random.uniform(-0.5, 0.5), 3) for o in range(n_out): initv[f"bo{o}"] = 0.0 + if init is not None: # caller-supplied weights (e.g. an XOR near-solution) + initv.update(init) return _emit_module(reg, steps, initv, n_in, n_out, modname, clk_div)