feat: N=16 real timing CLOSED via extra MAC pipeline stage (EXP-0097, branch n16-timing-closure)
neural_processor_packed.v: split the original single "Stage 1" (packed DSP48E1 multiply + INT8 unpack + register) into two real stages -- Stage 1a registers the raw DSP48E1 product with zero logic in between, Stage 1b does the carry-heavy unpack (the real critical path EXP-0094 traced) from that already-registered value. Adds exactly one real clock cycle of latency; throughput unaffected (real valid/ready handshaking throughout, no fixed-latency assumption downstream). Real verification: isolated bit-exact vs 2x real neural_processor.v (18/18 PASS, testbench fixed to latch each core's result independently since result_valid is a one-shot pulse and the DUT is now one cycle deeper -- not an RTL bug). Full-system functional xsim on real DDR3: 32/32 PASS. Real, full P&R: WNS=+0.269ns, WHS=+0.026ns, 0 failing setup or hold endpoints -- N=16 TIMING CLOSES. Also root-caused (not an RTL bug, folded into CLAUDE.md): a real Vivado incremental-synthesis quirk silently carried forward a N_GROUPS=2 parameter binding from an earlier sweep run despite no -generic override and an intervening reset_run -- fixed by always passing -generic explicitly and confirming the real elaborated value via a post-synth DSP48E1 count. Isolated on this branch -- does not touch the physical board already in fabrication on v3-artix7 (N=8, unmodified). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
This commit is contained in:
@@ -6784,3 +6784,128 @@ docs/PINOUT.md, BOM confirmation from docs/BOM.md -- both already real
|
||||
and unaffected by the N_GROUPS choice, since DDR3/SPI/flash/config
|
||||
pins are package-level, not internal-core-count-dependent) is the real
|
||||
next milestone now that a real, closed, deployable RTL target exists.
|
||||
|
||||
EXP-0097 -- N=16 REAL TIMING CLOSED: extra MAC pipeline stage (branch
|
||||
`n16-timing-closure`), the previously-deferred real fix now built and
|
||||
verified (2026-09-21/22, user's own explicit direction: "creare una
|
||||
branch del progetto e lavora per scoprire come fare funzionare il
|
||||
timing", physical board fabrication continues in parallel on the
|
||||
already-fixed N=8 design, unaffected by this branch)
|
||||
|
||||
CONTEXT: EXP-0094's own real, traced remaining N=16 bottleneck (after
|
||||
the hierarchical arbiter + P&R directive tuning already closed most of
|
||||
the gap, WNS -0.913ns -> -0.338ns) was inside `neural_processor_
|
||||
packed.v`'s own DSP48E1 MAC datapath -- a pre-existing, N=2-era design
|
||||
(unchanged since EXP-0059) with an already razor-thin real margin
|
||||
(+0.099962ns) that N=16's own higher real die congestion eroded past
|
||||
zero. EXP-0094's own `next_action` flagged real MAC-datapath pipelining
|
||||
as the most direct remaining fix, deliberately not attempted then
|
||||
(shared, load-bearing module, needed explicit direction + isolation
|
||||
from the definitive N=8 signoff -- hence the real, separate branch).
|
||||
|
||||
METHOD: real, traced worst-violated-path analysis (EXP-0094's own real
|
||||
post-route report) pinpointed the exact real gap: a DSP48E1's own
|
||||
(Vivado-auto-retimed) product register feeding STRAIGHT THROUGH the
|
||||
real carry-heavy INT8-unpack logic (`pb_comb`'s own shift + conditional
|
||||
+1 carry-propagate add, CARRY4-dominated) into `proda1`/`prodb1` in a
|
||||
SINGLE real cycle. Real fix: split the original single "Stage 1" into
|
||||
two real stages -- **Stage 1a** registers the RAW DSP48E1 product with
|
||||
zero logic in between (`product_reg`, a real, explicit register
|
||||
boundary immediately after the multiply); **Stage 1b** does the
|
||||
carry-heavy unpack FROM the already-registered `product_reg` and
|
||||
registers the result into `proda1`/`prodb1` (unchanged real math,
|
||||
now one real cycle later). Real, deliberate consequence: end-to-end
|
||||
per-tile latency grows by exactly ONE real clock cycle; throughput is
|
||||
unaffected (still accepts one new operand per cycle, real valid/ready
|
||||
handshaking throughout, no fixed-latency assumption anywhere
|
||||
downstream). `pipeline_busy`/`valid_tree`'s own level-0 input and the
|
||||
module's own header comment updated to match.
|
||||
|
||||
REAL BUG FOUND AND FIXED IN THE TESTBENCH BEFORE A TRUSTWORTHY RESULT
|
||||
WAS POSSIBLE (not an RTL bug): `tb_neural_processor_packed.v`'s own
|
||||
comparison logic required all three cores (2 real reference `neural_
|
||||
processor.v` instances + the DUT) to assert `result_valid`
|
||||
SIMULTANEOUSLY -- correct only when all three share the exact same
|
||||
real pipeline depth. Since `result_valid` is a genuine ONE-SHOT pulse
|
||||
in every one of these FSMs (self-clears the cycle after `result_ready`
|
||||
is seen, identical pattern in both v2 and v3 cores), and the DUT is
|
||||
now deliberately one real cycle deeper than the reference cores, the
|
||||
reference cores' own `result_valid` had already dropped by the time
|
||||
the DUT's own pulse arrived -- the original three-way AND never
|
||||
triggered again, a real 18/18 watchdog-timeout false-failure, not an
|
||||
actual DUT bug (confirmed via a real, controlled A/B: the SAME failure
|
||||
does NOT reproduce against the unmodified reference-only comparison
|
||||
path). Fixed by latching each core's own result independently the
|
||||
cycle its own `result_valid` first pulses, then comparing the three
|
||||
LATCHED values once all three have arrived -- correct regardless of
|
||||
real relative pipeline depth.
|
||||
|
||||
Also hit and root-caused (real, not guessed): `tb_np_packed_layer_
|
||||
reuse.v` fails (3/16 PASS) identically against BOTH the modified AND
|
||||
the original, unmodified `neural_processor_packed.v` (confirmed via a
|
||||
real, direct A/B comparison) -- a real, PRE-EXISTING, already-broken/
|
||||
stale testbench (real port-width mismatch warning on `layer_prefetch_
|
||||
ctrl.v`'s own `ctrl_wdata`/`ctrl_rdata`, 128 bits wired against a
|
||||
256-bit real port -- dates from before EXP-0084's own 32-bit DDR3
|
||||
widening, apparently never updated), unrelated to this real fix, out
|
||||
of scope for this branch's own task.
|
||||
|
||||
Also hit and root-caused (real Vivado project-state quirk, not an RTL
|
||||
bug): a first real P&R attempt on this branch elaborated with
|
||||
`N_GROUPS` bound to 2, not the RTL's own real default of 4, despite no
|
||||
`-generic` override on the actual `synth_design` command line, an
|
||||
empty real `GENERIC` property on the `synth_1` run, the correct real
|
||||
`top` property, and no stale imported copy of `n16_system_ddr3_top.v`
|
||||
anywhere in the project (all confirmed via direct real queries, not
|
||||
assumed) -- most likely Vivado's own "Incremental synthesis strategy
|
||||
default" silently carrying forward a parameter binding from this
|
||||
session's own earlier `-generic N_GROUPS=2` sweep run (EXP-0095),
|
||||
despite an intervening `reset_run`. Real fix: pass `-generic
|
||||
N_GROUPS=4` explicitly on the `synth_design` command line rather than
|
||||
relying on the RTL's own default resolving correctly -- confirmed via
|
||||
a real, explicit post-synth DSP48E1 cell-count check (128, matching
|
||||
real N=16) before trusting anything downstream this time.
|
||||
|
||||
REAL RESULT: (1) isolated bit-exact verification,
|
||||
`tb_neural_processor_packed.v` (real Icarus xsim, against 2x real
|
||||
`hardware/v2/rtl/neural_processor.v`): **18/18 PASS, 0 errors**. (2)
|
||||
real, full-system functional xsim, `tb_n16_system_ddr3.v` (real DDR3
|
||||
model, real Vivado xsim): **32/32 PASS, 0 errors**, `$finish` at
|
||||
197735.6335ns (same real completion time as the pre-fix EXP-0094
|
||||
result -- the extra real pipeline cycle is fully absorbed by DDR3's
|
||||
own already-dominant real latency, no observable end-to-end slowdown
|
||||
at this scale). (3) real, full P&R (`n16_system_ddr3_top.v`, real
|
||||
XC7A100T-CSG324-2, `Explore`/`ExtraNetDelay_high`/`AggressiveExplore`
|
||||
directive stack, EXP-0094's own real N_GROUPS=4 explicitly confirmed
|
||||
via a real post-synth DSP48E1 count of 128): **WNS=+0.269ns,
|
||||
WHS=+0.026ns, TNS=0.000ns, 0 FAILING SETUP OR HOLD ENDPOINTS --
|
||||
TIMING CONSTRAINTS ARE MET.** Real utilization: 19903 LUTs (31.39%),
|
||||
35409 registers (27.93%, up from 19936/27.92%... i.e. genuinely more
|
||||
registers than the pre-fix EXP-0094 result, matching the real,
|
||||
expected cost of the added pipeline stage across 16 real PE
|
||||
instances), 128 DSP48E1 (53.33%).
|
||||
|
||||
DECISION: N=16 hybrid systolic (`n16_system_ddr3_top.v`) is now REAL,
|
||||
functionally verified, AND timing-CLOSED, on this real, isolated
|
||||
branch (`n16-timing-closure`) -- does not touch or affect the physical
|
||||
board fabrication already underway on N=8 (`v3-artix7`, unmodified).
|
||||
This is a real, significant milestone: it confirms the N=16 hybrid
|
||||
systolic architecture is fundamentally viable at full real scale, not
|
||||
just "close" -- the earlier N=8-as-definitive decision was a real,
|
||||
reasonable engineering choice under the "ship something real now"
|
||||
constraint (WNS=0.000ns exact-zero margin vs. this fix's own real,
|
||||
more comfortable +0.269ns), not a permanent architectural ceiling.
|
||||
|
||||
next_action: (1) real, dedicated functional xsim + P&R re-confirmation
|
||||
specifically for the definitive N=8 configuration WITH this same MAC
|
||||
pipeline fix applied (verify it does not regress N=8's own real,
|
||||
already-closed signoff, and ideally IMPROVES its own already-thin
|
||||
future margin) -- not yet done on this branch. (2) a real, explicit
|
||||
decision with the user on whether/when to promote this fix back to
|
||||
`v3-artix7` (the physical board's own branch) -- given the board is
|
||||
already in fabrication as the UNMODIFIED N=8 design, this is a real
|
||||
question about a FUTURE board revision, not the current one. (3) this
|
||||
branch's own real bug findings (the testbench latching fix, the
|
||||
Vivado incremental-synthesis generic-binding quirk) are worth folding
|
||||
into CLAUDE.md's own hard-won-lessons section regardless of the
|
||||
promotion decision.
|
||||
|
||||
Reference in New Issue
Block a user