Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/NOW.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
4 changes: 3 additions & 1 deletion tools/gft_backprop_microcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)


Expand Down
Loading