|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| `timescale 1ns / 1ps
|
|
|
| module tb_128core;
|
|
|
| parameter NUM_CORES = 128;
|
| parameter CORE_ID_BITS = 7;
|
| parameter NUM_NEURONS = 256;
|
| parameter NEURON_BITS = 8;
|
| parameter DATA_WIDTH = 16;
|
| parameter MAX_FANOUT = 32;
|
| parameter FANOUT_BITS = 5;
|
| parameter CONN_ADDR_BITS = 13;
|
| parameter CLK_PERIOD = 10;
|
|
|
| reg clk, rst_n;
|
| reg start;
|
|
|
| reg prog_conn_we;
|
| reg [CORE_ID_BITS-1:0] prog_conn_core;
|
| reg [NEURON_BITS-1:0] prog_conn_src;
|
| reg [FANOUT_BITS-1:0] prog_conn_slot;
|
| reg [NEURON_BITS-1:0] prog_conn_target;
|
| reg signed [DATA_WIDTH-1:0] prog_conn_weight;
|
|
|
| reg prog_route_we;
|
| reg [CORE_ID_BITS-1:0] prog_route_src_core;
|
| reg [NEURON_BITS-1:0] prog_route_src_neuron;
|
| reg [CORE_ID_BITS-1:0] prog_route_dest_core;
|
| reg [NEURON_BITS-1:0] prog_route_dest_neuron;
|
| reg signed [DATA_WIDTH-1:0] prog_route_weight;
|
|
|
| reg ext_valid;
|
| reg [CORE_ID_BITS-1:0] ext_core;
|
| reg [NEURON_BITS-1:0] ext_neuron_id;
|
| reg signed [DATA_WIDTH-1:0] ext_current;
|
|
|
| wire timestep_done;
|
| wire [NUM_CORES-1:0] spike_valid_bus;
|
| wire [NUM_CORES*NEURON_BITS-1:0] spike_id_bus;
|
| wire [4:0] mesh_state_out;
|
| wire [31:0] total_spikes;
|
| wire [31:0] timestep_count;
|
|
|
| integer spike_count;
|
| integer core_spiked [0:NUM_CORES-1];
|
| integer i;
|
|
|
| neuromorphic_mesh #(
|
| .NUM_CORES (NUM_CORES),
|
| .CORE_ID_BITS (CORE_ID_BITS),
|
| .NUM_NEURONS (NUM_NEURONS),
|
| .NEURON_BITS (NEURON_BITS),
|
| .DATA_WIDTH (DATA_WIDTH),
|
| .MAX_FANOUT (MAX_FANOUT),
|
| .FANOUT_BITS (FANOUT_BITS),
|
| .CONN_ADDR_BITS (CONN_ADDR_BITS),
|
| .THRESHOLD (16'sd1000),
|
| .LEAK_RATE (16'sd3),
|
| .REFRAC_CYCLES (3)
|
| ) dut (
|
| .clk (clk),
|
| .rst_n (rst_n),
|
| .start (start),
|
| .prog_conn_we (prog_conn_we),
|
| .prog_conn_core (prog_conn_core),
|
| .prog_conn_src (prog_conn_src),
|
| .prog_conn_slot (prog_conn_slot),
|
| .prog_conn_target (prog_conn_target),
|
| .prog_conn_weight (prog_conn_weight),
|
| .prog_route_we (prog_route_we),
|
| .prog_route_src_core (prog_route_src_core),
|
| .prog_route_src_neuron (prog_route_src_neuron),
|
| .prog_route_dest_core (prog_route_dest_core),
|
| .prog_route_dest_neuron(prog_route_dest_neuron),
|
| .prog_route_weight (prog_route_weight),
|
| .learn_enable (1'b0),
|
| .graded_enable (1'b0),
|
| .dendritic_enable (1'b0),
|
| .async_enable (1'b0),
|
| .prog_conn_comp (2'd0),
|
| .prog_param_we (1'b0),
|
| .prog_param_core ({CORE_ID_BITS{1'b0}}),
|
| .prog_param_neuron (8'd0),
|
| .prog_param_id (3'd0),
|
| .prog_param_value (16'sd0),
|
| .ext_valid (ext_valid),
|
| .ext_core (ext_core),
|
| .ext_neuron_id (ext_neuron_id),
|
| .ext_current (ext_current),
|
| .timestep_done (timestep_done),
|
| .spike_valid_bus (spike_valid_bus),
|
| .spike_id_bus (spike_id_bus),
|
| .mesh_state_out (mesh_state_out),
|
| .total_spikes (total_spikes),
|
| .timestep_count (timestep_count)
|
| );
|
|
|
| initial clk = 0;
|
| always #(CLK_PERIOD/2) clk = ~clk;
|
|
|
| always @(posedge clk) begin
|
| for (i = 0; i < NUM_CORES; i = i + 1) begin
|
| if (spike_valid_bus[i]) begin
|
| spike_count = spike_count + 1;
|
| core_spiked[i] = core_spiked[i] + 1;
|
| end
|
| end
|
| end
|
|
|
| task add_conn;
|
| input [CORE_ID_BITS-1:0] core;
|
| input [NEURON_BITS-1:0] src;
|
| input [FANOUT_BITS-1:0] slot;
|
| input [NEURON_BITS-1:0] target;
|
| input signed [DATA_WIDTH-1:0] weight;
|
| begin
|
| @(posedge clk);
|
| prog_conn_we <= 1;
|
| prog_conn_core <= core;
|
| prog_conn_src <= src;
|
| prog_conn_slot <= slot;
|
| prog_conn_target <= target;
|
| prog_conn_weight <= weight;
|
| @(posedge clk);
|
| prog_conn_we <= 0;
|
| end
|
| endtask
|
|
|
| task add_route;
|
| input [CORE_ID_BITS-1:0] src_core;
|
| input [NEURON_BITS-1:0] src_neuron;
|
| input [CORE_ID_BITS-1:0] dest_core;
|
| input [NEURON_BITS-1:0] dest_neuron;
|
| input signed [DATA_WIDTH-1:0] weight;
|
| begin
|
| @(posedge clk);
|
| prog_route_we <= 1;
|
| prog_route_src_core <= src_core;
|
| prog_route_src_neuron <= src_neuron;
|
| prog_route_dest_core <= dest_core;
|
| prog_route_dest_neuron<= dest_neuron;
|
| prog_route_weight <= weight;
|
| @(posedge clk);
|
| prog_route_we <= 0;
|
| end
|
| endtask
|
|
|
| task run_mesh_timestep;
|
| input [CORE_ID_BITS-1:0] stim_core;
|
| input [NEURON_BITS-1:0] stim_neuron;
|
| input signed [DATA_WIDTH-1:0] stim_current;
|
| begin
|
| ext_valid <= 1;
|
| ext_core <= stim_core;
|
| ext_neuron_id <= stim_neuron;
|
| ext_current <= stim_current;
|
| @(posedge clk);
|
| ext_valid <= 0;
|
|
|
| @(posedge clk);
|
| start <= 1;
|
| @(posedge clk);
|
| start <= 0;
|
|
|
| wait(timestep_done);
|
| @(posedge clk);
|
| end
|
| endtask
|
|
|
| task run_mesh_empty;
|
| begin
|
| @(posedge clk);
|
| start <= 1;
|
| @(posedge clk);
|
| start <= 0;
|
| wait(timestep_done);
|
| @(posedge clk);
|
| end
|
| endtask
|
|
|
| task reset_counts;
|
| begin
|
| spike_count = 0;
|
| for (i = 0; i < NUM_CORES; i = i + 1)
|
| core_spiked[i] = 0;
|
| end
|
| endtask
|
|
|
| integer t, pass_count, fail_count;
|
|
|
| initial begin
|
|
|
| for (i = 0; i < NUM_CORES; i = i + 1)
|
| core_spiked[i] = 0;
|
| spike_count = 0;
|
| pass_count = 0;
|
| fail_count = 0;
|
| rst_n = 0; start = 0;
|
| ext_valid = 0; ext_core = 0; ext_neuron_id = 0; ext_current = 0;
|
| prog_conn_we = 0; prog_conn_core = 0; prog_conn_src = 0;
|
| prog_conn_slot = 0; prog_conn_target = 0; prog_conn_weight = 0;
|
| prog_route_we = 0; prog_route_src_core = 0; prog_route_src_neuron = 0;
|
| prog_route_dest_core = 0; prog_route_dest_neuron = 0; prog_route_weight = 0;
|
|
|
| $display("");
|
| $display("================================================================");
|
| $display(" 128-Core Neuromorphic Mesh Test (Phase 11)");
|
| $display(" %0d cores x %0d neurons = %0d total neurons",
|
| NUM_CORES, NUM_NEURONS, NUM_CORES * NUM_NEURONS);
|
| $display("================================================================");
|
|
|
| #(CLK_PERIOD * 5);
|
| rst_n = 1;
|
| #(CLK_PERIOD * 5);
|
|
|
| $display("");
|
| $display("--- TEST 1: All 128 Cores Start and Complete ---");
|
|
|
|
|
| ext_valid <= 1;
|
| ext_core <= 7'd0;
|
| ext_neuron_id <= 8'd0;
|
| ext_current <= 16'sd1200;
|
| @(posedge clk);
|
| ext_core <= 7'd127;
|
| @(posedge clk);
|
| ext_valid <= 0;
|
|
|
| spike_count = 0;
|
|
|
| @(posedge clk);
|
| start <= 1;
|
| @(posedge clk);
|
| start <= 0;
|
|
|
| wait(timestep_done);
|
| @(posedge clk);
|
|
|
| $display(" Timestep completed: ts=%0d, total_spikes=%0d", timestep_count, total_spikes);
|
| $display(" Core 0 spiked: %0d, Core 127 spiked: %0d",
|
| core_spiked[0], core_spiked[127]);
|
|
|
| if (timestep_count == 1 && total_spikes >= 2) begin
|
| $display(" PASS: All 128 cores completed timestep, both endpoints spiked");
|
| pass_count = pass_count + 1;
|
| end else begin
|
| $display(" FAIL: Expected ts=1 with >=2 spikes, got ts=%0d spikes=%0d",
|
| timestep_count, total_spikes);
|
| fail_count = fail_count + 1;
|
| end
|
|
|
| $display("");
|
| $display("--- TEST 2: Far-Core Route (Core 0 -> Core 127) ---");
|
| reset_counts();
|
|
|
|
|
| add_conn(7'd0, 8'd0, 5'd0, 8'd1, 16'sd1200);
|
| add_conn(7'd0, 8'd1, 5'd0, 8'd2, 16'sd1200);
|
| add_conn(7'd0, 8'd2, 5'd0, 8'd3, 16'sd1200);
|
|
|
|
|
| add_route(7'd0, 8'd3, 7'd127, 8'd0, 16'sd1200);
|
|
|
|
|
| add_conn(7'd127, 8'd0, 5'd0, 8'd1, 16'sd1200);
|
|
|
| $display(" Running 20 timesteps with stimulus to Core 0 N0...");
|
|
|
| for (t = 0; t < 20; t = t + 1) begin
|
| run_mesh_timestep(7'd0, 8'd0, 16'sd200);
|
| end
|
|
|
| $display(" Core 0 spikes: %0d", core_spiked[0]);
|
| $display(" Core 127 spikes: %0d", core_spiked[127]);
|
|
|
| if (core_spiked[127] > 0) begin
|
| $display(" PASS: Spike propagated from Core 0 to Core 127!");
|
| pass_count = pass_count + 1;
|
| end else begin
|
| $display(" FAIL: No spikes reached Core 127");
|
| fail_count = fail_count + 1;
|
| end
|
|
|
| $display("");
|
| $display("--- TEST 3: Multi-Hop Chain (0 -> 42 -> 85 -> 127) ---");
|
| reset_counts();
|
|
|
|
|
| add_conn(7'd42, 8'd0, 5'd0, 8'd1, 16'sd1200);
|
| add_conn(7'd42, 8'd1, 5'd0, 8'd2, 16'sd1200);
|
| add_conn(7'd42, 8'd2, 5'd0, 8'd3, 16'sd1200);
|
|
|
|
|
|
|
| add_conn(7'd0, 8'd4, 5'd0, 8'd5, 16'sd1200);
|
| add_conn(7'd0, 8'd5, 5'd0, 8'd6, 16'sd1200);
|
| add_conn(7'd0, 8'd6, 5'd0, 8'd7, 16'sd1200);
|
|
|
|
|
| add_route(7'd0, 8'd7, 7'd42, 8'd0, 16'sd1200);
|
|
|
|
|
| add_route(7'd42, 8'd3, 7'd85, 8'd0, 16'sd1200);
|
|
|
|
|
| add_conn(7'd85, 8'd0, 5'd0, 8'd1, 16'sd1200);
|
| add_conn(7'd85, 8'd1, 5'd0, 8'd2, 16'sd1200);
|
| add_conn(7'd85, 8'd2, 5'd0, 8'd3, 16'sd1200);
|
|
|
|
|
| add_route(7'd85, 8'd3, 7'd127, 8'd2, 16'sd1200);
|
|
|
|
|
| add_conn(7'd127, 8'd2, 5'd0, 8'd3, 16'sd1200);
|
|
|
| $display(" Running 60 timesteps with stimulus to Core 0 N4...");
|
|
|
| for (t = 0; t < 60; t = t + 1) begin
|
| run_mesh_timestep(7'd0, 8'd4, 16'sd200);
|
| end
|
|
|
| $display(" Core 0 spikes: %0d", core_spiked[0]);
|
| $display(" Core 42 spikes: %0d", core_spiked[42]);
|
| $display(" Core 85 spikes: %0d", core_spiked[85]);
|
| $display(" Core 127 spikes: %0d", core_spiked[127]);
|
|
|
| if (core_spiked[42] > 0 && core_spiked[85] > 0 && core_spiked[127] > 0) begin
|
| $display(" PASS: Spike traversed all 3 hops (0->42->85->127)!");
|
| pass_count = pass_count + 1;
|
| end else begin
|
| $display(" FAIL: Chain incomplete (C42=%0d, C85=%0d, C127=%0d)",
|
| core_spiked[42], core_spiked[85], core_spiked[127]);
|
| fail_count = fail_count + 1;
|
| end
|
|
|
| $display("");
|
| $display("================================================================");
|
| $display(" 128-CORE TEST RESULTS: %0d PASS, %0d FAIL", pass_count, fail_count);
|
| $display("================================================================");
|
| $display(" Architecture: %0d cores x %0d neurons = %0d total",
|
| NUM_CORES, NUM_NEURONS, NUM_CORES * NUM_NEURONS);
|
| $display(" Total timesteps: %0d", timestep_count);
|
| $display(" Total spikes: %0d", total_spikes);
|
| if (fail_count == 0)
|
| $display(" ALL TESTS PASSED");
|
| else
|
| $display(" SOME TESTS FAILED");
|
| $display("================================================================");
|
|
|
| #(CLK_PERIOD * 10);
|
| $finish;
|
| end
|
|
|
| initial begin
|
| #(CLK_PERIOD * 50_000_000);
|
| $display("TIMEOUT at mesh_state=%0d, ts=%0d", mesh_state_out, timestep_count);
|
| $finish;
|
| end
|
|
|
| endmodule
|
|
|