feat: real 32-bit DDR3 channel widening - functionally complete, timing NOT yet closed (EXP-0084)
Real 32-bit DDR3 widening (2x MT41J128M16JT-125:K chips ganged in parallel, user's own MIG wizard session). Full RTL adaptation across the shared ctrl bus (16-bit word -> 32-bit word, BURST_LEN=8 unchanged, burst payload 128->256 bits): - mig_native_adapter.v: app_wdf_data/app_rd_data 64->128 bits (real, confirmed against the regenerated MIG wrapper), beat count unchanged. - act_tile_fetch.v: real logic change - burst now holds 4 tiles instead of 2 (sel_lat extended to 2 registered bits, 4-way case mux instead of 2-way ternary, same request-time-registered-select discipline as EXP-0081). Not a further bytes/MAC reduction, just what's needed to keep 100% packing utilization at the larger burst. - host_mem_bridge.v: real addressing redesign - host-facing 16-bit-word contract kept unchanged (ESP32 firmware unaffected), internally translated onto the new 32-bit-native ctrl bus. - sdram_arbiter_n.v, layer_prefetch_ctrl.v, packed_slot.v, ddr_prefetch_mgr.v, n2_system_ddr3_top.v: mechanical width bump plus doubled ddr3_dq/dqs/dm pins and the real differential sys_clk/clk_ref top-level ports the regenerated MIG now requires. New burst_mem_model32.v: explicitly synthetic 32-bit test-only burst memory (the real 16-bit SDR model is genuinely fixed-width, shared by 20+ other tests, correctly not touched). Found and fixed a real address-aliasing bug in it during bring-up (MEM_ADDR_BITS=16 silently wrapped a real 0x10000 test address to 0). Real verification: all isolated testbenches re-verified (10/10, 33/33, 32/32, 7/7, 9/9 PASS), plus real xsim against the real 2-chip DDR3 model (tb_mig_native_adapter.v 12/12 PASS, tb_n2_system_ddr3.v 8/8 PASS, both chips visibly returning different real data). Real P&R: 5 real bugs found and fixed across iterations (stale single-ended MIG clock ports, a real VCCO conflict between the flash SPI bus and the differential reference clock in bank 14 - fixed by moving flash to bank 16, a stale imported XDC - same bug class as EXP-0078 but for constraints this time, missing IOSTANDARDs, and two previously-silently-broken XDC property bugs). Route completes 100%, but real timing does NOT close: WNS -0.618ns, 213 failing endpoints. Honest root cause: the violation is inside neural_processor_packed.v's own packed-MAC accumulation tree, unchanged since EXP-0059 - it has real margin at the old 155.039MHz ui_clk but not at the new 172.414MHz the paired clock-period change produced. This is NOT caused by the 32-bit width change itself. Width alone, even at the old clock, already delivers the full intended 2x bandwidth gain (1.24 -> ~2.48 GB/s) - width and clock rate are separable levers. Current trustworthy timing signoff remains EXP-0083 (16-bit, +0.073ns) until the clock period is reverted toward 3225ps (keeping Data Width=32) in one more real, user-gated MIG wizard session. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
// already measured (7.16x real memory-side speedup vs zero-reuse,
|
||||
// same hardware, see that testbench's own header).
|
||||
//
|
||||
// One layer = LAYER_BYTES bytes, fetched as LAYER_BYTES/(2*BURST_LEN)
|
||||
// One layer = LAYER_BYTES bytes, fetched as LAYER_BYTES/BYTES_PER_BURST
|
||||
// back-to-back BURST_LEN-word transactions starting at layer_base
|
||||
// (word address). Sequential -> lands in the SAME open row for any
|
||||
// layer that fits within one row (1024 columns = 256 tile-blocks at
|
||||
@@ -18,7 +18,7 @@
|
||||
// target models use), so this composes directly with EXP-0054's
|
||||
// open-row policy without needing anything special here.
|
||||
//
|
||||
// Each captured burst (ctrl_rdata, 16*BURST_LEN bits) is LATCHED
|
||||
// Each captured burst (ctrl_rdata, 32*BURST_LEN bits) is LATCHED
|
||||
// locally before draining -- does not assume the controller holds
|
||||
// rdata stable beyond the cycle `ready` pulses (its own documented
|
||||
// contract is "valid the same cycle ready pulses", nothing more).
|
||||
@@ -27,6 +27,17 @@
|
||||
// sub-counters to keep in sync, deliberately simpler than a first
|
||||
// draft of this module that tracked them separately and was harder to
|
||||
// convince correct by inspection.
|
||||
//
|
||||
// EXP-0084 (real 32-bit DDR3 channel widening): ctrl_wdata/ctrl_rdata
|
||||
// widened from the old 16-bit-word convention to 32*BURST_LEN bits
|
||||
// (BYTES_PER_BURST from 2 bytes/word*BURST_LEN to 4 bytes/word*
|
||||
// BURST_LEN) -- the ONLY real change needed, since the
|
||||
// byte-drain logic itself was already word-width-agnostic (drains
|
||||
// BYTES_PER_BURST bytes one at a time regardless of the underlying
|
||||
// word size). This is a real, deliberate exception to this file's own
|
||||
// "reused unmodified from v2" status -- the shared ctrl bus's own
|
||||
// width is a real interface contract that changed project-wide, not a
|
||||
// V3-specific choice this file could stay isolated from.
|
||||
// ============================================================
|
||||
module layer_prefetch_ctrl #(
|
||||
parameter DATA_WIDTH = 8,
|
||||
@@ -54,20 +65,20 @@ module layer_prefetch_ctrl #(
|
||||
output reg ctrl_req,
|
||||
output wire ctrl_wr, // always 0: read-only
|
||||
output reg [ADDR_WIDTH-1:0] ctrl_addr,
|
||||
output wire [16*BURST_LEN-1:0] ctrl_wdata, // unused (read-only), tied off
|
||||
output wire [2*BURST_LEN-1:0] ctrl_wmask, // unused (read-only), tied off
|
||||
input wire [16*BURST_LEN-1:0] ctrl_rdata,
|
||||
output wire [32*BURST_LEN-1:0] ctrl_wdata, // unused (read-only), tied off
|
||||
output wire [4*BURST_LEN-1:0] ctrl_wmask, // unused (read-only), tied off
|
||||
input wire [32*BURST_LEN-1:0] ctrl_rdata,
|
||||
input wire ctrl_ready,
|
||||
input wire ctrl_busy
|
||||
);
|
||||
localparam BYTES_PER_BURST = 2*BURST_LEN;
|
||||
localparam BYTES_PER_BURST = 4*BURST_LEN;
|
||||
localparam BURSTS_PER_LAYER = LAYER_BYTES/BYTES_PER_BURST;
|
||||
localparam BIDXW = (BURSTS_PER_LAYER <= 1) ? 1 : $clog2(BURSTS_PER_LAYER);
|
||||
localparam DIDXW = $clog2(BYTES_PER_BURST);
|
||||
|
||||
assign ctrl_wr = 1'b0;
|
||||
assign ctrl_wdata = {(16*BURST_LEN){1'b0}};
|
||||
assign ctrl_wmask = {(2*BURST_LEN){1'b0}};
|
||||
assign ctrl_wdata = {(32*BURST_LEN){1'b0}};
|
||||
assign ctrl_wmask = {(4*BURST_LEN){1'b0}};
|
||||
|
||||
localparam S_IDLE = 3'd0,
|
||||
S_WAIT = 3'd1,
|
||||
@@ -78,7 +89,7 @@ module layer_prefetch_ctrl #(
|
||||
reg [BIDXW-1:0] burst_idx;
|
||||
reg [DIDXW-1:0] drain_cnt;
|
||||
reg [ADDR_WIDTH-1:0] base_lat;
|
||||
reg [16*BURST_LEN-1:0] burst_lat;
|
||||
reg [32*BURST_LEN-1:0] burst_lat;
|
||||
|
||||
// combinational: which byte of the layer is currently being drained
|
||||
wire [BUFADDRW-1:0] cur_fill_addr = burst_idx * BYTES_PER_BURST + drain_cnt;
|
||||
@@ -96,7 +107,7 @@ module layer_prefetch_ctrl #(
|
||||
burst_idx <= {BIDXW{1'b0}};
|
||||
drain_cnt <= {DIDXW{1'b0}};
|
||||
base_lat <= {ADDR_WIDTH{1'b0}};
|
||||
burst_lat <= {(16*BURST_LEN){1'b0}};
|
||||
burst_lat <= {(32*BURST_LEN){1'b0}};
|
||||
end else begin
|
||||
ctrl_req <= 1'b0;
|
||||
fill_we <= 1'b0;
|
||||
|
||||
Reference in New Issue
Block a user