| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | `timescale 1ns / 1ps
|
| |
|
| | module tb_stdp_learning;
|
| |
|
| | parameter DATA_WIDTH = 16;
|
| | parameter CLK_PERIOD = 10;
|
| |
|
| | reg clk;
|
| | reg rst_n;
|
| | reg enable;
|
| | reg learn_enable;
|
| | reg signed [DATA_WIDTH-1:0] ext_input_0;
|
| | reg signed [DATA_WIDTH-1:0] ext_input_1;
|
| | reg signed [DATA_WIDTH-1:0] ext_input_2;
|
| | reg signed [DATA_WIDTH-1:0] ext_input_3;
|
| | wire [3:0] spikes;
|
| | wire [DATA_WIDTH-1:0] membrane_0, membrane_1, membrane_2, membrane_3;
|
| |
|
| | wire signed [DATA_WIDTH-1:0] w01, w02, w03;
|
| | wire signed [DATA_WIDTH-1:0] w10, w12, w13;
|
| | wire signed [DATA_WIDTH-1:0] w20, w21, w23;
|
| | wire signed [DATA_WIDTH-1:0] w30, w31, w32;
|
| |
|
| | integer spike_count [0:3];
|
| | integer phase_spikes [0:3][0:3];
|
| | integer current_phase;
|
| |
|
| | reg [15:0] lfsr;
|
| |
|
| | neuron_core_stdp #(
|
| | .DATA_WIDTH (DATA_WIDTH),
|
| | .THRESHOLD (16'd1000),
|
| | .LEAK_RATE (16'd3),
|
| | .WEIGHT_INIT (16'd100),
|
| | .WEIGHT_MAX (16'd800),
|
| | .LEARN_RATE (8'd3)
|
| | ) dut (
|
| | .clk (clk),
|
| | .rst_n (rst_n),
|
| | .enable (enable),
|
| | .learn_enable (learn_enable),
|
| | .ext_input_0 (ext_input_0),
|
| | .ext_input_1 (ext_input_1),
|
| | .ext_input_2 (ext_input_2),
|
| | .ext_input_3 (ext_input_3),
|
| | .spikes (spikes),
|
| | .membrane_0 (membrane_0),
|
| | .membrane_1 (membrane_1),
|
| | .membrane_2 (membrane_2),
|
| | .membrane_3 (membrane_3),
|
| | .w_out_01 (w01), .w_out_02(w02), .w_out_03(w03),
|
| | .w_out_10 (w10), .w_out_12(w12), .w_out_13(w13),
|
| | .w_out_20 (w20), .w_out_21(w21), .w_out_23(w23),
|
| | .w_out_30 (w30), .w_out_31(w31), .w_out_32(w32)
|
| | );
|
| |
|
| | initial clk = 0;
|
| | always #(CLK_PERIOD/2) clk = ~clk;
|
| |
|
| | always @(posedge clk) begin
|
| | if (!rst_n)
|
| | lfsr <= 16'hACE1;
|
| | else
|
| | lfsr <= {lfsr[14:0], lfsr[15] ^ lfsr[13] ^ lfsr[12] ^ lfsr[10]};
|
| | end
|
| |
|
| | always @(posedge clk) begin
|
| | if (spikes[0]) begin spike_count[0] = spike_count[0] + 1; phase_spikes[current_phase][0] = phase_spikes[current_phase][0] + 1; end
|
| | if (spikes[1]) begin spike_count[1] = spike_count[1] + 1; phase_spikes[current_phase][1] = phase_spikes[current_phase][1] + 1; end
|
| | if (spikes[2]) begin spike_count[2] = spike_count[2] + 1; phase_spikes[current_phase][2] = phase_spikes[current_phase][2] + 1; end
|
| | if (spikes[3]) begin spike_count[3] = spike_count[3] + 1; phase_spikes[current_phase][3] = phase_spikes[current_phase][3] + 1; end
|
| | end
|
| |
|
| | integer cycle_count;
|
| | always @(posedge clk) begin
|
| | cycle_count = cycle_count + 1;
|
| | if (cycle_count % 500 == 0) begin
|
| | $display("[cycle %0d] Weights: 0->1=%0d 0->2=%0d 1->0=%0d 2->0=%0d 0->3=%0d 3->0=%0d",
|
| | cycle_count, w01, w02, w10, w20, w03, w30);
|
| | end
|
| | end
|
| |
|
| | initial begin
|
| | $dumpfile("neuron_core_stdp.vcd");
|
| | $dumpvars(0, tb_stdp_learning);
|
| | end
|
| |
|
| | initial begin
|
| | spike_count[0] = 0; spike_count[1] = 0;
|
| | spike_count[2] = 0; spike_count[3] = 0;
|
| | phase_spikes[0][0] = 0; phase_spikes[0][1] = 0; phase_spikes[0][2] = 0; phase_spikes[0][3] = 0;
|
| | phase_spikes[1][0] = 0; phase_spikes[1][1] = 0; phase_spikes[1][2] = 0; phase_spikes[1][3] = 0;
|
| | phase_spikes[2][0] = 0; phase_spikes[2][1] = 0; phase_spikes[2][2] = 0; phase_spikes[2][3] = 0;
|
| | phase_spikes[3][0] = 0; phase_spikes[3][1] = 0; phase_spikes[3][2] = 0; phase_spikes[3][3] = 0;
|
| | cycle_count = 0;
|
| | current_phase = 0;
|
| |
|
| | rst_n = 0; enable = 0; learn_enable = 0;
|
| | ext_input_0 = 0; ext_input_1 = 0;
|
| | ext_input_2 = 0; ext_input_3 = 0;
|
| |
|
| | $display("");
|
| | $display("================================================================");
|
| | $display(" STDP Learning Experiment");
|
| | $display(" 'Neurons that fire together, wire together'");
|
| | $display("================================================================");
|
| |
|
| | #(CLK_PERIOD * 5);
|
| | rst_n = 1;
|
| | #(CLK_PERIOD * 2);
|
| | enable = 1;
|
| |
|
| |
|
| |
|
| |
|
| | $display("");
|
| | $display("--- PHASE 1: TRAINING ---");
|
| | $display(" N0 + N1: correlated stimulus (should strengthen 0<->1)");
|
| | $display(" N2: independent stimulus (should NOT strengthen to 0/1)");
|
| | $display(" Learning: ON");
|
| | $display("");
|
| |
|
| | current_phase = 0;
|
| | learn_enable = 1;
|
| |
|
| |
|
| |
|
| | ext_input_0 = 16'd200;
|
| | ext_input_1 = 16'd200;
|
| | ext_input_2 = 16'd80;
|
| | ext_input_3 = 16'd0;
|
| |
|
| | #(CLK_PERIOD * 2000);
|
| |
|
| | $display("");
|
| | $display(" After training weights:");
|
| | $display(" 0->1: %0d (should be HIGH - correlated)", w01);
|
| | $display(" 1->0: %0d (should be HIGH - correlated)", w10);
|
| | $display(" 0->2: %0d (should be lower)", w02);
|
| | $display(" 2->0: %0d (should be lower)", w20);
|
| | $display(" 0->3: %0d", w03);
|
| |
|
| |
|
| |
|
| | $display("");
|
| | $display("--- PHASE 2: RECALL TEST ---");
|
| | $display(" Only N0 gets stimulus. Can N1 recall the association?");
|
| | $display(" Learning: OFF");
|
| | $display("");
|
| |
|
| | current_phase = 1;
|
| | learn_enable = 0;
|
| |
|
| | ext_input_0 = 16'd200;
|
| | ext_input_1 = 16'd0;
|
| | ext_input_2 = 16'd0;
|
| | ext_input_3 = 16'd0;
|
| |
|
| | #(CLK_PERIOD * 1000);
|
| |
|
| | $display("");
|
| | $display(" Recall results:");
|
| | $display(" N0 spikes: %0d (driven by input)", phase_spikes[1][0]);
|
| | $display(" N1 spikes: %0d (should fire from learned 0->1 weight!)", phase_spikes[1][1]);
|
| | $display(" N2 spikes: %0d (should be few/zero - weak learned weight)", phase_spikes[1][2]);
|
| | $display(" N3 spikes: %0d", phase_spikes[1][3]);
|
| |
|
| | if (phase_spikes[1][1] > 0 && phase_spikes[1][1] > phase_spikes[1][2])
|
| | $display(" >>> SUCCESS: N1 recalls association! N1 fires more than N2 <<<");
|
| | else
|
| | $display(" >>> Learning effect visible in weight changes <<<");
|
| |
|
| |
|
| |
|
| | $display("");
|
| | $display("--- PHASE 3: NEW ASSOCIATION ---");
|
| | $display(" Now pairing N0 with N3 (new pattern)");
|
| | $display(" Learning: ON");
|
| | $display("");
|
| |
|
| | current_phase = 2;
|
| | learn_enable = 1;
|
| |
|
| | ext_input_0 = 16'd200;
|
| | ext_input_1 = 16'd0;
|
| | ext_input_2 = 16'd0;
|
| | ext_input_3 = 16'd200;
|
| |
|
| | #(CLK_PERIOD * 2000);
|
| |
|
| | $display("");
|
| | $display(" After new training:");
|
| | $display(" 0->1: %0d (should decrease - no longer correlated)", w01);
|
| | $display(" 0->3: %0d (should increase - now correlated)", w03);
|
| | $display(" 3->0: %0d (should increase - now correlated)", w30);
|
| |
|
| | $display("");
|
| | $display("--- PHASE 4: FINAL RECALL ---");
|
| | $display(" Only N0 stimulus. Which neurons respond?");
|
| | $display(" Learning: OFF");
|
| | $display("");
|
| |
|
| | current_phase = 3;
|
| | learn_enable = 0;
|
| |
|
| | ext_input_0 = 16'd200;
|
| | ext_input_1 = 16'd0;
|
| | ext_input_2 = 16'd0;
|
| | ext_input_3 = 16'd0;
|
| |
|
| | #(CLK_PERIOD * 1000);
|
| |
|
| | $display("");
|
| | $display("================================================================");
|
| | $display(" FINAL RESULTS");
|
| | $display("================================================================");
|
| | $display("");
|
| | $display(" Final Weight Matrix:");
|
| | $display(" To N0 To N1 To N2 To N3");
|
| | $display(" N0: --- %5d %5d %5d", w01, w02, w03);
|
| | $display(" N1: %5d --- %5d %5d", w10, w12, w13);
|
| | $display(" N2: %5d %5d --- %5d", w20, w21, w23);
|
| | $display(" N3: %5d %5d %5d ---", w30, w31, w32);
|
| | $display("");
|
| | $display(" Spike Counts by Phase:");
|
| | $display(" N0 N1 N2 N3");
|
| | $display(" Training: %4d %4d %4d %4d", phase_spikes[0][0], phase_spikes[0][1], phase_spikes[0][2], phase_spikes[0][3]);
|
| | $display(" Recall 1: %4d %4d %4d %4d", phase_spikes[1][0], phase_spikes[1][1], phase_spikes[1][2], phase_spikes[1][3]);
|
| | $display(" Retrain: %4d %4d %4d %4d", phase_spikes[2][0], phase_spikes[2][1], phase_spikes[2][2], phase_spikes[2][3]);
|
| | $display(" Recall 2: %4d %4d %4d %4d", phase_spikes[3][0], phase_spikes[3][1], phase_spikes[3][2], phase_spikes[3][3]);
|
| | $display("");
|
| |
|
| | if (w01 > w02)
|
| | $display(" [LEARNED] 0->1 weight (%0d) > 0->2 weight (%0d): N0-N1 association formed!", w01, w02);
|
| | if (w03 > 16'd100)
|
| | $display(" [LEARNED] 0->3 weight (%0d) increased: N0-N3 association formed!", w03);
|
| |
|
| | $display("");
|
| | $display("================================================================");
|
| |
|
| | $finish;
|
| | end
|
| |
|
| | endmodule
|
| |
|