0% found this document useful (0 votes)
19 views21 pages

Synapse Core

The document contains the Verilog code for the synaptic core and AER output link modules of the ODIN project, which is an online-learning digital spiking neuromorphic processor developed at Université catholique de Louvain. It includes details about the module parameters, input and output configurations, and the internal logic for updating synaptic weights and managing neuron events. The code is licensed under the Solderpad Hardware License, and it references a related publication in the IEEE Transactions on Biomedical Circuits and Systems.

Uploaded by

jayarajsuresh45
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views21 pages

Synapse Core

The document contains the Verilog code for the synaptic core and AER output link modules of the ODIN project, which is an online-learning digital spiking neuromorphic processor developed at Université catholique de Louvain. It includes details about the module parameters, input and output configurations, and the internal logic for updating synaptic weights and managing neuron events. The code is licensed under the Solderpad Hardware License, and it references a related publication in the IEEE Transactions on Biomedical Circuits and Systems.

Uploaded by

jayarajsuresh45
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 21

Synapse_core.

v
// Copyright (C) 2016-2019 Université catholique de Louvain (UCLouvain), Belgium.

// Copyright and related rights are licensed under the Solderpad Hardware

// License, Version 2.0 (the "License"); you may not use this file except in

// compliance with the License. You may obtain a copy of the License at

// http://solderpad.org/licenses/SHL-2.0/. The software, hardware and materials

// distributed under this License are provided in the hope that it will be useful

// on an as is basis, without warranties or conditions of any kind, either

// expressed or implied; without even the implied warranty of merchantability or

// fitness for a particular purpose. See the Solderpad Hardware License for more

// detailed permissions and limitations.

//------------------------------------------------------------------------------

//

// "synaptic_core.v" - ODIN synaptic core module

//

// Project: ODIN - An online-learning digital spiking neuromorphic processor

//

// Author: C. Frenkel, Université catholique de Louvain (UCLouvain), 04/2017

//

// Cite/paper: C. Frenkel, M. Lefebvre, J.-D. Legat and D. Bol, "A 0.086-mm² 12.7-pJ/SOP 64k-
Synapse 256-Neuron Online-Learning

// Digital Spiking Neuromorphic Processor in 28-nm CMOS," IEEE Transactions on


Biomedical Circuits and Systems,

// vol. 13, no. 1, pp. 145-158, 2019.

//

//------------------------------------------------------------------------------
module synaptic_core #(

parameter N = 256,

parameter M = 8

)(

// Global inputs ------------------------------------------

input wire RSTN_syncn,

input wire CLK,

// Inputs from SPI configuration registers ----------------

input wire SPI_GATE_ACTIVITY_sync,

input wire [ N-1:0] SPI_SYN_SIGN,

input wire SPI_UPDATE_UNMAPPED_SYN,

// Inputs from controller ---------------------------------

input wire [ 7:0] CTRL_PRE_EN,

input wire CTRL_BIST_REF,

input wire CTRL_SYNARRAY_WE,

input wire [ 12:0] CTRL_SYNARRAY_ADDR,

input wire CTRL_SYNARRAY_CS,

input wire [2*M-1:0] CTRL_PROG_DATA,

input wire [2*M-1:0] CTRL_SPI_ADDR,

// Inputs from neurons ------------------------------------

input wire [ N-1:0] NEUR_V_UP,

input wire [ N-1:0] NEUR_V_DOWN,

// Outputs ------------------------------------------------
output wire [ 31:0] SYNARRAY_RDATA,

output wire [ 31:0] SYNARRAY_WDATA,

output wire SYN_SIGN

);

// Internal regs and wires definitions

wire [ 31:0] SYNARRAY_WDATA_int;

wire [ N-1:0] NEUR_V_UP_int, NEUR_V_DOWN_int;

wire [ N-2:0] syn_sign_dummy;

genvar i;

// SDSP update logic

generate

for (i=0; i<8; i=i+1) begin

sdsp_update #(

.WIDTH(3)

) sdsp_update_gen (

// Inputs

// General

.SYN_PRE(CTRL_PRE_EN[i] & (SPI_UPDATE_UNMAPPED_SYN |


SYNARRAY_RDATA[(i<<2)+3])),

.SYN_BIST_REF(CTRL_BIST_REF),

// From neuron
.V_UP(NEUR_V_UP_int[i]),

.V_DOWN(NEUR_V_DOWN_int[i]),

// From SRAM

.WSYN_CURR(SYNARRAY_RDATA[(i<<2)+3:(i<<2)]),

// Output

.WSYN_NEW(SYNARRAY_WDATA_int[(i<<2)+3:(i<<2)])

);

end

endgenerate

assign NEUR_V_UP_int = NEUR_V_UP >> ({3'b0,CTRL_SYNARRAY_ADDR[4:0]} << 3);

assign NEUR_V_DOWN_int = NEUR_V_DOWN >> ({3'b0,CTRL_SYNARRAY_ADDR[4:0]} <<


3);

// Updated or configured weights to be written to the synaptic memory

generate

for (i=0; i<4; i=i+1) begin

assign SYNARRAY_WDATA[(i<<3)+7:(i<<3)] = SPI_GATE_ACTIVITY_sync

((i == CTRL_SPI_ADDR[14:13])

? ((CTRL_PROG_DATA[M-1:0] & ~CTRL_PROG_DATA[2*M-


1:M]) | (SYNARRAY_RDATA[(i<<3)+7:(i<<3)] & CTRL_PROG_DATA[2*M-1:M]))

: SYNARRAY_RDATA[(i<<3)+7:(i<<3)])

: SYNARRAY_WDATA_int[(i<<3)+7:(i<<3)];

end

endgenerate
// Synaptic memory wrapper

SRAM_8192x32_wrapper synarray_0 (

// Global inputs

.RSTN (RSTN_syncn),

.CK (CLK),

// Control and data inputs

.CS (CTRL_SYNARRAY_CS),

.WE (CTRL_SYNARRAY_WE),

.A (CTRL_SYNARRAY_ADDR),

.D (SYNARRAY_WDATA),

// Data output

.Q (SYNARRAY_RDATA)

);

assign {syn_sign_dummy,SYN_SIGN} = SPI_SYN_SIGN >> CTRL_SYNARRAY_ADDR[12:5];

endmodule

module SRAM_8192x32_wrapper (

input wire CK, // Clock


input wire RSTN, // Reset (active low)

input wire CS, // Chip Select

input wire WE, // Write Enable

input wire [12:0] A, // Address

input wire [31:0] D, // Data input

output reg [31:0] Q // Data output

);

reg [31:0] mem [0:8191];

// Load weights from memory file

initial begin

$readmemh("weights.mem", mem);

end

always @(posedge CK) begin

if (!RSTN)

Q <= 0;

else if (CS) begin

if (WE)

mem[A] <= D;

else

Q <= mem[A];

end

end

endmodule
aer_output.v

// Copyright (C) 2016-2019 Université catholique de Louvain (UCLouvain), Belgium.

// Copyright and related rights are licensed under the Solderpad Hardware

// License, Version 2.0 (the "License"); you may not use this file except in

// compliance with the License. You may obtain a copy of the License at

// http://solderpad.org/licenses/SHL-2.0/. The software, hardware and materials

// distributed under this License are provided in the hope that it will be useful

// on an as is basis, without warranties or conditions of any kind, either

// expressed or implied; without even the implied warranty of merchantability or

// fitness for a particular purpose. See the Solderpad Hardware License for more

// detailed permissions and limitations.

//------------------------------------------------------------------------------

//

// "aer_out.v" - ODIN AER output link module

//

// Project: ODIN - An online-learning digital spiking neuromorphic processor

//

// Author: C. Frenkel, Université catholique de Louvain (UCLouvain), 04/2017

//

// Cite/paper: C. Frenkel, M. Lefebvre, J.-D. Legat and D. Bol, "A 0.086-mm² 12.7-pJ/SOP
64k-Synapse 256-Neuron Online-Learning

// Digital Spiking Neuromorphic Processor in 28-nm CMOS," IEEE Transactions on


Biomedical Circuits and Systems,

// vol. 13, no. 1, pp. 145-158, 2019.

//

//------------------------------------------------------------------------------
module aer_out #(

parameter N = 256,

parameter M = 8

)(

// Global input -----------------------------------

input wire CLK,

input wire RST,

// Inputs from SPI configuration latches ----------

input wire SPI_GATE_ACTIVITY_sync,

input wire SPI_OUT_AER_MONITOR_EN,

input wire [ M-1:0] SPI_MONITOR_NEUR_ADDR,

input wire [ M-1:0] SPI_MONITOR_SYN_ADDR,

input wire SPI_AER_SRC_CTRL_nNEUR,

// Neuron data inputs -----------------------------

input wire [ 14:0] NEUR_STATE_MONITOR,

input wire [ 6:0] NEUR_EVENT_OUT,

input wire CTRL_NEURMEM_WE,

input wire [ M-1:0] CTRL_NEURMEM_ADDR,

input wire CTRL_NEURMEM_CS,

// Synapse data inputs ----------------------------

input wire [ 31:0] SYNARRAY_WDATA,

input wire CTRL_SYNARRAY_WE,

input wire [ 12:0] CTRL_SYNARRAY_ADDR,

input wire CTRL_SYNARRAY_CS,


// Input from scheduler ---------------------------

input wire [ 12:0] SCHED_DATA_OUT,

// Input from controller --------------------------

input wire CTRL_AEROUT_POP_NEUR,

// Output to controller ---------------------------

output reg AEROUT_CTRL_BUSY,

// Output 8-bit AER link --------------------------

output reg [ M-1:0] AEROUT_ADDR,

output reg AEROUT_REQ,

input wire AEROUT_ACK

);

reg AEROUT_ACK_sync_int, AEROUT_ACK_sync, AEROUT_ACK_sync_del;

wire AEROUT_ACK_sync_negedge;

reg [ 7:0] neuron_state_monitor_samp;

reg [ 3:0] synapse_state_samp;

wire [ 31:0] synapse_state_int;

wire neuron_state_event, synapse_state_event, synapse_state_event_cond;

reg synapse_state_event_del;

wire monitored_neuron_popped;

reg do_neuron0_transfer, do_neuron1_transfer, do_synapse_transfer;


wire rst_activity;

assign rst_activity = RST || SPI_GATE_ACTIVITY_sync;

assign monitored_neuron_popped = CTRL_AEROUT_POP_NEUR &&


(SCHED_DATA_OUT[M-1:0] == SPI_MONITOR_NEUR_ADDR);

assign neuron_state_event = SPI_OUT_AER_MONITOR_EN && ((CTRL_NEURMEM_CS


&& CTRL_NEURMEM_WE && (CTRL_NEURMEM_ADDR == SPI_MONITOR_NEUR_ADDR)) ||
(monitored_neuron_popped && SPI_AER_SRC_CTRL_nNEUR));

assign synapse_state_event_cond = SPI_OUT_AER_MONITOR_EN &&


CTRL_SYNARRAY_CS && CTRL_SYNARRAY_WE && (CTRL_SYNARRAY_ADDR ==
{SPI_MONITOR_SYN_ADDR, SPI_MONITOR_NEUR_ADDR[7:3]});

assign synapse_state_event = synapse_state_event_cond && !neuron_state_event;

// Sync barrier

always @(posedge CLK, posedge rst_activity) begin

if (rst_activity) begin

AEROUT_ACK_sync_int <= 1'b0;

AEROUT_ACK_sync <= 1'b0;

AEROUT_ACK_sync_del <= 1'b0;

end

else begin

AEROUT_ACK_sync_int <= AEROUT_ACK;

AEROUT_ACK_sync <= AEROUT_ACK_sync_int;

AEROUT_ACK_sync_del <= AEROUT_ACK_sync;


end

end

assign AEROUT_ACK_sync_negedge = ~AEROUT_ACK_sync && AEROUT_ACK_sync_del;

// Register state bank

always @(posedge CLK) begin

if (neuron_state_event)

neuron_state_monitor_samp <= NEUR_STATE_MONITOR[7:0];

else

neuron_state_monitor_samp <= neuron_state_monitor_samp;

end

always @(posedge CLK) begin

if (synapse_state_event_cond)

synapse_state_samp <= synapse_state_int[3:0];

else

synapse_state_samp <= synapse_state_samp;

end

assign synapse_state_int = SYNARRAY_WDATA >> ({2'b0,SPI_MONITOR_NEUR_ADDR[2:0]}


<< 2);

// Output AER interface

always @(posedge CLK, posedge rst_activity) begin

if (rst_activity) begin

AEROUT_ADDR <= 8'b0;

AEROUT_REQ <= 1'b0;


AEROUT_CTRL_BUSY <= 1'b0;

do_neuron0_transfer <= 1'b0;

do_neuron1_transfer <= 1'b0;

do_synapse_transfer <= 1'b0;

synapse_state_event_del <= 1'b0;

end else if (~SPI_OUT_AER_MONITOR_EN) begin

do_neuron0_transfer <= 1'b0;

do_neuron1_transfer <= 1'b0;

do_synapse_transfer <= 1'b0;

synapse_state_event_del <= 1'b0;

if ((SPI_AER_SRC_CTRL_nNEUR ? CTRL_AEROUT_POP_NEUR : NEUR_EVENT_OUT[6])


&& ~AEROUT_ACK_sync) begin

AEROUT_ADDR <= SPI_AER_SRC_CTRL_nNEUR ? SCHED_DATA_OUT[M-1:0] :


CTRL_NEURMEM_ADDR;

AEROUT_REQ <= 1'b1;

AEROUT_CTRL_BUSY <= 1'b1;

end else if (AEROUT_ACK_sync) begin

AEROUT_ADDR <= AEROUT_ADDR;

AEROUT_REQ <= 1'b0;

AEROUT_CTRL_BUSY <= 1'b1;

end else if (AEROUT_ACK_sync_negedge) begin

AEROUT_ADDR <= AEROUT_ADDR;

AEROUT_REQ <= 1'b0;

AEROUT_CTRL_BUSY <= 1'b0;

end else begin

AEROUT_ADDR <= AEROUT_ADDR;

AEROUT_REQ <= AEROUT_REQ;

AEROUT_CTRL_BUSY <= AEROUT_CTRL_BUSY;

end
end else begin

if (AEROUT_ACK_sync_negedge) begin

AEROUT_ADDR <= AEROUT_ADDR;

AEROUT_REQ <= 1'b0;

AEROUT_CTRL_BUSY <= do_neuron0_transfer || synapse_state_event_del;

do_neuron0_transfer <= 1'b0;

do_neuron1_transfer <= do_neuron0_transfer;

do_synapse_transfer <= 1'b0;

synapse_state_event_del <= synapse_state_event_del;

end else if (AEROUT_ACK_sync) begin

AEROUT_ADDR <= AEROUT_ADDR;

AEROUT_REQ <= 1'b0;

AEROUT_CTRL_BUSY <= 1'b1;

do_neuron0_transfer <= do_neuron0_transfer;

do_neuron1_transfer <= do_neuron1_transfer;

do_synapse_transfer <= do_synapse_transfer;

synapse_state_event_del <= synapse_state_event_del;

end else if ((neuron_state_event || synapse_state_event) && !AEROUT_REQ) begin

AEROUT_ADDR <= synapse_state_event ? {4'b1111,synapse_state_int[3:0]}

: {(SPI_AER_SRC_CTRL_nNEUR ?
monitored_neuron_popped : NEUR_EVENT_OUT[6]),NEUR_STATE_MONITOR[14:8]};

AEROUT_REQ <= 1'b1;

AEROUT_CTRL_BUSY <= 1'b1;

do_neuron0_transfer <= neuron_state_event;

do_neuron1_transfer <= 1'b0;

do_synapse_transfer <= synapse_state_event;

synapse_state_event_del <= synapse_state_event_cond && neuron_state_event;

end else if (do_neuron1_transfer && !AEROUT_REQ) begin


AEROUT_ADDR <= neuron_state_monitor_samp;

AEROUT_REQ <= 1'b1;

AEROUT_CTRL_BUSY <= 1'b1;

do_neuron0_transfer <= 1'b0;

do_neuron1_transfer <= 1'b1;

do_synapse_transfer <= 1'b0;

synapse_state_event_del <= synapse_state_event_del;

end else if (synapse_state_event_del && !AEROUT_REQ) begin

AEROUT_ADDR <= {4'b1111,synapse_state_samp};

AEROUT_REQ <= 1'b1;

AEROUT_CTRL_BUSY <= 1'b1;

do_neuron0_transfer <= 1'b0;

do_neuron1_transfer <= 1'b0;

do_synapse_transfer <= 1'b0;

synapse_state_event_del <= 1'b0;

end else begin

AEROUT_ADDR <= AEROUT_ADDR;

AEROUT_REQ <= AEROUT_REQ;

AEROUT_CTRL_BUSY <= AEROUT_CTRL_BUSY;

do_neuron0_transfer <= do_neuron0_transfer;

do_neuron1_transfer <= do_neuron1_transfer;

do_synapse_transfer <= do_synapse_transfer;

synapse_state_event_del <= synapse_state_event_del;

end

end

end
endmodule

sdsp_update.v
// Copyright (C) 2016-2019 Université catholique de Louvain (UCLouvain), Belgium.

// Copyright and related rights are licensed under the Solderpad Hardware

// License, Version 2.0 (the "License"); you may not use this file except in

// compliance with the License. You may obtain a copy of the License at

// http://solderpad.org/licenses/SHL-2.0/. The software, hardware and materials

// distributed under this License are provided in the hope that it will be useful

// on an as is basis, without warranties or conditions of any kind, either

// expressed or implied; without even the implied warranty of merchantability or

// fitness for a particular purpose. See the Solderpad Hardware License for more

// detailed permissions and limitations.

//------------------------------------------------------------------------------

//

// "sdsp_update.v" - ODIN SDSP update logic module

//

// Project: ODIN - An online-learning digital spiking neuromorphic processor

//

// Author: C. Frenkel, Université catholique de Louvain (UCLouvain), 04/2017

//

// Cite/paper: C. Frenkel, M. Lefebvre, J.-D. Legat and D. Bol, "A 0.086-mm² 12.7-pJ/SOP 64k-
Synapse 256-Neuron Online-Learning

// Digital Spiking Neuromorphic Processor in 28-nm CMOS," IEEE Transactions on


Biomedical Circuits and Systems,

// vol. 13, no. 1, pp. 145-158, 2019.

//

//------------------------------------------------------------------------------
module sdsp_update #(

parameter WIDTH = 3

)(

// Inputs

// General

input wire SYN_PRE,

input wire SYN_BIST_REF,

// From neuron

input wire V_UP,

input wire V_DOWN,

// From SRAM

input wire [WIDTH:0] WSYN_CURR,

// Output

output reg [WIDTH:0] WSYN_NEW

);

wire w_lt_half;

wire do_up, do_down;

wire overflow;

assign w_lt_half = SYN_PRE & ~WSYN_CURR[WIDTH-1];

assign do_up = SYN_PRE & (SYN_BIST_REF ? ~w_lt_half : V_UP);

assign do_down = SYN_PRE & (SYN_BIST_REF ? w_lt_half : V_DOWN);


assign overflow = SYN_PRE & ((do_up && (&WSYN_CURR[WIDTH-1:0])) || (do_down &&
(~|WSYN_CURR[WIDTH-1:0])));

always @(*) begin

if (overflow) WSYN_NEW = WSYN_CURR;

else if (do_up) WSYN_NEW = WSYN_CURR + {{(WIDTH){1'b0}},1'b1};

else if (do_down) WSYN_NEW = WSYN_CURR - {{(WIDTH){1'b0}},1'b1};

else WSYN_NEW = WSYN_CURR;

end

endmodule

tb_synaptic_core.v

`timescale 1ns / 1ps

module tb_synaptic_core;

// Parameters

localparam N = 256;

localparam M = 8;

// Clock and Reset

reg CLK;

reg RSTN_syncn;
// SPI Configuration Inputs

reg SPI_GATE_ACTIVITY_sync;

reg [N-1:0] SPI_SYN_SIGN;

reg SPI_UPDATE_UNMAPPED_SYN;

// Controller Inputs

reg [7:0] CTRL_PRE_EN;

reg CTRL_BIST_REF;

reg CTRL_SYNARRAY_WE;

reg [12:0] CTRL_SYNARRAY_ADDR;

reg CTRL_SYNARRAY_CS;

reg [2*M-1:0] CTRL_PROG_DATA;

reg [2*M-1:0] CTRL_SPI_ADDR;

// Neuron Inputs

reg [N-1:0] NEUR_V_UP;

reg [N-1:0] NEUR_V_DOWN;

// Outputs

wire [31:0] SYNARRAY_RDATA;

wire [31:0] SYNARRAY_WDATA;

wire SYN_SIGN;

// Instantiate DUT

synaptic_core #(

.N(N),

.M(M)
) dut (

.RSTN_syncn(RSTN_syncn),

.CLK(CLK),

.SPI_GATE_ACTIVITY_sync(SPI_GATE_ACTIVITY_sync),

.SPI_SYN_SIGN(SPI_SYN_SIGN),

.SPI_UPDATE_UNMAPPED_SYN(SPI_UPDATE_UNMAPPED_SYN),

.CTRL_PRE_EN(CTRL_PRE_EN),

.CTRL_BIST_REF(CTRL_BIST_REF),

.CTRL_SYNARRAY_WE(CTRL_SYNARRAY_WE),

.CTRL_SYNARRAY_ADDR(CTRL_SYNARRAY_ADDR),

.CTRL_SYNARRAY_CS(CTRL_SYNARRAY_CS),

.CTRL_PROG_DATA(CTRL_PROG_DATA),

.CTRL_SPI_ADDR(CTRL_SPI_ADDR),

.NEUR_V_UP(NEUR_V_UP),

.NEUR_V_DOWN(NEUR_V_DOWN),

.SYNARRAY_RDATA(SYNARRAY_RDATA),

.SYNARRAY_WDATA(SYNARRAY_WDATA),

.SYN_SIGN(SYN_SIGN)

);

// Clock generation

always #5 CLK = ~CLK; // 100MHz

// Stimulus

initial begin

$dumpfile("tb_synaptic_core.vcd");

$dumpvars(0, tb_synaptic_core);
CLK = 0;

RSTN_syncn = 0;

SPI_GATE_ACTIVITY_sync = 0;

SPI_SYN_SIGN = 0;

SPI_UPDATE_UNMAPPED_SYN = 0;

CTRL_PRE_EN = 8'h00;

CTRL_BIST_REF = 0;

CTRL_SYNARRAY_WE = 0;

CTRL_SYNARRAY_ADDR = 13'd0;

CTRL_SYNARRAY_CS = 0;

CTRL_PROG_DATA = 0;

CTRL_SPI_ADDR = 0;

NEUR_V_UP = 0;

NEUR_V_DOWN = 0;

// Reset pulse

#20;

RSTN_syncn = 1;

// Preload configuration

#10;

CTRL_SYNARRAY_ADDR = 13'd1;

CTRL_SYNARRAY_CS = 1;

CTRL_SYNARRAY_WE = 0;

#10;

SPI_UPDATE_UNMAPPED_SYN = 1;

CTRL_PRE_EN = 8'hFF;
NEUR_V_UP = {256{1'b1}};

NEUR_V_DOWN = {256{1'b0}};

// Simulate SPI programming

#20;

SPI_GATE_ACTIVITY_sync = 1;

CTRL_PROG_DATA = 16'h00FF;

CTRL_SPI_ADDR = 16'h0000;

#20;

SPI_GATE_ACTIVITY_sync = 0;

CTRL_SYNARRAY_WE = 1;

#10;

CTRL_SYNARRAY_WE = 0;

#50;

$finish;

end

endmodule

You might also like