feat: extend neuron_memory to support N_NEURONS>1 (Phase 3)
neuron_memory.v only handled a single neuron. Added an N_NEURONS parameter (default 1, fully backward compatible) and a memory-bound neuron loop: X is read once (shared layer input), and for each neuron in turn W and bias are re-read from PSRAM and fed to a single, reused neuron_parallel instance -- no change to the validated compute datapath (neuron_parallel/mac8/mac_unit). Addressing follows layer.v's neuron-major convention: neuron n's weights live at w_base + n*N_INPUTS bytes, its bias at bias_addr + n. Output changed from a single `y` port to a packed `y_bus` (DATA_WIDTH*N_NEURONS bits, neuron-major), matching layer.v's y_bus. - rtl/neuron_memory.v: N_NEURONS parameter, neuron_index/ w_group_base/bias_group_addr tracking, y_reg[] array assembled into y_bus, STATE_WAIT_N now loops back to STATE_READ_W for the next neuron instead of finishing after one. - sim/neuron_memory_tb.v: updated to the new y_bus port (N_NEURONS=1 explicit); all 5 existing tests still pass unchanged, confirming backward compatibility. - sim/neuron_memory_multi_tb.v: new end-to-end test (full memory_interface + psram_controller + psram_model stack) with N_NEURONS=3, validating per-neuron addressing and a single done pulse at the end of the sequence (scale, larger value, ReLU). - Full regression re-run: all existing testbenches still pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WQV3vS9TXaGDJ5cRfnfidt
This commit is contained in:
+81
-9
@@ -4,6 +4,7 @@ module neuron_memory #(
|
||||
parameter ADDR_WIDTH = 22,
|
||||
parameter DATA_WIDTH = 8,
|
||||
parameter N_INPUTS = 32,
|
||||
parameter N_NEURONS = 1,
|
||||
parameter PARALLEL = 8,
|
||||
parameter ACC_WIDTH = 32
|
||||
)(
|
||||
@@ -35,9 +36,13 @@ module neuron_memory #(
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Result
|
||||
//
|
||||
// One INT8 output per neuron, packed neuron-major (same
|
||||
// convention as layer.v's y_bus): neuron n occupies
|
||||
// y_bus[n*DATA_WIDTH +: DATA_WIDTH].
|
||||
// ------------------------------------------------------------
|
||||
|
||||
output reg signed [7:0] y,
|
||||
output wire signed [DATA_WIDTH*N_NEURONS-1:0] y_bus,
|
||||
output reg busy,
|
||||
output reg done
|
||||
);
|
||||
@@ -57,6 +62,28 @@ module neuron_memory #(
|
||||
|
||||
reg [$clog2(N_INPUTS+1)-1:0] index;
|
||||
|
||||
// ============================================================
|
||||
// NEURON LOOP (Phase 3: multi-neuron memory integration)
|
||||
//
|
||||
// X is shared and read once per layer invocation. W and bias
|
||||
// are re-read from memory for each neuron in turn and fed to a
|
||||
// single, reused neuron_parallel instance (memory-bound design:
|
||||
// one neuron computed at a time). w_group_base/bias_group_addr
|
||||
// track the current neuron's base address and are advanced by
|
||||
// N_INPUTS / 1 byte respectively between neurons, following the
|
||||
// same neuron-major layout as layer.v's weights_bus/bias_bus.
|
||||
// ============================================================
|
||||
|
||||
localparam NEURON_INDEX_WIDTH =
|
||||
(N_NEURONS <= 1) ? 1 : $clog2(N_NEURONS);
|
||||
|
||||
reg [NEURON_INDEX_WIDTH-1:0] neuron_index;
|
||||
|
||||
reg [ADDR_WIDTH-1:0] w_group_base;
|
||||
reg [ADDR_WIDTH-1:0] bias_group_addr;
|
||||
|
||||
reg signed [7:0] y_reg [0:N_NEURONS-1];
|
||||
|
||||
// ============================================================
|
||||
// LOCAL MEMORY ARRAYS
|
||||
// ============================================================
|
||||
@@ -84,6 +111,16 @@ module neuron_memory #(
|
||||
end
|
||||
endgenerate
|
||||
|
||||
genvar j;
|
||||
|
||||
generate
|
||||
for (j = 0; j < N_NEURONS; j = j + 1) begin : GEN_Y_BUS
|
||||
|
||||
assign y_bus[j*DATA_WIDTH +: DATA_WIDTH] = y_reg[j];
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// ============================================================
|
||||
// INT8 MEMORY ACCESS
|
||||
//
|
||||
@@ -191,6 +228,8 @@ module neuron_memory #(
|
||||
|
||||
reg neuron_start;
|
||||
|
||||
integer rst_i;
|
||||
|
||||
wire signed [7:0] neuron_y;
|
||||
wire neuron_busy;
|
||||
wire neuron_done;
|
||||
@@ -225,6 +264,10 @@ module neuron_memory #(
|
||||
state <= STATE_IDLE;
|
||||
index <= 0;
|
||||
|
||||
neuron_index <= 0;
|
||||
w_group_base <= 0;
|
||||
bias_group_addr <= 0;
|
||||
|
||||
bias_reg <= 0;
|
||||
|
||||
access_req <= 1'b0;
|
||||
@@ -234,7 +277,9 @@ module neuron_memory #(
|
||||
|
||||
neuron_start <= 1'b0;
|
||||
|
||||
y <= 0;
|
||||
for (rst_i = 0; rst_i < N_NEURONS; rst_i = rst_i + 1)
|
||||
y_reg[rst_i] <= 0;
|
||||
|
||||
busy <= 1'b0;
|
||||
done <= 1'b0;
|
||||
|
||||
@@ -263,6 +308,10 @@ module neuron_memory #(
|
||||
busy <= 1'b1;
|
||||
index <= 0;
|
||||
|
||||
neuron_index <= 0;
|
||||
w_group_base <= w_base;
|
||||
bias_group_addr <= bias_addr;
|
||||
|
||||
// First X byte
|
||||
access_addr <= x_base;
|
||||
access_wr <= 1'b0;
|
||||
@@ -288,7 +337,7 @@ module neuron_memory #(
|
||||
|
||||
index <= 0;
|
||||
|
||||
access_addr <= w_base;
|
||||
access_addr <= w_group_base;
|
||||
access_wr <= 1'b0;
|
||||
access_req <= 1'b1;
|
||||
|
||||
@@ -319,7 +368,7 @@ module neuron_memory #(
|
||||
|
||||
if (index == N_INPUTS-1) begin
|
||||
|
||||
access_addr <= bias_addr;
|
||||
access_addr <= bias_group_addr;
|
||||
access_wr <= 1'b0;
|
||||
access_req <= 1'b1;
|
||||
|
||||
@@ -329,7 +378,7 @@ module neuron_memory #(
|
||||
|
||||
index <= index + 1'b1;
|
||||
|
||||
access_addr <= w_base + index + 1'b1;
|
||||
access_addr <= w_group_base + index + 1'b1;
|
||||
access_req <= 1'b1;
|
||||
|
||||
end
|
||||
@@ -374,11 +423,34 @@ module neuron_memory #(
|
||||
|
||||
if (neuron_done) begin
|
||||
|
||||
y <= neuron_y;
|
||||
busy <= 1'b0;
|
||||
done <= 1'b1;
|
||||
y_reg[neuron_index] <= neuron_y;
|
||||
|
||||
state <= STATE_IDLE;
|
||||
if (neuron_index == N_NEURONS-1) begin
|
||||
|
||||
// Last neuron of the layer: done.
|
||||
busy <= 1'b0;
|
||||
done <= 1'b1;
|
||||
|
||||
state <= STATE_IDLE;
|
||||
|
||||
end else begin
|
||||
|
||||
// Advance to the next neuron: X stays
|
||||
// in x_mem (shared), reload W and bias
|
||||
// for neuron_index+1 from memory.
|
||||
neuron_index <= neuron_index + 1'b1;
|
||||
w_group_base <= w_group_base + N_INPUTS;
|
||||
bias_group_addr <= bias_group_addr + 1'b1;
|
||||
|
||||
index <= 0;
|
||||
|
||||
access_addr <= w_group_base + N_INPUTS;
|
||||
access_wr <= 1'b0;
|
||||
access_req <= 1'b1;
|
||||
|
||||
state <= STATE_READ_W;
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user