FASE #1 hardware freeze for FPGA-Neural V2, N4/P8, single external SDRAM (Alliance Memory AS4C4M16SA-6TIN) serving weights, activations, and results through one physical sdram_controller.v instance. Removes the PSRAM dependency (hardware/v1/rtl/psram_controller.v + memory_interface.v) from the V2 physical path entirely -- V1 itself remains fully unmodified, the golden reference. New RTL: sdram_unified_backend.v (2-way W/AR arbitration over one SDRAM controller, real per-byte DQM write masking added to sdram_controller.v for correct single-byte result writes with no read-modify-write), nms_neural_multiprocessor_sdram_unified.v (the frozen top-level). Two real bugs found and fixed via full-system testing before being accepted (ERR-0023): a deadlock and an off-by-one data-shift bug in the new arbitration logic. Real results: N=4 and N=2 D-Stress bit-exact (256/256 neurons), 40 real AUTO REFRESH events interleaved with zero corruption, real Yosys+nextpnr-ecp5 synthesis/P&R for LFE5U-45F-8CABGA381 (149/245 TRELLIS_IO, a real 45-pin reduction from the prior dual-memory design). Timing is MARGINAL (1/8 P&R seeds >=80MHz), reported honestly rather than masked by the best seed. Real, sourced ball-level pinout for the SDRAM bus + clk/rst (39/149 signals, P&R-verified) using the official Lattice ECP5U-45 pinout CSV found on disk during this step's own pre-commit review -- corrects an earlier draft that wrongly assumed no real pinout data was available. Chip readiness: NO. Real, disclosed blockers remain (no physical host interface exists yet -- the RTL's own reg_* ports are a 110-pin raw test-harness bus; clock source/PLL decision; power/configuration component selection) -- see hardware/v2/docs/{HARDWARE_FREEZE, CHIP_READINESS,OPEN_ITEMS}.md for the complete, itemized status. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
70 lines
3.0 KiB
Verilog
70 lines
3.0 KiB
Verilog
// ============================================================
|
|
// Neural Memory System (NMS) -- STEP 3: banked activation SRAM
|
|
// contention model. SIMULATION-ONLY, NEVER SYNTHESIZED.
|
|
//
|
|
// Models a single shared activation vector striped across N_BANKS
|
|
// banks by tile index (bank = tile_idx % N_BANKS). Each bank can serve
|
|
// ONE DISTINCT address per cycle, but BROADCASTS that address's data
|
|
// to every requester currently wanting it (a shared-producer, many-
|
|
// consumer read costs exactly one read, not one per consumer -- see
|
|
// hardware/v2/nms/rtl.. STEP2's own architecture.log note and the
|
|
// user's own NMS spec §11). A cycle where two+ requesters mapped to
|
|
// the same bank want DIFFERENT tile indices serves only one of them
|
|
// (lowest-index requester wins this round); the others simply retry
|
|
// next cycle (idempotent -- an ideal SRAM read has no state cost).
|
|
//
|
|
// Read latency is modeled as ZERO cycles (grant and data-available
|
|
// are the same cycle) -- this file isolates the BANK CONTENTION
|
|
// question specifically, decoupled from backing-store latency, which
|
|
// STEP1 (hardware/v2/nms/rtl/ideal_memory_model.v, EXP-0017) already
|
|
// characterized separately. Fill-from-PSRAM is out of scope here too
|
|
// (the vector is assumed already resident, i.e. steady-state
|
|
// consumption after prefetch -- the question this file answers is
|
|
// "does the on-chip organization itself let N_SLOTS scale", not
|
|
// "how do we hide PSRAM latency" (already answered by STEP1).
|
|
// ============================================================
|
|
module ideal_banked_activation #(
|
|
parameter NREQ = 4,
|
|
parameter N_BANKS = 2,
|
|
parameter AW = 32
|
|
)(
|
|
input [NREQ-1:0] req_valid,
|
|
input [NREQ*AW-1:0] req_addr_flat,
|
|
output reg [NREQ-1:0] ack
|
|
);
|
|
integer b, i;
|
|
reg [AW-1:0] req_addr [0:NREQ-1];
|
|
reg [AW-1:0] served_addr;
|
|
reg have_served;
|
|
integer bank_of_i;
|
|
|
|
always @* begin
|
|
for (i = 0; i < NREQ; i = i + 1)
|
|
req_addr[i] = req_addr_flat[i*AW +: AW];
|
|
|
|
ack = {NREQ{1'b0}};
|
|
for (b = 0; b < N_BANKS; b = b + 1) begin
|
|
have_served = 1'b0;
|
|
served_addr = {AW{1'b0}};
|
|
// first pass: lowest-index valid requester in this bank sets
|
|
// the address served this cycle
|
|
for (i = 0; i < NREQ; i = i + 1) begin
|
|
bank_of_i = req_addr[i] % N_BANKS;
|
|
if (req_valid[i] && (bank_of_i == b) && !have_served) begin
|
|
served_addr = req_addr[i];
|
|
have_served = 1'b1;
|
|
end
|
|
end
|
|
// second pass: broadcast ack to every requester in this bank
|
|
// that wants the SAME address (free, one read serves all)
|
|
if (have_served) begin
|
|
for (i = 0; i < NREQ; i = i + 1) begin
|
|
bank_of_i = req_addr[i] % N_BANKS;
|
|
if (req_valid[i] && (bank_of_i == b) && (req_addr[i] == served_addr))
|
|
ack[i] = 1'b1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
endmodule
|