diff --git a/docs/NOW.md b/docs/NOW.md index 2b27acaa2..9746919a2 100644 --- a/docs/NOW.md +++ b/docs/NOW.md @@ -1,7 +1,14 @@ -# NOW — docs: a slower clock is not the fix; pipelining is (2026-08-08) +# NOW — docs: localized the shared-core deep path (GftSadd=54, GftSmul=44) (2026-08-08) Last updated: 2026-08-08 +## docs: localized the shared-core critical depth — pipeline the normalize/round cascade, not the multiplier (Refs #1764) + +- Measured where the deep combinational path actually is, so the pipeline cut lands in the right place. `GftSmul` is purely combinational (`assign result = smul(a,b)`; clk/en/ready unused → no read-before-ready bug). Yosys `ltp` puts the shared-core critical depth at `GftSadd` = 54 and `GftSmul` = 44 +- The depth is NOT the multiplier width: `magmul`'s `*` lowers to a 32-iteration shift-add, but operands are `512+mant ∈ [512,1023]` (10-bit), so yosys already prunes the dead upper iterations — hand-narrowing the loop to 10 leaves depth unchanged (44→45) and area flat. Tested this BEFORE touching the verified spec (observe-before-mutate); narrowing the multiply is a dead end +- The real depth is the dependent normalize/round cascade: `magsub`'s 4-stage priority-shift + `<<14` fixed-point + RNE in `GftSadd`, and `magmul`'s post-product RNE carry in `GftSmul`. Concrete pipeline cut: split each cascade into TWO registered stages (~27 / ~22 deep), which both halves the path and resynchronises it (kills the placement hazard); the microsequencer then waits a fixed 2-cycle latency instead of a settle counter +- Reinforces why neither slow-clock nor path-shortening fixes it: the ~47 ns nominal path is already ~100× under the µs settle window, so the glitch is a placement hazard invisible to static timing — only a mid-cascade register addresses it. Documented in `docs/SILICON_TRAINING_METHODOLOGY.md`. Docs only. Refs #1764 + ## docs: a slower clock cannot fix the seed-lottery — pipelining the shared core is the only structural fix (Refs #1764) - Investigated the "just run the deep path on a slower clock" remedy and ruled it out on TWO independent grounds. (a) NOT buildable on openXC7: a fabric-counter divided clock needs a clock buffer, and nextpnr-xilinx cannot place one driven from fabric — both `BUFG` and `BUFR` fed by a divider bit fail with "Unable to find legal placement" (7-series clock-buffer inputs come from clock-capable pins / the CMT, not general routing). Only an MMCM/PLL could make a real divided clock diff --git a/docs/SILICON_TRAINING_METHODOLOGY.md b/docs/SILICON_TRAINING_METHODOLOGY.md index 302728855..b0833c92d 100644 --- a/docs/SILICON_TRAINING_METHODOLOGY.md +++ b/docs/SILICON_TRAINING_METHODOLOGY.md @@ -102,6 +102,23 @@ no Docker, native macOS arm64. 200 MHz. This is a code/spec change, not a clock or constraint change. It is the prerequisite for training nets larger than XOR on this open flow (where seed-search runs out — a 62-step net does not stabilise in any seed). +- **Where the depth actually is (measured, so we pipeline the right place).** `GftSmul` + is purely combinational (`assign result = smul(a,b)`; the `clk`/`en`/`ready` ports are + unused, so there is no read-before-ready bug). Yosys `ltp` (longest topological path) + puts the shared-core critical depth at **`GftSadd` = 54** and **`GftSmul` = 44**. The + depth is *not* the multiplier width: the `*` in `magmul` lowers to a 32-iteration + shift-add, but its operands are `512+mant ∈ [512,1023]` (10-bit), so yosys prunes the + dead upper iterations — hand-narrowing the loop to 10 leaves the depth unchanged (44 → + 45) and the area flat, so **narrowing the multiply is a dead end** (tested before + touching the verified spec). The real depth is the *dependent normalize/round cascade*: + `magsub`'s 4-stage priority-shift + `<<14` fixed-point + round-to-nearest-even in + `GftSadd`, and `magmul`'s post-product RNE carry in `GftSmul`. So the pipeline cut is + concrete: split each of those cascades into **two registered stages** (~27 and ~22 deep), + which both halves the path *and* resynchronises it — the microsequencer then waits the + fixed 2-cycle latency instead of a `settle` counter. Note the ~47 ns nominal path is + already ~100× under the µs settle window, which is why the glitch is a *placement hazard* + a static-timing fix cannot see, and only a mid-cascade register (resynchronisation) + addresses. ## Reproducibility