feat: denser activation packing, real bandwidth ceiling doubled (EXP-0081)
Implements the highest-leverage fix from EXP-0080's bottleneck analysis: act_tile_fetch.v now packs 2 consecutive tiles per DDR3 burst (even tile low 64 bits, odd tile high 64 bits) instead of 1 tile per burst, halving real DDR3 bytes-per-useful-byte. Timing-safe by construction: the tile-index select bit is registered at request time, long before the real DDR3 round-trip completes, never racing the arriving read data (unlike the runtime part-select pattern EXP-0079 deliberately avoided). Re-verified at all 3 levels (isolated engine 8/8, packed_slot.v 9/9 with bit-identical results to EXP-0079, full N=2 system on real DDR3 8/8) -- the real JEDEC trace now shows no half-burst padding, direct confirmation the fix works in practice, not just in theory. Also: real device data gathered on this package's I/O bank layout (only 5 banks total, 14/15/16/34/35) informing the next bandwidth step (32-bit-wide single controller recommended over a second independent channel, given the pin/logic cost comparison). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
This commit is contained in:
@@ -120,31 +120,31 @@ module tb;
|
||||
end
|
||||
endtask
|
||||
|
||||
// ---- real activation preload (EXP-0079: act_tile_fetch.v replaces
|
||||
// the old combinational stand-in) -- one full BURST_LEN=8-word
|
||||
// burst PER TILE (act_tile_fetch.v's own real memory layout
|
||||
// convention, see that module's header), P_IN=8 bytes in the low
|
||||
// 64 bits, upper 64 bits padding. x_base(li,pos) = ACT_MEM_BASE +
|
||||
// (li*M+pos)*(N_TILES*BURST_LEN), well clear of the weight region
|
||||
// (word addresses 0..L*WORDS_PER_LAYER-1). ----
|
||||
// ---- real activation preload (EXP-0081 layout: TWO consecutive
|
||||
// tiles share one BURST_LEN=8-word burst -- even tile in the low
|
||||
// 64 bits, odd tile in the high 64 bits, see act_tile_fetch.v's
|
||||
// own header). x_base(li,pos) = ACT_MEM_BASE + (li*M+pos)*
|
||||
// (N_TILES/2*BURST_LEN), well clear of the weight region. ----
|
||||
localparam [ADDR_WIDTH-1:0] ACT_MEM_BASE = 26'h10000;
|
||||
function automatic [ADDR_WIDTH-1:0] act_x_base(input integer li, input integer pos);
|
||||
act_x_base = ACT_MEM_BASE + (li*M + pos) * (N_TILES*BURST_LEN);
|
||||
act_x_base = ACT_MEM_BASE + (li*M + pos) * ((N_TILES/2)*BURST_LEN);
|
||||
endfunction
|
||||
|
||||
task automatic preload_sdram_activations;
|
||||
integer li, pos, t, k;
|
||||
integer li, pos, tp, k;
|
||||
reg [16*BURST_LEN-1:0] burst_data;
|
||||
reg [ADDR_WIDTH-1:0] base;
|
||||
begin
|
||||
for (li = 0; li < L; li = li + 1) begin
|
||||
for (pos = 0; pos < M; pos = pos + 1) begin
|
||||
base = act_x_base(li, pos);
|
||||
for (t = 0; t < N_TILES; t = t + 1) begin
|
||||
for (tp = 0; tp < N_TILES/2; tp = tp + 1) begin // tp = burst-pair index
|
||||
burst_data = {(16*BURST_LEN){1'b0}};
|
||||
for (k = 0; k < P_IN/2; k = k + 1)
|
||||
burst_data[k*16 +: 16] = {input_byte(li, pos, t*P_IN + 2*k+1), input_byte(li, pos, t*P_IN + 2*k)};
|
||||
sdram_write_burst(base[SDRAM_ADDR_WIDTH-1:0] + t*BURST_LEN, burst_data);
|
||||
burst_data[k*16 +: 16] = {input_byte(li, pos, (2*tp)*P_IN + 2*k+1), input_byte(li, pos, (2*tp)*P_IN + 2*k)};
|
||||
for (k = 0; k < P_IN/2; k = k + 1)
|
||||
burst_data[(P_IN/2+k)*16 +: 16] = {input_byte(li, pos, (2*tp+1)*P_IN + 2*k+1), input_byte(li, pos, (2*tp+1)*P_IN + 2*k)};
|
||||
sdram_write_burst(base[SDRAM_ADDR_WIDTH-1:0] + tp*BURST_LEN, burst_data);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user