feat: two-flash programming architecture, FPGA_DATA_READY, real JTAG/config pinout
Establishes the real ESP32<->ECP5 programming architecture: flash #1 (neural-network data, existing V1 subsystem, ball reserved not yet wired into V2) stays separate from flash #2 (boot bitstream, MSPI auto-boot, CFG[2:0]=[0,1,0]); ESP32 talks JTAG only (bit-banged, no hardware JTAG-master peripheral on S3/C6), updating flash #2 through the ECP5's own internal sysCONFIG-to-SPI bridge, never driving the flash pins directly -- zero bus contention, confirmed against the real Lattice hardware checklist and sysCONFIG user guide. Adds real, verified ball assignments (official Lattice CABGA381 CSV + Project Trellis iodb.json) for JTAG, PROGRAMN/INITN/DONE, CFG[2:0], and the MSPI dedicated pins -- all written to docs/pinouts.md. Implements FPGA_DATA_READY as real RTL: a system-idle detector (dependency_manager's any_pending OR neural_director's !queue_empty OR any active slot), sticky on the busy->idle edge, self-clearing on new work -- not a per-neuron completion pulse, which was confirmed too fine-grained. Bit-exact regression re-verified at N_SLOTS=4 and 8 (zero cycle-count change), new explicit data_ready assertion check added to the D-Stress testbench (PASS both configs), and a fresh Yosys+nextpnr-ecp5 placement check (0 errors, data_ready placed at G3). Also fixes a real, independently-found bug while editing an adjacent file: nms_neural_multiprocessor_sdram_unified.v's own sdram_a port was still [11:0] (12 bits), stale from before the 64MB/13-bit memory upgrade. Not exercised by the real board-level top (which wires SDRAM directly, bypassing this wrapper) but WAS silently truncating A12 in every D-Stress simulation this session, including today's earlier ERR-0029 verification runs. Assessed impact: all D-Stress test addresses used this session decode to rows under 4096 (bit 12 never actually needed), so no false-positive PASS is believed to have resulted -- but the full 64MB space was never actually exercised through this wrapper. Fixed; re-verified bit-exact with identical cycle counts. See decisions.log DEC-0041 for full detail. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
This commit is contained in:
@@ -66,6 +66,11 @@ module fpga_neural_v2_top #(
|
||||
inout wire [15:0] sdram_dq,
|
||||
output wire [1:0] sdram_dqm,
|
||||
|
||||
// FPGA_DATA_READY: high once the whole registered graph has
|
||||
// finished (system-idle sticky flag, self-clearing on new work) --
|
||||
// see nms_dataflow_core_sdram.v for the full design comment.
|
||||
output wire data_ready,
|
||||
|
||||
output wire pll_locked
|
||||
);
|
||||
|
||||
@@ -141,6 +146,7 @@ module fpga_neural_v2_top #(
|
||||
.reg_required(reg_required), .reg_producer_ids(reg_producer_ids),
|
||||
.reg_x_base(reg_x_base), .reg_w_base(reg_w_base), .reg_n_tiles(reg_n_tiles),
|
||||
.reg_result_addr(reg_result_addr),
|
||||
.data_ready(data_ready),
|
||||
.slot_mem_req(slot_mem_req), .slot_mem_wr(slot_mem_wr), .slot_mem_addr(slot_mem_addr),
|
||||
.slot_mem_wdata(slot_mem_wdata), .slot_mem_lb_n(slot_mem_lb_n), .slot_mem_ub_n(slot_mem_ub_n),
|
||||
.slot_mem_rdata(slot_mem_rdata), .slot_mem_ready(slot_mem_ready),
|
||||
|
||||
@@ -79,6 +79,10 @@ module nms_dataflow_core_sdram #(
|
||||
input wire [15:0] reg_n_tiles,
|
||||
input wire [ADDR_WIDTH-1:0] reg_result_addr,
|
||||
|
||||
// FPGA_DATA_READY: see the assignment site (below u_director) for
|
||||
// the full design comment.
|
||||
output wire data_ready,
|
||||
|
||||
output wire [N_SLOTS:0] slot_mem_req,
|
||||
output wire [N_SLOTS:0] slot_mem_wr,
|
||||
output wire [ADDR_WIDTH*(N_SLOTS+1)-1:0] slot_mem_addr,
|
||||
@@ -110,6 +114,7 @@ module nms_dataflow_core_sdram #(
|
||||
|
||||
wire dm_producer_done_valid;
|
||||
wire [NODE_IDW-1:0] dm_producer_done_node_id;
|
||||
wire dm_any_pending;
|
||||
|
||||
dependency_manager #(
|
||||
.N_NODES(N_NODES), .MAX_DEPS(MAX_DEPS), .ADDR_WIDTH(ADDR_WIDTH)
|
||||
@@ -122,7 +127,8 @@ module nms_dataflow_core_sdram #(
|
||||
.producer_done_valid(dm_producer_done_valid), .producer_done_node_id(dm_producer_done_node_id),
|
||||
.ready_valid(dm_ready_valid), .ready_ready(dm_ready_ready), .ready_node_id(dm_ready_node_id),
|
||||
.ready_x_base(dm_ready_x_base), .ready_w_base(dm_ready_w_base),
|
||||
.ready_n_tiles(dm_ready_n_tiles), .ready_result_addr(dm_ready_result_addr)
|
||||
.ready_n_tiles(dm_ready_n_tiles), .ready_result_addr(dm_ready_result_addr),
|
||||
.any_pending(dm_any_pending)
|
||||
);
|
||||
|
||||
wire [15:0] dm_ready_node_id_ext = {{(16-NODE_IDW){1'b0}}, dm_ready_node_id};
|
||||
@@ -135,6 +141,7 @@ module nms_dataflow_core_sdram #(
|
||||
wire [$clog2(N_SLOTS)-1:0] dir_job_out_slot;
|
||||
wire [3:0] dir_state;
|
||||
wire dir_error;
|
||||
wire dir_queue_empty;
|
||||
|
||||
neural_director #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH), .N_SLOTS(N_SLOTS), .QUEUE_DEPTH(QUEUE_DEPTH)
|
||||
@@ -148,9 +155,37 @@ module nms_dataflow_core_sdram #(
|
||||
.slot_n_tiles(dir_slot_n_tiles), .slot_result_addr(dir_slot_result_addr),
|
||||
.slot_node_id(dir_slot_node_id), .slot_job_done(dir_slot_job_done),
|
||||
.job_out_done(dir_job_out_done), .job_out_slot(dir_job_out_slot),
|
||||
.dir_state(dir_state), .dir_error(dir_error)
|
||||
.dir_state(dir_state), .dir_error(dir_error), .queue_empty(dir_queue_empty)
|
||||
);
|
||||
|
||||
// ---- FPGA_DATA_READY: system-idle detection (see decisions.log
|
||||
// for the full design rationale) ----
|
||||
// sys_busy: true while ANY of {a slot is active, the director's
|
||||
// dispatch queue is non-empty, dependency_manager has a node not
|
||||
// yet dispatched} holds. data_ready is a sticky level that goes
|
||||
// HIGH on the busy->idle falling edge (a graph just finished) and
|
||||
// LOW again the instant any new work starts (registration or
|
||||
// dispatch) -- self-clearing, no explicit host ACK needed. Correct
|
||||
// ONLY if the host finishes registering every node of a graph
|
||||
// before the first one completes (documented assumption, see
|
||||
// decisions.log) -- registration (microseconds over SPI) is far
|
||||
// faster than per-neuron compute (~195 real measured cycles) for
|
||||
// every workload this project has characterized.
|
||||
wire sys_busy = (|job_active) || (!dir_queue_empty) || dm_any_pending;
|
||||
reg sys_busy_prev;
|
||||
reg data_ready_reg;
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
sys_busy_prev <= 1'b0;
|
||||
data_ready_reg <= 1'b0;
|
||||
end else begin
|
||||
sys_busy_prev <= sys_busy;
|
||||
if (sys_busy) data_ready_reg <= 1'b0;
|
||||
else if (sys_busy_prev) data_ready_reg <= 1'b1;
|
||||
end
|
||||
end
|
||||
assign data_ready = data_ready_reg;
|
||||
|
||||
wire [15:0] completed_node_id_16 = dir_slot_node_id[dir_job_out_slot*16 +: 16];
|
||||
assign dm_producer_done_valid = dir_job_out_done;
|
||||
assign dm_producer_done_node_id = completed_node_id_16[NODE_IDW-1:0];
|
||||
|
||||
@@ -60,6 +60,9 @@ module nms_neural_multiprocessor_sdram_unified #(
|
||||
input wire [15:0] reg_n_tiles,
|
||||
input wire [ADDR_WIDTH-1:0] reg_result_addr,
|
||||
|
||||
// FPGA_DATA_READY: system-idle sticky flag, see nms_dataflow_core_sdram.v
|
||||
output wire data_ready,
|
||||
|
||||
// ---- STEP19: ONE physical SDRAM interface, ALL traffic
|
||||
// (weights + activations + results) ----
|
||||
output wire sdram_cke,
|
||||
@@ -68,7 +71,7 @@ module nms_neural_multiprocessor_sdram_unified #(
|
||||
output wire sdram_cas_n,
|
||||
output wire sdram_we_n,
|
||||
output wire [1:0] sdram_ba,
|
||||
output wire [11:0] sdram_a,
|
||||
output wire [12:0] sdram_a,
|
||||
inout wire [15:0] sdram_dq,
|
||||
output wire [1:0] sdram_dqm
|
||||
);
|
||||
@@ -94,6 +97,7 @@ module nms_neural_multiprocessor_sdram_unified #(
|
||||
.reg_required(reg_required), .reg_producer_ids(reg_producer_ids),
|
||||
.reg_x_base(reg_x_base), .reg_w_base(reg_w_base), .reg_n_tiles(reg_n_tiles),
|
||||
.reg_result_addr(reg_result_addr),
|
||||
.data_ready(data_ready),
|
||||
.slot_mem_req(slot_mem_req), .slot_mem_wr(slot_mem_wr), .slot_mem_addr(slot_mem_addr),
|
||||
.slot_mem_wdata(slot_mem_wdata), .slot_mem_lb_n(slot_mem_lb_n), .slot_mem_ub_n(slot_mem_ub_n),
|
||||
.slot_mem_rdata(slot_mem_rdata), .slot_mem_ready(slot_mem_ready),
|
||||
|
||||
Reference in New Issue
Block a user