feat: integrate flash #1 (neural-network data) RTL into V2 top-level
Closes the flash #1 RTL gap flagged in DEC-0041: real, unmodified V1 subsystem (flash_slot_manager.v/flash_copy_engine.v/spi_flash_master.v/ crc32.v) now instantiated in fpga_neural_v2_top.v, bridged to the AR memory bus via a new flash_mem_adapter.v (byte<->word, matches nms_memory_manager_stream_wide.v's own real masking convention), and commandable over SPI via a new spi_host_bridge.v opcode (OP_FLASH_CMD, 0x30) using the same byte-counting idiom as OP_WRITE_JOB. Real balls now in the LPF: flash_sclk=B2, flash_mosi=E2, flash_miso=F2, flash_cs_n=F3. New tb_flash_integration_smoke.v: real SPI-triggered OP_FLASH_READ_BLOCK verified bit-exact (64/64 bytes) against a real V1 flash_model.v instance, through the new adapter and the widened (2->3 port) host-arb arbiter; WRITE_JOB regression confirms the new 3rd port doesn't disturb existing traffic. Full existing regression re-run clean: D-Stress N=4/ N=8 (bit-exact + data_ready PASS), board-level smoke test (11/11), isolated spi_host_bridge test (18/18). Honest, disclosed finding: a full 8-seed P&R re-verification shows N_SLOTS=4 @ 64MHz regressed from 8/8 to 3/8 PASS (worst 60.18MHz). Root cause traced via the real critical-path report: the SAME pre-existing arbiter-to-sdram-backend bottleneck already documented all session, made worse by flash's added die-area placement pressure -- not a new path through the flash logic itself. N_SLOTS=8 essentially unchanged (6/8, was 5/8). See decisions.log DEC-0042 for full detail and open decision points. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
// ================================================================
|
||||
// FLASH_MEM_ADAPTER -- bridges flash_slot_manager.v's real, unmodified
|
||||
// V1 "Port D" (PSRAM-style byte interface: d_req/d_wr/d_addr/d_wdata/
|
||||
// d_rdata/d_ready, byte-addressed, 8-bit signed data) to V2's real AR-
|
||||
// port convention (word address, 16-bit data, lb_n/ub_n byte lane
|
||||
// masking) used by slot_mem_arbiter.v's clients.
|
||||
//
|
||||
// Byte<->word convention matches nms_memory_manager_stream_wide.v's
|
||||
// own real, already-verified result-writeback logic EXACTLY (not
|
||||
// invented): word_addr = byte_addr[ADDR_WIDTH-1:1], byte_addr[0]==0
|
||||
// selects the LOWER lane (lb_n=0,ub_n=1), byte_addr[0]==1 selects the
|
||||
// UPPER lane (lb_n=1,ub_n=0); write data is replicated to both halves
|
||||
// of the 16-bit word, the mask picks which half the SDRAM controller
|
||||
// actually writes.
|
||||
//
|
||||
// Simple valid/ready passthrough: request held (s_req) from issue
|
||||
// until the arbiter/backend returns s_ready, matching the same
|
||||
// "hold, don't pulse" idiom already used throughout this project
|
||||
// (nms_memory_manager_stream_wide.v, spi_host_bridge.v's own mem_req).
|
||||
// ================================================================
|
||||
module flash_mem_adapter #(
|
||||
parameter ADDR_WIDTH = 26, // AR-side word-address bus width
|
||||
parameter BYTE_ADDR_WIDTH = 26 // flash_slot_manager's own PSRAM_ADDR_WIDTH
|
||||
)(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
// ---- flash_slot_manager's own real "Port D" ----
|
||||
input wire d_req,
|
||||
input wire d_wr,
|
||||
input wire [BYTE_ADDR_WIDTH-1:0] d_addr,
|
||||
input wire signed [7:0] d_wdata,
|
||||
output reg signed [7:0] d_rdata,
|
||||
output reg d_ready,
|
||||
|
||||
// ---- AR-port-style client, into slot_mem_arbiter.v ----
|
||||
output reg s_req,
|
||||
output reg s_wr,
|
||||
output reg [ADDR_WIDTH-1:0] s_addr,
|
||||
output reg [15:0] s_wdata,
|
||||
output reg s_lb_n,
|
||||
output reg s_ub_n,
|
||||
input wire [15:0] s_rdata,
|
||||
input wire s_ready
|
||||
);
|
||||
|
||||
reg pending;
|
||||
reg lane;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
s_req <= 1'b0;
|
||||
s_wr <= 1'b0;
|
||||
s_addr <= {ADDR_WIDTH{1'b0}};
|
||||
s_wdata <= 16'h0;
|
||||
s_lb_n <= 1'b1;
|
||||
s_ub_n <= 1'b1;
|
||||
d_ready <= 1'b0;
|
||||
d_rdata <= 8'sd0;
|
||||
pending <= 1'b0;
|
||||
lane <= 1'b0;
|
||||
end else begin
|
||||
d_ready <= 1'b0;
|
||||
if (!pending && d_req) begin
|
||||
s_req <= 1'b1;
|
||||
s_wr <= d_wr;
|
||||
s_addr <= d_addr[BYTE_ADDR_WIDTH-1:1];
|
||||
lane <= d_addr[0];
|
||||
s_wdata <= d_addr[0] ? {d_wdata, 8'h00} : {8'h00, d_wdata};
|
||||
s_lb_n <= d_addr[0] ? 1'b1 : 1'b0;
|
||||
s_ub_n <= d_addr[0] ? 1'b0 : 1'b1;
|
||||
pending <= 1'b1;
|
||||
end else if (pending && s_ready) begin
|
||||
s_req <= 1'b0;
|
||||
d_rdata <= lane ? s_rdata[15:8] : s_rdata[7:0];
|
||||
d_ready <= 1'b1;
|
||||
pending <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user