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:
@@ -77,6 +77,14 @@ module fpga_neural_v2_top #(
|
||||
// see nms_dataflow_core_sdram.v for the full design comment.
|
||||
output wire data_ready,
|
||||
|
||||
// ---- Flash #1 (neural-network weights/graph data): real,
|
||||
// ordinary GPIO SPI bus, physically separate from flash #2 (boot)
|
||||
// -- see decisions.log for the two-flash architecture rationale.
|
||||
output wire flash_sclk,
|
||||
output wire flash_mosi,
|
||||
input wire flash_miso,
|
||||
output wire flash_cs_n,
|
||||
|
||||
output wire pll_locked
|
||||
);
|
||||
|
||||
@@ -114,6 +122,13 @@ module fpga_neural_v2_top #(
|
||||
wire [15:0] host_mem_wdata, host_mem_rdata;
|
||||
wire host_mem_ready;
|
||||
|
||||
wire flash_op_start;
|
||||
wire [2:0] flash_op_code;
|
||||
wire [3:0] flash_slot_id;
|
||||
wire [23:0] flash_new_offset, flash_new_length, flash_ext_length, flash_raw_flash_addr;
|
||||
wire [7:0] flash_new_type;
|
||||
wire [ADDR_WIDTH-1:0] flash_ext_addr;
|
||||
|
||||
spi_host_bridge #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH), .N_NODES(N_NODES), .MAX_DEPS(MAX_DEPS)
|
||||
) u_spi_bridge (
|
||||
@@ -126,7 +141,13 @@ module fpga_neural_v2_top #(
|
||||
.mem_req(host_mem_req), .mem_wr(host_mem_wr), .mem_addr(host_mem_addr),
|
||||
.mem_wdata(host_mem_wdata), .mem_lb_n(host_mem_lb_n), .mem_ub_n(host_mem_ub_n),
|
||||
.mem_rdata(host_mem_rdata), .mem_ready(host_mem_ready),
|
||||
.soft_rst_pulse(soft_rst_pulse)
|
||||
.soft_rst_pulse(soft_rst_pulse),
|
||||
.flash_op_start(flash_op_start), .flash_op_code(flash_op_code),
|
||||
.flash_slot_id(flash_slot_id), .flash_new_offset(flash_new_offset),
|
||||
.flash_new_length(flash_new_length), .flash_new_type(flash_new_type),
|
||||
.flash_ext_addr(flash_ext_addr), .flash_ext_length(flash_ext_length),
|
||||
.flash_raw_flash_addr(flash_raw_flash_addr),
|
||||
.flash_busy(flash1_busy), .flash_done(flash1_done), .flash_err(flash1_err)
|
||||
);
|
||||
|
||||
// ============================================================
|
||||
@@ -183,24 +204,33 @@ module fpga_neural_v2_top #(
|
||||
.m_rdata(arb_m_rdata), .m_ready(arb_m_ready)
|
||||
);
|
||||
|
||||
// ---- AR level 2 (NEW, STEP20): compute-side AR stream (port0)
|
||||
// vs. SPI host raw memory port (port1) -- reuses slot_mem_arbiter
|
||||
// completely unchanged, just at N_PORTS=2, its own already-proven
|
||||
// pending-latch discipline applying equally to a 2-port instance ----
|
||||
wire [1:0] host_arb_s_req, host_arb_s_wr, host_arb_s_lb_n, host_arb_s_ub_n, host_arb_s_ready;
|
||||
wire [ADDR_WIDTH*2-1:0] host_arb_s_addr;
|
||||
wire [16*2-1:0] host_arb_s_wdata, host_arb_s_rdata;
|
||||
// ---- AR level 2 (STEP20/STEP21): compute-side AR stream (port0,
|
||||
// highest priority) vs. SPI host raw memory port (port1) vs.
|
||||
// flash #1 (neural-network data) port (port2, lowest priority --
|
||||
// matches V1's own "Port D, lowest priority" convention for this
|
||||
// exact traffic class) -- reuses slot_mem_arbiter completely
|
||||
// unchanged, just at N_PORTS=3, its own already-proven pending-
|
||||
// latch discipline applying equally to a 3-port instance ----
|
||||
wire flash_ar_req, flash_ar_wr, flash_ar_lb_n, flash_ar_ub_n, flash_ar_ready;
|
||||
wire [ADDR_WIDTH-1:0] flash_ar_addr;
|
||||
wire [15:0] flash_ar_wdata, flash_ar_rdata;
|
||||
|
||||
assign host_arb_s_req = {host_mem_req, arb_m_req};
|
||||
assign host_arb_s_wr = {host_mem_wr, arb_m_wr};
|
||||
assign host_arb_s_lb_n = {host_mem_lb_n, arb_m_lb_n};
|
||||
assign host_arb_s_ub_n = {host_mem_ub_n, arb_m_ub_n};
|
||||
assign host_arb_s_addr = {host_mem_addr, arb_m_addr};
|
||||
assign host_arb_s_wdata = {host_mem_wdata, arb_m_wdata};
|
||||
wire [2:0] host_arb_s_req, host_arb_s_wr, host_arb_s_lb_n, host_arb_s_ub_n, host_arb_s_ready;
|
||||
wire [ADDR_WIDTH*3-1:0] host_arb_s_addr;
|
||||
wire [16*3-1:0] host_arb_s_wdata, host_arb_s_rdata;
|
||||
|
||||
assign host_arb_s_req = {flash_ar_req, host_mem_req, arb_m_req};
|
||||
assign host_arb_s_wr = {flash_ar_wr, host_mem_wr, arb_m_wr};
|
||||
assign host_arb_s_lb_n = {flash_ar_lb_n, host_mem_lb_n, arb_m_lb_n};
|
||||
assign host_arb_s_ub_n = {flash_ar_ub_n, host_mem_ub_n, arb_m_ub_n};
|
||||
assign host_arb_s_addr = {flash_ar_addr, host_mem_addr, arb_m_addr};
|
||||
assign host_arb_s_wdata = {flash_ar_wdata, host_mem_wdata, arb_m_wdata};
|
||||
assign arb_m_ready = host_arb_s_ready[0];
|
||||
assign arb_m_rdata = host_arb_s_rdata[15:0];
|
||||
assign host_mem_ready = host_arb_s_ready[1];
|
||||
assign host_mem_rdata = host_arb_s_rdata[31:16];
|
||||
assign flash_ar_ready = host_arb_s_ready[2];
|
||||
assign flash_ar_rdata = host_arb_s_rdata[47:32];
|
||||
|
||||
wire final_ar_req, final_ar_wr;
|
||||
wire [ADDR_WIDTH-1:0] final_ar_addr;
|
||||
@@ -210,7 +240,7 @@ module fpga_neural_v2_top #(
|
||||
wire final_ar_ready;
|
||||
|
||||
slot_mem_arbiter #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH), .N_PORTS(2)
|
||||
.ADDR_WIDTH(ADDR_WIDTH), .N_PORTS(3)
|
||||
) u_host_arb (
|
||||
.clk(clk), .rst(core_rst),
|
||||
.s_req(host_arb_s_req), .s_wr(host_arb_s_wr), .s_addr(host_arb_s_addr),
|
||||
@@ -221,6 +251,46 @@ module fpga_neural_v2_top #(
|
||||
.m_rdata(final_ar_rdata), .m_ready(final_ar_ready)
|
||||
);
|
||||
|
||||
// ---- Flash #1 (neural-network weights/graph data): real,
|
||||
// unmodified V1 subsystem (flash_slot_manager.v, which owns
|
||||
// flash_copy_engine.v, which owns spi_flash_master.v; crc32.v used
|
||||
// internally too) -- see decisions.log for the integration design.
|
||||
// Command interface driven by spi_host_bridge.v's own new
|
||||
// OP_FLASH_CMD opcode. Data path bridged into the AR arbiter above
|
||||
// via flash_mem_adapter.v (byte<->word, matches nms_memory_
|
||||
// manager_stream_wide.v's own real masking convention). ----
|
||||
wire flash_d_req, flash_d_wr, flash_d_ready;
|
||||
wire [ADDR_WIDTH-1:0] flash_d_addr;
|
||||
wire signed [7:0] flash_d_wdata, flash_d_rdata;
|
||||
wire flash1_busy, flash1_done, flash1_err;
|
||||
|
||||
flash_slot_manager #(
|
||||
.PSRAM_ADDR_WIDTH(ADDR_WIDTH), .CLK_FREQ_MHZ(64), .SCLK_DIV(2)
|
||||
) u_flash1 (
|
||||
.clk(clk), .rst(core_rst),
|
||||
.mosi(flash_mosi), .miso(flash_miso), .cs_n(flash_cs_n), .sclk(flash_sclk),
|
||||
.op_start(flash_op_start), .op_code(flash_op_code), .slot_id(flash_slot_id),
|
||||
.new_offset(flash_new_offset), .new_length(flash_new_length), .new_type(flash_new_type),
|
||||
.ext_psram_addr(flash_ext_addr), .ext_length(flash_ext_length),
|
||||
.raw_flash_addr(flash_raw_flash_addr),
|
||||
.busy(flash1_busy), .done(flash1_done), .err(flash1_err),
|
||||
.cat_read_sel(4'd0), .cat_out_offset(), .cat_out_length(),
|
||||
.cat_out_type(), .cat_out_valid(), .cat_out_crc(),
|
||||
.d_req(flash_d_req), .d_wr(flash_d_wr), .d_addr(flash_d_addr),
|
||||
.d_wdata(flash_d_wdata), .d_rdata(flash_d_rdata), .d_ready(flash_d_ready)
|
||||
);
|
||||
|
||||
flash_mem_adapter #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH), .BYTE_ADDR_WIDTH(ADDR_WIDTH)
|
||||
) u_flash_adapter (
|
||||
.clk(clk), .rst(core_rst),
|
||||
.d_req(flash_d_req), .d_wr(flash_d_wr), .d_addr(flash_d_addr),
|
||||
.d_wdata(flash_d_wdata), .d_rdata(flash_d_rdata), .d_ready(flash_d_ready),
|
||||
.s_req(flash_ar_req), .s_wr(flash_ar_wr), .s_addr(flash_ar_addr),
|
||||
.s_wdata(flash_ar_wdata), .s_lb_n(flash_ar_lb_n), .s_ub_n(flash_ar_ub_n),
|
||||
.s_rdata(flash_ar_rdata), .s_ready(flash_ar_ready)
|
||||
);
|
||||
|
||||
// ---- W: weight fetch (unchanged) ----
|
||||
wire [N_SLOTS-1:0] wide_s_wr = {N_SLOTS{1'b0}};
|
||||
wire [64*N_SLOTS-1:0] wide_s_wdata = {(64*N_SLOTS){1'b0}};
|
||||
|
||||
Reference in New Issue
Block a user