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:
@@ -70,7 +70,14 @@ module dependency_manager #(
|
||||
output reg [ADDR_WIDTH-1:0] ready_x_base,
|
||||
output reg [ADDR_WIDTH-1:0] ready_w_base,
|
||||
output reg [15:0] ready_n_tiles,
|
||||
output reg [ADDR_WIDTH-1:0] ready_result_addr
|
||||
output reg [ADDR_WIDTH-1:0] ready_result_addr,
|
||||
|
||||
// FPGA_DATA_READY support: high while at least one registered node
|
||||
// has not yet been handed to the Director (ST_WAITING or ST_READY --
|
||||
// ST_DISPATCHED is deliberately excluded, since dispatched work is
|
||||
// tracked downstream by neural_director.v's own queue/slot state,
|
||||
// not here -- see this file's own ST_DISPATCHED comment).
|
||||
output wire any_pending
|
||||
);
|
||||
|
||||
localparam ST_EMPTY = 2'd0;
|
||||
@@ -111,6 +118,17 @@ module dependency_manager #(
|
||||
end
|
||||
end
|
||||
|
||||
// ---- FPGA_DATA_READY support (see any_pending port comment above) ----
|
||||
reg any_pending_r;
|
||||
integer pi;
|
||||
always @(*) begin
|
||||
any_pending_r = 1'b0;
|
||||
for (pi = 0; pi < N_NODES; pi = pi + 1)
|
||||
if (node_state[pi] == ST_WAITING || node_state[pi] == ST_READY)
|
||||
any_pending_r = 1'b1;
|
||||
end
|
||||
assign any_pending = any_pending_r;
|
||||
|
||||
integer ni, di;
|
||||
|
||||
always @(posedge clk) begin
|
||||
|
||||
@@ -73,7 +73,13 @@ module neural_director #(
|
||||
output reg [$clog2(N_SLOTS)-1:0] job_out_slot,
|
||||
|
||||
output reg [3:0] dir_state,
|
||||
output reg dir_error
|
||||
output reg dir_error,
|
||||
|
||||
// FPGA_DATA_READY support: high when the dispatch queue is empty
|
||||
// (no job waiting for a free slot) -- combined upstream with
|
||||
// dependency_manager's any_pending and this module's own slot
|
||||
// activity to detect true system-idle.
|
||||
output wire queue_empty
|
||||
);
|
||||
|
||||
localparam DIR_IDLE = 4'd0;
|
||||
@@ -97,6 +103,7 @@ module neural_director #(
|
||||
reg [Q_ADDR_WIDTH:0] q_count; // one extra bit: 0..QUEUE_DEPTH inclusive
|
||||
|
||||
wire q_empty = (q_count == 0);
|
||||
assign queue_empty = q_empty;
|
||||
wire q_full = (q_count == QUEUE_DEPTH[Q_ADDR_WIDTH:0]);
|
||||
|
||||
assign job_in_ready = !q_full;
|
||||
|
||||
Reference in New Issue
Block a user