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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user