/*! \file
*
* \brief implementation of the neuron.h interface.
*
*/
#include "neuron.h"
#include "models/spindle_model.h"
#include <neuron/input_types/input_type.h>
#include <neuron/additional_inputs/additional_input.h>
#include <neuron/threshold_types/threshold_type.h>
#include "synapse_types/synapse_types.h"
#include <neuron/plasticity/synapse_dynamics.h>
#include <common/out_spikes.h>
#include <recording.h>
#include <debug.h>
#include <string.h>
#define SPIKE_RECORDING_CHANNEL 0
#define V_RECORDING_CHANNEL 1
#define GSYN_RECORDING_CHANNEL 2
//! Array of neuron states
static neuron_pointer_t neuron_array;
//! Input states array
static input_type_pointer_t input_type_array;
//! Additional input array
static additional_input_pointer_t additional_input_array;
//! Threshold states array
static threshold_type_pointer_t threshold_type_array;
//! Global parameters for the neurons
static global_neuron_params_pointer_t global_parameters;
//! The key to be used for this core (will be ORed with neuron id)
static key_t key;
//! A checker that says if this model should be transmitting. If set to false
//! by the data region, then this model should not have a key.
static bool use_key;
//! The number of neurons on the core
static uint32_t n_neurons;
//! The recording flags
static uint32_t recording_flags;
//! The input buffers - from synapses.c
static input_t *input_buffers;
//! storage for neuron state with timestamp
static timed_state_t *voltages;
uint32_t voltages_size;
//! storage for neuron input with timestamp
static timed_input_t *inputs;
uint32_t input_size;
//! f_dyn and f_st to be used for synapses shaping
REAL f_dyn;
REAL f_st;
//! parameters that reside in the neuron_parameter_data_region in human
//! readable form
typedef enum parmeters_in_neuron_parameter_data_region {
HAS_KEY, TRANSMISSION_KEY, N_NEURONS_TO_SIMULATE,
INCOMING_SPIKE_BUFFER_SIZE, START_OF_GLOBAL_PARAMETERS,
} parmeters_in_neuron_parameter_data_region;
//! private method for doing output debug data on the neurons
static inline void _print_neurons() {
//! only if the models are compiled in debug mode will this method contain
//! said lines.
#if LOG_LEVEL >= LOG_DEBUG
log_debug("-------------------------------------\n");
for (index_t n = 0; n < n_neurons; n++) {
neuron_model_print_state_variables(&(neuron_array[n]));
}
log_debug("-------------------------------------\n");
//}
#endif // LOG_LEVEL >= LOG_DEBUG
}
//! private method for doing output debug data on the neurons
static inline void _print_neuron_parameters() {
//! only if the models are compiled in debug mode will this method contain
//! said lines.
#if LOG_LEVEL >= LOG_DEBUG
log_debug("-------------------------------------\n");
for (index_t n = 0; n < n_neurons; n++) {
neuron_model_print_parameters(&(neuron_array[n]));
}
log_debug("-------------------------------------\n");
//}
#endif // LOG_LEVEL >= LOG_DEBUG
}
//! \brief Set up the neuron models
//! \param[in] address the absolute address in SDRAM for the start of the
//! NEURON_PARAMS data region in SDRAM
//! \param[in] recording_flags_param the recordings parameters
//! (contains which regions are active and how big they are)
//! \param[out] n_neurons_value The number of neurons this model is to emulate
//! \return True is the initialisation was successful, otherwise False
bool neuron_initialise(address_t address, uint32_t recording_flags_param,
uint32_t *n_neurons_value, uint32_t *incoming_spike_buffer_size) {
log_info("neuron_initialise: starting");
// Check if there is a key to use
use_key = address[HAS_KEY];
// Read the spike key to use
key = address[TRANSMISSION_KEY];
// output if this model is expecting to transmit
if (!use_key){
log_info("\tThis model is not expecting to transmit as it has no key");
}
else{
log_info("\tThis model is expected to transmit with key = %08x", key);
}
// Read the neuron details
n_neurons = address[N_NEURONS_TO_SIMULATE];
*n_neurons_value = n_neurons;
// Read the size of the incoming spike buffer to use
*incoming_spike_buffer_size = address[INCOMING_SPIKE_BUFFER_SIZE];
uint32_t next = START_OF_GLOBAL_PARAMETERS;
// Read the global parameter details
if (sizeof(global_neuron_params_t) > 0) {
global_parameters = (global_neuron_params_t *) spin1_malloc(
sizeof(global_neuron_params_t));
if (global_parameters == NULL) {
log_error("Unable to allocate global neuron parameters"
"- Out of DTCM");
return false;
}
memcpy(global_parameters, &address[next],
sizeof(global_neuron_params_t));
next += sizeof(global_neuron_params_t) / 4;
}
log_info(
"\t neurons = %u, spike buffer size = %u, params size = %u,"
"input type size = %u, threshold size = %u", n_neurons,
*incoming_spike_buffer_size, sizeof(neuron_t),
sizeof(input_type_t), sizeof(threshold_type_t));
// Allocate DTCM for neuron array and copy block of data
if (sizeof(neuron_t) != 0) {
neuron_array = (neuron_t *) spin1_malloc(n_neurons * sizeof(neuron_t));
if (neuron_array == NULL) {
log_error("Unable to allocate neuron array - Out of DTCM");
return false;
}
memcpy(neuron_array, &address[next], n_neurons * sizeof(neuron_t));
next += (n_neurons * sizeof(neuron_t)) / 4;
}
// Allocate DTCM for input type array and copy block of data
if (sizeof(input_type_t) != 0) {
input_type_array = (input_type_t *) spin1_malloc(
n_neurons * sizeof(input_type_t));
if (input_type_array == NULL) {
log_error("Unable to allocate input type array - Out of DTCM");
return false;
}
memcpy(input_type_array, &address[next],
n_neurons * sizeof(input_type_t));
next += (n_neurons * sizeof(input_type_t)) / 4;
}
// Allocate DTCM for additional input array and copy block of data
if (sizeof(additional_input_t) != 0) {
additional_input_array = (additional_input_pointer_t) spin1_malloc(
n_neurons * sizeof(additional_input_t));
if (additional_input_array == NULL) {
log_error("Unable to allocate additional input array"
" - Out of DTCM");
return false;
}
memcpy(additional_input_array, &address[next],
n_neurons * sizeof(additional_input_t));
next += (n_neurons * sizeof(additional_input_t)) / 4;
}
// Allocate DTCM for threshold type array and copy block of data
if (sizeof(threshold_type_t) != 0) {
threshold_type_array = (threshold_type_t *) spin1_malloc(
n_neurons * sizeof(threshold_type_t));
if (threshold_type_array == NULL) {
log_error("Unable to allocate threshold type array - Out of DTCM");
return false;
}
memcpy(threshold_type_array, &address[next],
n_neurons * sizeof(threshold_type_t));
}
// Set up the out spikes array
if (!out_spikes_initialize(n_neurons)) {
return false;
}
// Set up the neuron model
neuron_model_set_global_neuron_params(global_parameters);
recording_flags = recording_flags_param;
voltages_size = sizeof(uint32_t) + sizeof(state_t) * n_neurons;
voltages = (timed_state_t *) spin1_malloc(voltages_size);
input_size = sizeof(uint32_t) + sizeof(input_struct_t) * n_neurons;
inputs = (timed_input_t *) spin1_malloc(input_size);
_print_neuron_parameters();
return true;
}
//! \setter for the internal input buffers
//! \param[in] input_buffers_value the new input buffers
void neuron_set_input_buffers(input_t *input_buffers_value) {
input_buffers = input_buffers_value;
}
static void print_bit_field2(bit_field_t b, size_t s)
{
use(b);
use(s);
index_t i; //!< For indexing through the bit field
for (i = 0; i < s; i++)
log_info("%08x\n", b [i]);
}
static void out_spikes_print2() {
log_info("out_spikes:\n");
if (!out_spikes_is_empty()) {
log_info("-----------\n");
print_bit_field2(out_spikes, out_spikes_size);
log_info("-----------\n");
} else {
log_info("out spikes is empty :(");
print_bit_field2(out_spikes, out_spikes_size);
log_info("-----------\n");
}
}
//! \executes all the updates to neural parameters when a given timer period
//! has occurred.
//! \param[in] time the timer tick value currently being executed
void neuron_do_timestep_update(timer_t time, REAL length, REAL dlength, uint8_t data_has_come) {
// maybe not necessary
if (n_neurons == 0)
return;
// just use the first neuron to compute the gamma activation
neuron_pointer_t neuron = &neuron_array[0];
input_type_pointer_t input_type = &input_type_array[0];
state_t voltage = neuron_model_get_membrane_voltage(neuron);
input_t exc_input_value = input_type_get_input_value(
synapse_types_get_excitatory_input(input_buffers, 0),
input_type);
input_t inh_input_value = input_type_get_input_value(
synapse_types_get_inhibitory_input(input_buffers, 0),
input_type);
f_dyn = input_type_convert_excitatory_input_to_current(
exc_input_value, input_type, voltage);
f_st = input_type_convert_inhibitory_input_to_current(
inh_input_value, input_type, voltage);
// log_info("dynamic gamma = %k, static gamma = %k", f_dyn, f_st);
if (data_has_come) {
spindle_model_compute_rate(f_dyn, f_st, f_st*REAL_CONST(0.829), length, dlength);
}
// update each neuron individually
for (index_t neuron_index = 0; neuron_index < n_neurons; neuron_index++) {
// // Get the parameters for this neuron
neuron = &neuron_array[neuron_index];
input_type = &input_type_array[neuron_index];
threshold_type_pointer_t threshold_type =
&threshold_type_array[neuron_index];
additional_input_pointer_t additional_input =
&additional_input_array[neuron_index];
voltage = neuron_model_get_membrane_voltage(neuron);
// // If we should be recording potential, record this neuron parameter
voltages->states[neuron_index] = neuron_model_get_membrane_voltage(neuron);
// // Get excitatory and inhibitory input from synapses and convert it
// // to current input
// input_t exc_input_value = input_type_get_input_value(
// synapse_types_get_excitatory_input(input_buffers, neuron_index),
// input_type);
// input_t inh_input_value = input_type_get_input_value(
// synapse_types_get_inhibitory_input(input_buffers, neuron_index),
// input_type);
// input_t exc_input = input_type_convert_excitatory_input_to_current(
// exc_input_value, input_type, voltage);
// input_t inh_input = input_type_convert_inhibitory_input_to_current(
// inh_input_value, input_type, voltage);
// if (data_has_come) {
// spindle_model_compute_rate(exc_input, exc_input, exc_input, length, dlength);
// }
// If we should be recording input, record the values
inputs->inputs[neuron_index].exc = f_dyn;
inputs->inputs[neuron_index].inh = f_st;
// update neuron parameters and determine if a spike should occur
bool spike = neuron_model_state_update(neuron);
// If the neuron has spiked
if (spike) {
log_debug("the neuron %d has been determined to spike",
neuron_index);
// Tell the neuron model
neuron_model_has_spiked(neuron);
// Tell the additional input
additional_input_has_spiked(additional_input);
// Do any required synapse processing
synapse_dynamics_process_post_synaptic_event(time, neuron_index);
// Record the spike
out_spikes_set_spike(neuron_index);
// Send the spike
while (use_key &&
!spin1_send_mc_packet(key | neuron_index, 0, NO_PAYLOAD)) {
spin1_delay_us(1);
}
} else {
log_debug("the neuron %d has been determined to not spike",
neuron_index);
}
}
// record neuron state (membrane potential) if needed
if (recording_is_channel_enabled(recording_flags, V_RECORDING_CHANNEL)) {
voltages->time = time;
recording_record(V_RECORDING_CHANNEL, voltages, voltages_size);
}
// record neuron inputs if needed
if (recording_is_channel_enabled(
recording_flags, GSYN_RECORDING_CHANNEL)) {
inputs->time = time;
recording_record(GSYN_RECORDING_CHANNEL, inputs, input_size);
}
// do logging stuff if required
out_spikes_print2();
_print_neurons();
// Record any spikes this timestep
if (recording_is_channel_enabled(
recording_flags, SPIKE_RECORDING_CHANNEL)) {
log_info("recording spikes...");
out_spikes_record(SPIKE_RECORDING_CHANNEL, time);
}
out_spikes_reset();
}
REAL get_f_dyn() {
return f_dyn;
}
REAL get_f_st() {
return f_st;
}