fix: propagate runtime-indexed-crossbar fix to slot_mem_arbiter(_wide) + dataflow_core mux

DEC-0043: slot_mem_arbiter.v/slot_mem_arbiter_wide.v both still had the
exact runtime-variable-indexed part-select anti-pattern
(pending_addr[grant_idx*ADDR_WIDTH +: ADDR_WIDTH], grant_idx a runtime
register) that neural_director.v had already found and fixed once
before -- ADDR_WIDTH=26 not being a power of 2 means this synthesizes
as a real multiplier + wide crossbar, sitting right on the
arbiter<->backend boundary this project's own N=8 congestion diagnosis
names, growing with N_PORTS=N_SLOTS(+1). Also fixed the cheaper but
same-class dir_job_out_slot*16 mux in nms_dataflow_core_sdram.v,
feeding directly into dependency_manager -- this exact signal was
DEC-0042's own diagnosed N=4 critical path.

Fix: N_PORTS/N_SLOTS parallel constant-indexed comparisons (unrolled
for-loop) instead of a runtime-indexed read -- same technique already
proven in neural_director.v. Purely an internal-implementation change.

Verified bit-exact via Verilator: tb_fpga_neural_v2_top_smoke.v 11/11
PASS; tb_nms_dstress_sdram_unified.v (256-neuron stress) at both
N_SLOTS_CFG=4 and =8, 256/256 bit-exact vs golden, total_cycles
IDENTICAL to pre-fix historical values (49927/49909, exact match to
DEC-0042's own recorded numbers).

Bonus finding from the same D-Stress run (not this commit's main
point, logged for Phase 3/4): sdram_busy_cycles ~81.6% and
useful-MAC-cycle fraction HALVING from N=4 to N=8 (2.04%->1.02%) --
real existing evidence the system is memory-bound on a single SDRAM
bank well before N=8, independent of Fmax.

Re-synthesis (8-seed sweep, N=4/N=8) in progress to measure the actual
Fmax delta from this fix -- committed separately once complete.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 22:39:00 +00:00
co-authored by Claude Sonnet 5
parent 19ef54aea8
commit 6a46dc857f
5 changed files with 204 additions and 14 deletions
+41 -6
View File
@@ -111,6 +111,39 @@ module slot_mem_arbiter_wide #(
end
end
// grant_idx-selected pending fields, read out via N_PORTS parallel
// CONSTANT-indexed comparisons (`gi` is the for-loop's own unrolled
// constant, not a runtime value) instead of a runtime-indexed part-
// select of a wide packed array -- same fix class already applied
// in neural_director.v (see that file's own header comment): a
// variable-indexed read/write of a wide packed array synthesizes as
// a real multiplier (index * ADDR_WIDTH, ADDR_WIDTH=26 not a power
// of 2) feeding a wide demux/crossbar, measurably worse as
// ADDR_WIDTH/N_PORTS grow -- exactly the arbiter<->backend boundary
// this project's own N=8 congestion diagnosis names. Functionally
// IDENTICAL to the old `pending_*[grant_idx]` reads (exactly one gi
// matches grant_idx whenever any_pending is set).
reg grant_wr_c, grant_lb_n_c, grant_ub_n_c;
reg [ADDR_WIDTH-1:0] grant_addr_c;
reg [DATA_WIDTH-1:0] grant_wdata_c;
integer gi;
always @(*) begin
grant_wr_c = 1'b0;
grant_lb_n_c = 1'b1;
grant_ub_n_c = 1'b1;
grant_addr_c = {ADDR_WIDTH{1'b0}};
grant_wdata_c = {DATA_WIDTH{1'b0}};
for (gi = 0; gi < N_PORTS; gi = gi + 1) begin
if (grant_idx == gi[PIDXW-1:0]) begin
grant_wr_c = pending_wr[gi];
grant_lb_n_c = pending_lb_n[gi];
grant_ub_n_c = pending_ub_n[gi];
grant_addr_c = pending_addr[gi*ADDR_WIDTH +: ADDR_WIDTH];
grant_wdata_c = pending_wdata[gi*DATA_WIDTH +: DATA_WIDTH];
end
end
end
integer pi;
always @(posedge clk) begin
@@ -157,12 +190,14 @@ module slot_mem_arbiter_wide #(
if (any_pending) begin
owner <= grant_idx + 1'b1;
m_req <= 1'b1;
m_wr <= pending_wr[grant_idx];
m_lb_n <= pending_lb_n[grant_idx];
m_ub_n <= pending_ub_n[grant_idx];
m_addr <= pending_addr[grant_idx*ADDR_WIDTH +: ADDR_WIDTH];
m_wdata <= pending_wdata[grant_idx*DATA_WIDTH +: DATA_WIDTH];
pending[grant_idx] <= 1'b0;
m_wr <= grant_wr_c;
m_lb_n <= grant_lb_n_c;
m_ub_n <= grant_ub_n_c;
m_addr <= grant_addr_c;
m_wdata <= grant_wdata_c;
for (pi = 0; pi < N_PORTS; pi = pi + 1) begin
if (grant_idx == pi[PIDXW-1:0]) pending[pi] <= 1'b0;
end
end
end else begin
if (m_ready) begin