Implements M4: memory_manager.v (arbitration/buffering/forwarding/ latency hiding/double buffering, §12) + prefetch_engine.v (double-buffered tile fetch, §13), sitting on the REAL, UNMODIFIED V1 PSRAM backend chain (int8_memory_access.v -> memory_interface.v -> psram_controller.v, per §15's explicit mandate not to touch the controller). Verified fully end-to-end with Verilator: real neural_processor (M1) fed entirely by memory_manager, computing against PSRAM-resident X/W tiles (double-buffered prefetch across up to 5 tiles) and writing its result back to PSRAM -- checked via an independent PSRAM read-back, with poison bytes around the operand regions to catch addressing errors. 3/3 jobs pass (1/3/5-tile configurations). Three real RTL bugs found and fixed during integration (full diagnostic trail in errors.log ERR-0006): prefetch_engine had no single-in-flight-request discipline, letting a queued request corrupt the bank bookkeeping of a fetch already running; the fix's own !pf_busy guard had a one-cycle blind spot (pf_busy lags pf_start by a clock) that needed an explicit !pf_start term; and a state-based mux for the shared backend port was off by one cycle, silently dropping the PSRAM result write entirely. Real synthesis: 0 CHECK problems, 851 LUT4/789 FF/108 CCU2C/0 DSP (expected, no multiplication in this module). Real place&route (via a synthesis-only timing harness, needed for the same TRELLIS_IO pin- budget reason as M2's array): Fmax 165.86 MHz, PASS at 80MHz. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
72 lines
3.0 KiB
Verilog
72 lines
3.0 KiB
Verilog
// ================================================================
|
|
// SYNTHESIS-ONLY TIMING HARNESS -- NOT a functional deliverable.
|
|
// Same rationale/pattern as harness_neural_processor_array.v (see its
|
|
// header and hardware/v2/logs/errors.log ERR-0005): memory_manager's
|
|
// wide ports (input_data/weight_data alone, 64 bits) exceed the
|
|
// LFE5U-45F's TRELLIS_IO budget as a bare top-level module. Drives
|
|
// them from an internal LFSR and reduces outputs to a small
|
|
// checksum, keeping only clk/rst/seed/checksum as real pins, to get
|
|
// a representative Fmax for memory_manager's own logic/routing.
|
|
// ================================================================
|
|
|
|
module harness_memory_manager #(
|
|
parameter DATA_WIDTH = 8,
|
|
parameter P_IN = 8,
|
|
parameter ADDR_WIDTH = 23
|
|
)(
|
|
input wire clk,
|
|
input wire rst,
|
|
input wire [7:0] seed,
|
|
output wire [7:0] checksum
|
|
);
|
|
|
|
reg [31:0] lfsr;
|
|
always @(posedge clk) begin
|
|
if (rst) lfsr <= {24'h0, seed} | 32'h1;
|
|
else lfsr <= {lfsr[30:0], lfsr[31] ^ lfsr[21] ^ lfsr[1] ^ lfsr[0]};
|
|
end
|
|
|
|
wire job_start = lfsr[0];
|
|
wire [ADDR_WIDTH-1:0] x_base = lfsr[ADDR_WIDTH-1:0];
|
|
wire [ADDR_WIDTH-1:0] w_base = {lfsr[7:0], lfsr[ADDR_WIDTH-9:0]};
|
|
wire [15:0] n_tiles = lfsr[15:0];
|
|
wire [ADDR_WIDTH-1:0] result_addr = {lfsr[3:0], lfsr[ADDR_WIDTH-5:0]};
|
|
wire operand_ready = lfsr[2];
|
|
wire result_valid = lfsr[3];
|
|
wire signed [DATA_WIDTH-1:0] result_data = lfsr[7:0];
|
|
wire signed [7:0] mem_rdata = lfsr[15:8];
|
|
wire mem_ready = lfsr[4];
|
|
|
|
wire job_done;
|
|
wire operand_valid;
|
|
wire signed [DATA_WIDTH*P_IN-1:0] input_data, weight_data;
|
|
wire tile_last;
|
|
wire result_ready;
|
|
wire mem_req, mem_wr;
|
|
wire [ADDR_WIDTH-1:0] mem_addr;
|
|
wire signed [7:0] mem_wdata;
|
|
|
|
memory_manager #(
|
|
.DATA_WIDTH(DATA_WIDTH), .P_IN(P_IN), .ADDR_WIDTH(ADDR_WIDTH)
|
|
) dut (
|
|
.clk(clk), .rst(rst),
|
|
.job_start(job_start), .x_base(x_base), .w_base(w_base),
|
|
.n_tiles(n_tiles), .result_addr(result_addr), .job_done(job_done),
|
|
.operand_valid(operand_valid), .operand_ready(operand_ready),
|
|
.input_data(input_data), .weight_data(weight_data), .tile_last(tile_last),
|
|
.result_valid(result_valid), .result_ready(result_ready), .result_data(result_data),
|
|
.mem_req(mem_req), .mem_wr(mem_wr), .mem_addr(mem_addr), .mem_wdata(mem_wdata),
|
|
.mem_rdata(mem_rdata), .mem_ready(mem_ready)
|
|
);
|
|
|
|
reg [7:0] chk;
|
|
always @(posedge clk) begin
|
|
if (rst) chk <= 8'h0;
|
|
else chk <= chk ^ input_data[7:0] ^ weight_data[7:0] ^ {7'h0, job_done}
|
|
^ {6'h0, tile_last, result_ready} ^ mem_addr[7:0]
|
|
^ {7'h0, mem_req} ^ {7'h0, mem_wr} ^ mem_wdata;
|
|
end
|
|
assign checksum = chk;
|
|
|
|
endmodule
|