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
8 changes: 7 additions & 1 deletion docs/NOW.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
# NOW — MMCM places but is dead on silicon; open-flow structural options exhausted (2026-08-08)
# NOW — Vivado closure kit: the multicycle constraint that kills the seed-lottery (2026-08-08)

Last updated: 2026-08-08

## feat(docs): Vivado closure kit -- the set_multicycle_path constraint the open flow cannot express (Refs #1764)

- The root-cause arc concluded the seed-lottery is a global placement effect of the timing-relaxed open-flow placement; the cure is not another register but telling a timing-driven P&R the truth about the path. nextpnr-xilinx XDC = create_clock only, so it cannot; Vivado can
- Added `docs/vivado_closure/`: (1) `bpseq_vivado.xdc` = create_clock 200 MHz + `set_multicycle_path 16` on the shared-core `rf -> rf` (through GftSmul/GftSadd) paths -- that path is genuinely multicycle (captured once per cen x settle ~2560 cycles), so Vivado closes it deterministically and the lottery disappears; (2) `vivado_build.tcl` batch synth->route->bitstream printing worst slack; (3) `README.md`
- This converts the documented open-toolchain limitation into a solved problem with the right instrument, and is the prerequisite for training nets > XOR (where open-flow seed-search runs out). Vivado does not run on this macOS arm64 host, so the kit is authored for the user's Vivado environment. Methodology points to it. Docs/scripts only. Refs #1764

## docs: MMCM real clock tree places but does NOT function on silicon -> open-toolchain options exhausted, seed-search is final (Refs #1764)

- Tested the last structural lever ("все три", Variant 1): regenerate the 200 MHz clock through the MMCM/CMT tree (low-skew) instead of the fabric IBUFDS net, to probe the global clock-skew hypothesis. MMCME2_BASE places in nextpnr and the fasm builds, but the flashed bitstream is DEAD on the AX7203 -- no UART response on any of 4 seeds, with or without a BUFG on the MMCM output
Expand Down
4 changes: 4 additions & 0 deletions docs/SILICON_TRAINING_METHODOLOGY.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ does not re-run them:
on openXC7, not functional** — the clock-skew hypothesis cannot be tested here, and the
open-toolchain structural options are fully exhausted. Only commercial P&R (Vivado) can
close timing directly or provide a working MMCM. Build in `scratchpad/board/bpmmcm/`.
A ready-to-run **Vivado closure kit** for this is in `docs/vivado_closure/`: a
`set_multicycle_path` on the shared-core `rf→rf` path — the exact constraint the open
flow cannot express — plus a batch build script, which closes the deep path
deterministically (no seed-search) and is the prerequisite for training nets > XOR.

Conclusion of the root-cause arc: **every local register-based fix has failed** — the
combinational datapath at the endpoints (7), mid-cloud (10), and the write/control path
Expand Down
41 changes: 41 additions & 0 deletions docs/vivado_closure/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Vivado closure kit — kills the seed-lottery with a real multicycle constraint

The open flow (yosys → nextpnr-xilinx → prjxray) **cannot express a multicycle timing
constraint** — nextpnr-xilinx's XDC parser supports only `create_clock`. So the deep
shared-core path (`rf → GftSmul/GftSadd → rf`) is left timing-relaxed and correctness
becomes placement-dependent: some `--seed` values train, most glitch (the "seed-lottery",
characterised across 12 measured dead ends in `SILICON_TRAINING_METHODOLOGY.md`).

Commercial P&R closes it directly. This kit is the minimal delta:

- **`bpseq_vivado.xdc`** — `create_clock` at 200 MHz **plus** `set_multicycle_path 16`
on the `rf → rf` (through-core) paths. That path is genuinely multicycle: the
microsequencer captures its result only once per `cen × settle` (~2560) cycles, so it
never needs 200 MHz single-cycle setup. Vivado then closes it deterministically.
- **`vivado_build.tcl`** — batch synth → opt → place → phys_opt → route → bitstream,
printing the worst setup slack (expect ≥ 0) and writing `bpseq_vivado.bit`.

## Run

```
# copy the RTL next to this kit:
cp ../bpseq_capstone.v bpseq.v
cp ../uart_bpseq.v ../gft_smul.v ../gft_sadd.v .
vivado -mode batch -source vivado_build.tcl
```

Then flash the result exactly like the open-flow bitstream — but **no seed-search**:

```
openFPGALoader -c digilent_hs2 --busdev-num 002:002 bpseq_vivado.bit
python3 ../drive_bpseq.py /dev/cu.usbserial-2120
```

## Why this is the fix (and the open flow is not)

Every *local* fix failed on silicon (endpoint / mid-cloud / write-control registration —
the fault is a global clock/placement effect of the relaxed placement). The cure is not a
different register; it is **telling the tool the truth about the path** so a timing-driven
placer closes it. Vivado can hear that constraint; nextpnr-xilinx cannot. This converts the
documented open-toolchain limitation into a solved problem with the right instrument, and it
is the prerequisite for training nets larger than XOR (where open-flow seed-search runs out).
26 changes: 26 additions & 0 deletions docs/vivado_closure/bpseq_vivado.xdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## AX7203 (xc7a200tfbg484-1) — GF-T microsequencer trainer, commercial P&R closure.
## The one constraint the open flow (nextpnr-xilinx XDC = create_clock only) cannot
## express: the shared-core path is MULTICYCLE, so Vivado closes it deterministically
## and the seed-lottery disappears.

## --- board clock (200 MHz LVDS); Vivado propagates through the IBUFDS automatically ---
set_property -dict {PACKAGE_PIN R4 IOSTANDARD DIFF_SSTL15} [get_ports clk_p]
set_property -dict {PACKAGE_PIN T4 IOSTANDARD DIFF_SSTL15} [get_ports clk_n]
create_clock -period 5.000 -name sys_clk [get_ports clk_p]

## --- the shared-core datapath is a multicycle path ---------------------------------
## rf -> (modf) -> GftSmul/GftSadd -> rf. The microsequencer captures the result only
## once per (cen x settle) cycles, so this path never needs to meet 200 MHz single-cycle
## setup. Its real delay is ~47 ns (~10 cycles); a 16-cycle budget closes it with margin
## while every launch->capture gap in the design is >= 2560 cycles, so this is safe.
## Counters (pc/settle/dc) and the UART FSM are NOT rf_reg, so they stay single-cycle.
set_multicycle_path 16 -setup -from [get_cells -hier -filter {NAME =~ *rf_reg*}] -to [get_cells -hier -filter {NAME =~ *rf_reg*}]
set_multicycle_path 15 -hold -from [get_cells -hier -filter {NAME =~ *rf_reg*}] -to [get_cells -hier -filter {NAME =~ *rf_reg*}]

## --- I/O -----------------------------------------------------------------------------
set_property -dict {PACKAGE_PIN P20 IOSTANDARD LVCMOS33} [get_ports uart_rx]
set_property -dict {PACKAGE_PIN N15 IOSTANDARD LVCMOS33} [get_ports uart_tx]
set_property -dict {PACKAGE_PIN B13 IOSTANDARD LVCMOS33} [get_ports {led[0]}]
set_property -dict {PACKAGE_PIN C13 IOSTANDARD LVCMOS33} [get_ports {led[1]}]
set_property -dict {PACKAGE_PIN D14 IOSTANDARD LVCMOS33} [get_ports {led[2]}]
set_property -dict {PACKAGE_PIN D15 IOSTANDARD LVCMOS33} [get_ports {led[3]}]
20 changes: 20 additions & 0 deletions docs/vivado_closure/vivado_build.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# vivado_build.tcl — batch build the GF-T microsequencer trainer for the AX7203.
# vivado -mode batch -source vivado_build.tcl
# Produces bpseq_vivado.bit with DETERMINISTIC timing closure (no seed-search):
# the multicycle constraint in bpseq_vivado.xdc lets a timing-driven P&R close the
# deep shared-core path that the open flow can only leave relaxed.
set part xc7a200tfbg484-1
set top top
read_verilog [list uart_bpseq.v bpseq.v gft_smul.v gft_sadd.v]
read_xdc bpseq_vivado.xdc
synth_design -top $top -part $part
opt_design
place_design
phys_opt_design
route_design
report_timing_summary -file timing_summary.rpt
# Expect: WNS >= 0 (all paths met, including the multicycle shared-core path).
set wns [get_property SLACK [get_timing_paths -max_paths 1 -nworst 1 -setup]]
puts "=== WNS (setup worst slack) = $wns ns ==="
write_bitstream -force bpseq_vivado.bit
puts "=== wrote bpseq_vivado.bit — flash with openFPGALoader, no seed-search needed ==="
Loading