sPyNNaker neural_modelling  7.4.2
neuron_impl_external_devices.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 The University of Manchester
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
19 #ifndef _NEURON_IMPL_EXTERNAL_DEVICES_H_
20 #define _NEURON_IMPL_EXTERNAL_DEVICES_H_
21 
22 #include "neuron_impl.h"
23 
25 enum send_type {
32 };
33 
34 // Includes for model parts used in this implementation
35 
39 
42 
43 // Further includes
44 #include <debug.h>
45 
46 
48 typedef struct packet_firing_data_t {
50  uint32_t key;
53  uint32_t value_as_payload;
56  accum min_value;
59  accum max_value;
65  enum send_type type;
67 
77  N_RECORDED_VARS = 3
78 };
79 
85  N_BITFIELD_VARS = 1
86 };
87 
88 // This import depends on variables defined above
90 
93 
96 
99 
102 
103 // Typesafe magic reinterpret cast
104 static inline uint _int_bits(int value) {
105  typedef union _int_bits_union {
106  int int_value;
107  uint uint_value;
108  } _int_bits_union;
109 
110  _int_bits_union converter;
111  converter.int_value = value;
112  return converter.uint_value;
113 }
114 
119 static inline uint _get_payload(enum send_type type, accum value) {
120  switch (type) {
121  case SEND_TYPE_INT:
122  return _int_bits((int) value);
123  case SEND_TYPE_UINT:
124  return (uint) value;
125  case SEND_TYPE_ACCUM:
126  return _int_bits(bitsk(value));
127  case SEND_TYPE_UACCUM:
128  return bitsuk((unsigned accum) value);
129  case SEND_TYPE_FRACT:
130  return _int_bits(bitslr((long fract) value));
131  case SEND_TYPE_UFRACT:
132  return bitsulr((long unsigned fract) value);
133  default:
134  log_error("Unknown enum value %u", value);
135  rt_error(RTE_SWERR);
136  }
137  return 0;
138 }
139 
140 SOMETIMES_UNUSED // Marked unused as only used sometimes
144 static bool neuron_impl_initialise(uint32_t n_neurons) {
145 
146  // Allocate DTCM for neuron array
147  log_info("Initialising for %u neurons", n_neurons);
148  neuron_array = spin1_malloc(n_neurons * sizeof(neuron_t));
149  if (neuron_array == NULL) {
150  log_error("Unable to allocate neuron array - Out of DTCM");
151  return false;
152  }
153 
154  // Allocate DTCM for packet firing array and copy block of data
156  spin1_malloc(n_neurons * sizeof(packet_firing_data_t));
157  if (packet_firing_array == NULL) {
158  log_error("Unable to allocate packet firing array - Out of DTCM");
159  return false;
160  }
161 
162  // Allocate DTCM for synapse shaping parameters
164  spin1_malloc(n_neurons * sizeof(synapse_types_t));
165  if (synapse_types_array == NULL) {
166  log_error("Unable to allocate synapse parameters array"
167  " - Out of DTCM");
168  return false;
169  }
170 
171  return true;
172 }
173 
174 SOMETIMES_UNUSED // Marked unused as only used sometimes
180  index_t synapse_type_index, index_t neuron_index,
181  input_t weights_this_timestep) {
182  // simple wrapper to synapse type input function
183  synapse_types_t *parameters = &synapse_types_array[neuron_index];
184  synapse_types_add_neuron_input(synapse_type_index,
185  parameters, weights_this_timestep);
186 }
187 
191 static uint32_t n_words_needed(size_t size) {
192  return (size + (sizeof(uint32_t) - 1)) / sizeof(uint32_t);
193 }
194 
195 SOMETIMES_UNUSED // Marked unused as only used sometimes
196 static void neuron_impl_load_neuron_parameters(
197  address_t address, uint32_t next, uint32_t n_neurons,
198  address_t save_initial_state) {
199 
200  // Read the number of steps per timestep
201  n_steps_per_timestep = address[next++];
202  if (n_steps_per_timestep > 1) {
203  log_info("Looping over %u steps each timestep", n_steps_per_timestep);
204  } else if (n_steps_per_timestep == 0) {
205  log_error("bad number of steps per timestep: 0");
206  }
207 
208  neuron_params_t *neuron_params = (neuron_params_t *) &address[next];
209  for (uint32_t i = 0; i < n_neurons; i++) {
211  }
212  next += n_words_needed(n_neurons * sizeof(neuron_params_t));
213 
214  spin1_memcpy(packet_firing_array, &address[next],
215  n_neurons * sizeof(packet_firing_data_t));
216  next += n_words_needed(n_neurons * sizeof(packet_firing_data_t));
217 
219  for (uint32_t i = 0; i < n_neurons; i++) {
221  }
223 
224  // If we are to save the initial state, copy the whole of the parameters
225  // to the initial state
226  if (save_initial_state) {
227  spin1_memcpy(save_initial_state, address, next * sizeof(uint32_t));
228  }
229 
230 #if LOG_LEVEL >= LOG_DEBUG
231  for (index_t n = 0; n < n_neurons; n++) {
233  }
234 #endif // LOG_LEVEL >= LOG_DEBUG
235 }
236 
241 static bool _test_will_fire(packet_firing_data_t *packet_firing) {
242  if (packet_firing->time_until_next_send == 0) {
243  packet_firing->time_until_next_send =
244  packet_firing->timesteps_between_sending;
245  --packet_firing->time_until_next_send;
246  return true;
247  }
248  --packet_firing->time_until_next_send;
249  return false;
250 }
251 
252 SOMETIMES_UNUSED // Marked unused as only used sometimes
258  UNUSED uint32_t timer_count, UNUSED uint32_t time, uint32_t n_neurons) {
259 
260  for (uint32_t neuron_index = 0; neuron_index < n_neurons; neuron_index++) {
261  // Get the neuron itself
262  neuron_t *this_neuron = &neuron_array[neuron_index];
263 
264  // Get threshold and additional input parameters for this neuron
265  packet_firing_data_t *the_packet_firing =
266  &packet_firing_array[neuron_index];
267  synapse_types_t *the_synapse_type =
268  &synapse_types_array[neuron_index];
269 
270  // Store whether the neuron has spiked
271  bool will_fire = false;
272 
273  // Loop however many times requested; do this in reverse for efficiency,
274  // and because the index doesn't actually matter
275  for (uint32_t i = n_steps_per_timestep; i > 0; i--) {
276  // Get the voltage
277  state_t soma_voltage = neuron_model_get_membrane_voltage(this_neuron);
278 
279  // Get the exc and inh values from the synapses
280  input_t exc_values[NUM_EXCITATORY_RECEPTORS];
281  input_t *exc_input_values =
282  synapse_types_get_excitatory_input(exc_values, the_synapse_type);
283  input_t inh_values[NUM_INHIBITORY_RECEPTORS];
284  input_t *inh_input_values =
285  synapse_types_get_inhibitory_input(inh_values, the_synapse_type);
286 
287  // Sum g_syn contributions from all receptors for recording
288  REAL total_exc = 0;
289  REAL total_inh = 0;
290 
291  for (int i = 0; i < NUM_EXCITATORY_RECEPTORS; i++) {
292  total_exc += exc_input_values[i];
293  }
294  for (int i = 0; i < NUM_INHIBITORY_RECEPTORS; i++) {
295  total_inh += inh_input_values[i];
296  }
297 
298  // Do recording if on the first step
299  if (i == n_steps_per_timestep) {
301  V_RECORDING_INDEX, neuron_index, soma_voltage);
303  GSYN_EXC_RECORDING_INDEX, neuron_index, total_exc);
305  GSYN_INH_RECORDING_INDEX, neuron_index, total_inh);
306  }
307 
308  // Get any input from an injected current source
309  REAL current_offset = current_source_get_offset(time, neuron_index);
310 
311  // update neuron parameters
313  NUM_EXCITATORY_RECEPTORS, exc_input_values,
314  NUM_INHIBITORY_RECEPTORS, inh_input_values,
315  0, current_offset, this_neuron);
316 
317  // determine if a packet should fly
318  will_fire = _test_will_fire(the_packet_firing);
319 
320  // If spike occurs, communicate to relevant parts of model
321  if (will_fire) {
322  if (the_packet_firing->value_as_payload) {
323  accum value_to_send = result;
324  if (result > the_packet_firing->max_value) {
325  value_to_send = the_packet_firing->max_value;
326  }
327  if (result < the_packet_firing->min_value) {
328  value_to_send = the_packet_firing->min_value;
329  }
330 
331  uint payload = _get_payload(
332  the_packet_firing->type,
333  value_to_send * the_packet_firing->value_as_payload);
334 
335  send_spike_mc_payload(the_packet_firing->key, payload);
336  } else {
337  send_spike_mc(the_packet_firing->key);
338  }
339  }
340 
341  // Shape the existing input according to the included rule
342  synapse_types_shape_input(the_synapse_type);
343  }
344 
345  if (will_fire) {
346  // Record the spike
348  }
349 
350  #if LOG_LEVEL >= LOG_DEBUG
352  #endif // LOG_LEVEL >= LOG_DEBUG
353  }
354 }
355 
356 SOMETIMES_UNUSED // Marked unused as only used sometimes
362  address_t address, uint32_t next, uint32_t n_neurons) {
363  // Skip over the steps per timestep
364  next += 1;
365 
366  neuron_params_t *neuron_params = (neuron_params_t *) &address[next];
367  for (uint32_t i = 0; i < n_neurons; i++) {
368  neuron_model_save_state(&neuron_array[i], &neuron_params[i]);
369  }
370  next += n_words_needed(n_neurons * sizeof(neuron_params_t));
371 
372  spin1_memcpy(&address[next], packet_firing_array,
373  n_neurons * sizeof(packet_firing_data_t));
374  next += n_words_needed(n_neurons * sizeof(packet_firing_data_t));
375 
377  for (uint32_t i = 0; i < n_neurons; i++) {
379  }
381 }
382 
383 #if LOG_LEVEL >= LOG_DEBUG
384 SOMETIMES_UNUSED // Marked unused as only used sometimes
388  bool empty = true;
389  for (index_t i = 0; i < n_neurons; i++) {
391  input_t exc_values[NUM_EXCITATORY_RECEPTORS];
392  input_t inh_values[NUM_INHIBITORY_RECEPTORS];
393  empty = empty && (0 == bitsk(
396  }
397 
398  if (!empty) {
399  for (index_t i = 0; i < n_neurons; i++) {
401  input_t exc_values[NUM_EXCITATORY_RECEPTORS];
402  input_t inh_values[NUM_INHIBITORY_RECEPTORS];
405  if (bitsk(input) != 0) {
406  log_debug("%3u: %12.6k (= ", i, input);
408  log_debug(")\n");
409  }
410  }
411  }
412 }
413 
414 SOMETIMES_UNUSED // Marked unused as only used sometimes
418  for (index_t n = 0; n < n_neurons; n++) {
420  }
421 }
422 
423 SOMETIMES_UNUSED // Marked unused as only used sometimes
427 const char *neuron_impl_get_synapse_type_char(uint32_t synapse_type) {
428  return synapse_types_get_type_char(synapse_type);
429 }
430 #endif // LOG_LEVEL >= LOG_DEBUG
431 
432 #endif // _NEURON_IMPL_EXTERNAL_DEVICES_H_
General API of a current source implementation.
static REAL current_source_get_offset(uint32_t time, uint32_t neuron_index)
Calculate the current offset from all injected current sources.
Implement all current sources.
static uint32_t time
Simulation time.
#define NUM_INHIBITORY_RECEPTORS
The number of inhibitory receptors.
Definition: input_type.h:37
#define NUM_EXCITATORY_RECEPTORS
The number of excitatory receptors.
Definition: input_type.h:28
Input type is standard current-based model.
accum REAL
Type used for "real" numbers.
Definition: maths-util.h:91
REAL state_t
The type of a state variable.
REAL input_t
The type of an input.
static uint32_t n_neurons
The number of neurons on the core.
Definition: neuron.c:45
General API of a neuron implementation.
bitfield_recording_indices
Indices for recording of bitfields.
@ PACKET_RECORDING_BITFIELD
Spike event recording index.
@ N_BITFIELD_VARS
Number of recorded bitfields.
void neuron_impl_print_synapse_parameters(uint32_t n_neurons)
Print the synapse parameters of the neurons.
static neuron_t * neuron_array
Array of neuron states.
uint32_t key
The key to send to update the value.
static void neuron_impl_do_timestep_update(uint32_t timer_count, uint32_t time, uint32_t n_neurons)
Do the timestep update for the particular implementation.
word_recording_indices
Indices for recording of words.
@ GSYN_INH_RECORDING_INDEX
Gsyn_inh (excitatory synaptic conductance/current) recording index.
@ GSYN_EXC_RECORDING_INDEX
Gsyn_exc (excitatory synaptic conductance/current) recording index.
@ N_RECORDED_VARS
Number of recorded word-sized state variables.
@ V_RECORDING_INDEX
V (somatic potential) recording index.
static uint32_t n_words_needed(size_t size)
The number of words required to hold an object of given size.
send_type
What sort of message payload should we send?
@ SEND_TYPE_ACCUM
Message payload is an accum
@ SEND_TYPE_UFRACT
Message payload is an unsigned fract
@ SEND_TYPE_INT
Message payload is an int32_t
@ SEND_TYPE_UACCUM
Message payload is an unsigned accum
@ SEND_TYPE_UINT
Message payload is an uint32_t
@ SEND_TYPE_FRACT
Message payload is a fract
static void neuron_impl_add_inputs(index_t synapse_type_index, index_t neuron_index, input_t weights_this_timestep)
Add inputs to the neuron.
static packet_firing_data_t * packet_firing_array
Threshold states array.
uint32_t timesteps_between_sending
The time between sending the value.
void neuron_impl_print_inputs(uint32_t n_neurons)
Print the inputs to the neurons.
static bool neuron_impl_initialise(uint32_t n_neurons)
Initialise the particular implementation of the data.
const char * neuron_impl_get_synapse_type_char(uint32_t synapse_type)
Get the synapse type character for a synapse type.
static uint n_steps_per_timestep
The number of steps to run per timestep.
uint32_t time_until_next_send
The time until the next sending of the value (initially 0)
static synapse_types_t * synapse_types_array
The synapse shaping parameters.
static void neuron_impl_store_neuron_parameters(address_t address, uint32_t next, uint32_t n_neurons)
Stores neuron parameters back into SDRAM.
enum send_type type
Send type.
The definition of the threshold.
static void neuron_model_print_state_variables(const neuron_t *neuron)
printout of state variables i.e. those values that might change
static state_t neuron_model_get_membrane_voltage(const neuron_t *neuron)
get the neuron membrane voltage for a given neuron parameter set
static state_t neuron_model_state_update(uint16_t num_excitatory_inputs, const input_t *exc_input, uint16_t num_inhibitory_inputs, const input_t *inh_input, input_t external_bias, REAL current_offset, neuron_t *restrict neuron)
primary function called in timer loop after synaptic updates
static void neuron_model_initialise(neuron_t *state, neuron_params_t *params, uint32_t n_steps_per_timestep)
initialise the structure from the parameters
static void neuron_model_save_state(neuron_t *state, neuron_params_t *params)
save parameters and state back to SDRAM for reading by host and recovery on restart
static void neuron_model_print_parameters(const neuron_t *neuron)
printout of parameters i.e. those values that don't change
Leaky Integrate and Fire neuron type.
definition of neuron parameters
definition for LIF neuron state
Recording of the state of a neuron (spiking, voltage, etc.)
static void neuron_recording_record_accum(uint32_t var_index, uint32_t neuron_index, accum value)
stores a recording of an accum variable only; this is faster than neuron_recording_record_value for t...
static void neuron_recording_record_bit(uint32_t var_index, uint32_t neuron_index)
stores a recording of a set bit; this is the only way to set a bit in a bitfield; neuron_recording_re...
static stdp_params params
Configuration parameters.
static void synapse_types_save_state(synapse_types_t *state, synapse_types_params_t *params)
save parameters and state back to SDRAM for reading by host and recovery on restart
static void synapse_types_initialise(synapse_types_t *state, synapse_types_params_t *params, uint32_t n_steps_per_time_step)
initialise the structure from the parameters
static const char * synapse_types_get_type_char(index_t synapse_type_index)
returns a human readable character for the type of synapse.
static void synapse_types_add_neuron_input(index_t synapse_type_index, synapse_types_t *parameters, input_t input)
adds the inputs for a give timer period to a given neuron that is being simulated by this model
static void synapse_types_print_input(synapse_types_t *parameters)
prints the input for a neuron ID given the available inputs currently only executed when the models a...
static input_t * synapse_types_get_excitatory_input(input_t *excitatory_response, synapse_types_t *parameters)
extracts the excitatory input buffers from the buffers available for a given neuron ID
static void synapse_types_print_parameters(synapse_types_t *parameters)
prints the parameters of the synapse type
static void synapse_types_shape_input(synapse_types_t *parameters)
decays the stuff thats sitting in the input buffers as these have not yet been processed and applied ...
static input_t * synapse_types_get_inhibitory_input(input_t *inhibitory_response, synapse_types_t *parameters)
extracts the inhibitory input buffers from the buffers available for a given neuron ID
implementation of synapse_types.h for Exponential shaping
Delta synapses support just a single excitatory and inhibitory input each.
The layout of the synapse parameters region.
Definition: synapses.c:256