sPyNNaker neural_modelling  7.4.2
delay_extension.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 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 
20 #include "delay_extension.h"
21 
22 #include <common/neuron-typedefs.h>
23 #include <common/in_spikes.h>
24 #include <bit_field.h>
25 #include <data_specification.h>
26 #include <debug.h>
27 #include <simulation.h>
28 #include <spin1_api.h>
29 #include <common/send_mc.h>
30 
32 #define IN_BUFFER_SIZE 256
33 
35 #define COUNTER_SATURATION_VALUE 255
36 
39  MC_PACKET = -1,
40  TIMER = 0,
41  USER = 0,
42  SDP = 1,
43  BACKGROUND = 1,
44  DMA = 2
45 };
46 
54  uint32_t n_packets_added;
56  uint32_t n_packets_sent;
60  uint32_t n_delays;
73 };
74 
75 // Globals
77 static bool has_key;
79 static uint32_t key = 0;
81 static uint32_t incoming_key = 0;
83 static uint32_t incoming_mask = 0;
86 static uint32_t incoming_neuron_mask = 0;
87 
89 static uint32_t num_neurons = 0;
90 
92 static uint32_t max_keys = 0;
93 
96 
98 static uint32_t time = UINT32_MAX;
100 static uint32_t simulation_ticks = 0;
102 static uint32_t infinite_run;
103 
111 static uint8_t **spike_counters = NULL;
113 static uint32_t num_delay_stages = 0;
115 static uint32_t n_delay_in_a_stage = 0;
117 static uint32_t num_delay_slots = 0;
119 static uint32_t num_delay_slots_mask = 0;
121 static uint32_t neuron_bit_field_words = 0;
122 
124 static uint32_t n_in_spikes = 0;
126 static uint32_t n_processed_spikes = 0;
128 static uint32_t n_spikes_sent = 0;
130 static uint32_t n_spikes_added = 0;
131 
133 static uint32_t n_delays = 0;
134 
136 static uint32_t saturation_count = 0;
137 
140 
143 
146 
148 static uint32_t timer_period = 0;
149 
151 static bool spike_processing = false;
152 
154 static uint32_t n_backgrounds_queued = 0;
155 
157 static uint32_t n_background_overloads = 0;
158 
160 static uint32_t max_backgrounds_queued = 0;
161 
163 static uint32_t n_colour_bits = 0;
164 
166 static uint32_t colour_mask = 0;
167 
169 static uint32_t colour = 0;
170 
171 //---------------------------------------
172 // Because we don't want to include string.h or strings.h for memset
179 static inline void zero_spike_counters(
180  uint8_t *counters, uint32_t num_items) {
181  for (uint32_t i = 0 ; i < num_items ; i++) {
182  counters[i] = 0;
183  }
184 }
185 
189 static inline uint32_t round_to_next_pot(uint32_t v) {
190  v--;
191  v |= v >> 1;
192  v |= v >> 2;
193  v |= v >> 4;
194  v |= v >> 8;
195  v |= v >> 16;
196  v++;
197  return v;
198 }
199 
204  log_debug("read_parameters: starting");
205 
206  has_key = params->has_key;
207  key = params->key;
208  incoming_key = params->incoming_key;
209  incoming_mask = params->incoming_mask;
211  log_debug("\t key = 0x%08x, incoming key = 0x%08x, incoming mask = 0x%08x,"
212  "incoming key mask = 0x%08x",
214 
215  num_neurons = params->n_atoms;
216  neuron_bit_field_words = get_bit_field_size(num_neurons);
217 
218  num_delay_stages = params->n_delay_stages;
219  n_delay_in_a_stage = params->n_delay_in_a_stage;
221 
223 
225  // We need an extra slot here (to make one clearable after the maximum delay
226  // time), and a power of 2 (to make it easier to loop)
227  uint32_t num_delay_slots_pot = round_to_next_pot(num_delay_slots + 1);
228  num_delay_slots_mask = num_delay_slots_pot - 1;
229 
230  log_info("\t parrot neurons = %u, neuron bit field words = %u,"
231  " num delay stages = %u, num delay slots = %u (pot = %u),"
232  " num delay slots mask = %08x, n delay in a stage = %u",
234  num_delay_stages, num_delay_slots, num_delay_slots_pot,
236 
237  // Allocate array of counters for each delay slot
238  spike_counters = spin1_malloc(num_delay_slots_pot * sizeof(uint8_t*));
239  if (spike_counters == NULL) {
240  log_error("failed to allocate memory for array of size %u bytes",
241  num_delay_slots_pot * sizeof(uint8_t*));
242  return false;
243  }
244 
245  for (uint32_t s = 0; s < num_delay_slots_pot; s++) {
246  // Allocate an array of counters for each neuron and zero
247  spike_counters[s] = spin1_malloc(num_neurons * sizeof(uint8_t));
248  if (spike_counters[s] == NULL) {
249  log_error("failed to allocate memory for bitfield of size %u bytes",
250  num_neurons * sizeof(uint8_t));
251  return false;
252  }
254  }
255 
256  n_colour_bits = params->n_colour_bits;
257  colour_mask = (1 << n_colour_bits) - 1;
258 
259  log_debug("read_parameters: completed successfully");
260  return true;
261 }
262 
265 static void store_provenance_data(address_t provenance_region) {
266  log_debug("writing other provenance data");
267  struct delay_extension_provenance *prov = (void *) provenance_region;
268 
269  // store the data into the provenance data region
275  prov->n_delays = n_delays;
284  log_debug("finished other provenance data");
285 }
286 
289 static bool initialize(void) {
290  log_info("initialise: started");
291 
292  // Get the address this core's DTCM data starts at from SRAM
293  data_specification_metadata_t *ds_regions =
294  data_specification_get_data_address();
295 
296  // Read the header
297  if (!data_specification_read_header(ds_regions)) {
298  return false;
299  }
300 
301  // Get the timing details and set up the simulation interface
302  if (!simulation_initialise(
303  data_specification_get_region(SYSTEM, ds_regions),
304  APPLICATION_NAME_HASH, &timer_period, &simulation_ticks,
305  &infinite_run, &time, SDP, DMA)) {
306  return false;
307  }
308 
309  // set provenance function
310  simulation_set_provenance_function(
312  data_specification_get_region(PROVENANCE_REGION, ds_regions));
313 
314  // Get the parameters
315  if (!read_parameters(data_specification_get_region(
316  DELAY_PARAMS, ds_regions))) {
317  return false;
318  }
319 
320  log_info("initialise: completed successfully");
321 
322  return true;
323 }
324 
325 // Callbacks
333 static void incoming_spike_callback(uint key, uint payload) {
334 
335  if (payload == 0) {
336  payload = 1;
337  }
338  log_debug("Received spike %x", key);
339 
340  for (uint32_t i = payload; i > 0; i--) {
341  n_in_spikes++;
343  }
344 
345  if (!spike_processing) {
346  if (spin1_trigger_user_event(0, 0)) {
347  spike_processing = true;
348  }
349  }
350 }
351 
355 static inline index_t key_n(key_t k) {
356  return k & incoming_neuron_mask;
357 }
358 
360 static inline void spike_process(void) {
361 
362  // While there are any incoming spikes
363  spike_t s;
364  uint32_t state = spin1_int_disable();
365  while (in_spikes_get_next_spike(&s)) {
366  spin1_mode_restore(state);
368 
369  if ((s & incoming_mask) == incoming_key) {
370  // Mask out neuron ID
371  uint32_t spike_id = key_n(s);
372  uint32_t spike_colour = spike_id & colour_mask;
373  uint32_t neuron_id = spike_id >> n_colour_bits;
374  if (neuron_id < num_neurons) {
375 
376  // Account for delayed spikes
377  int32_t colour_diff = colour - spike_colour;
378  uint32_t colour_delay = colour_diff & colour_mask;
379 
380  // Get current time slot of incoming spike counters
381  uint32_t time_slot = (time + colour_delay) & num_delay_slots_mask;
382  uint8_t *time_slot_spike_counters = spike_counters[time_slot];
383 
384  // Increment counter
385  if (time_slot_spike_counters[neuron_id] ==
387  saturation_count += 1;
388  } else {
389  time_slot_spike_counters[neuron_id]++;
390  }
391  log_debug("Incrementing counter %u = %u\n",
392  neuron_id,
393  time_slot_spike_counters[neuron_id]);
394  n_spikes_added++;
395  } else {
397  log_debug("Invalid neuron ID %u", neuron_id);
398  }
399  } else {
401  log_debug("Invalid spike key 0x%08x", s);
402  }
403  state = spin1_int_disable();
404  }
405 
406  spike_processing = false;
407  spin1_mode_restore(state);
408 }
409 
414 static void user_callback(UNUSED uint unused0, UNUSED uint unused1) {
415  spike_process();
416 }
417 
422 static void background_callback(uint local_time, UNUSED uint timer_count) {
423  // Loop through delay stages
424  for (uint32_t d = 0; d < num_delay_stages; d++) {
425  uint32_t delay_stage_delay = (d + 1) * n_delay_in_a_stage;
426  if (local_time >= delay_stage_delay) {
427  uint32_t delay_stage_time_slot =
428  (local_time - delay_stage_delay) & num_delay_slots_mask;
429  uint8_t *delay_stage_spike_counters =
430  spike_counters[delay_stage_time_slot];
431 
432  log_debug("%u: Checking time slot %u for delay stage %u (delay %u)",
433  local_time, delay_stage_time_slot, d, delay_stage_delay);
434 
435  // Loop through neurons
436  for (uint32_t n = 0; n < num_neurons; n++) {
437 
438  // If no spikes to send, skip
439  if (delay_stage_spike_counters[n] == 0) {
440  continue;
441  }
442 
443  // Calculate key all spikes coming from this neuron will be
444  // sent with
445  uint32_t neuron_index = ((d * num_neurons) + n);
446  uint32_t spike_key = (key + (neuron_index << n_colour_bits)) | colour;
447 
448  log_debug("Neuron %u sending %u spikes after delay"
449  "stage %u with key %x",
450  n, delay_stage_spike_counters[n], d,
451  spike_key);
452 
453  // fire n spikes as payload, 1 as none payload.
454  if (has_key) {
455  if (delay_stage_spike_counters[n] > 1) {
456  log_debug(
457  "%d: sending packet with key 0x%08x and payload %d",
458  time, spike_key, delay_stage_spike_counters[n]);
459 
460  send_spike_mc_payload(spike_key, delay_stage_spike_counters[n]);
461 
462  // update counter
463  n_spikes_sent += delay_stage_spike_counters[n];
464  } else if (delay_stage_spike_counters[n] == 1) {
465  log_debug("%d: sending spike with key 0x%08x", time, spike_key);
466 
467  send_spike_mc(spike_key);
468 
469  // update counter
470  n_spikes_sent++;
471  }
472  }
473  }
474  }
475  }
477 }
478 
482 static void timer_callback(uint timer_count, UNUSED uint unused1) {
483  uint32_t state = spin1_int_disable();
484  uint32_t n_spikes = in_spikes_size();
486  in_spikes_clear();
487  }
488  // Record the count whether clearing or not for provenance
490  time++;
491 
492  // Clear counters
493  if (time > num_delay_slots) {
494  uint32_t clearable_slot = ((time - 1) - num_delay_slots) & num_delay_slots_mask;
495  log_debug("%d: Clearing time slot %d", time, clearable_slot);
497  }
498 
499  log_debug("Timer tick %u", time);
500 
501  // If a fixed number of simulation ticks are specified and these have passed
502  if (simulation_is_finished()) {
503  // handle the pause and resume functionality
504  simulation_handle_pause_resume(NULL);
505 
506  log_debug("Delay extension finished at time %u, %u received spikes, "
507  "%u processed spikes, %u sent spikes, %u added spikes",
510 
511  log_debug("Delayed %u times", n_delays);
512 
513  // Subtract 1 from the time so this tick gets done again on the next
514  // run
515  time--;
516 
517  simulation_ready_to_read();
518  spin1_mode_restore(state);
519  return;
520  }
521 
522  // Set the colour for the time step
523  colour = time & colour_mask;
524 
525  if (!spin1_schedule_callback(background_callback, time, timer_count, BACKGROUND)) {
526  // We have failed to do this timer tick!
528  } else {
532  }
533  }
534  spin1_mode_restore(state);
535 }
536 
538 void c_main(void) {
539  log_info("max dtcm supply %d", sark_heap_max(sark.heap, 0));
540  if (!initialize()) {
541  log_error("Error in initialisation - exiting!");
542  rt_error(RTE_SWERR);
543  }
544 
545  // Start the time at "-1" so that the first tick will be 0
546  time = UINT32_MAX;
547 
548  // Initialise the incoming spike buffer
550  rt_error(RTE_SWERR);
551  }
552 
553  // Set timer tick (in microseconds)
554  log_debug("Timer period %u", timer_period);
555  spin1_set_timer_tick(timer_period);
556 
557  // Register callbacks
558  spin1_callback_on(MC_PACKET_RECEIVED, incoming_spike_callback, MC_PACKET);
559  spin1_callback_on(MCPL_PACKET_RECEIVED, incoming_spike_callback, MC_PACKET);
560  spin1_callback_on(TIMER_TICK, timer_callback, TIMER);
561  spin1_callback_on(USER_EVENT, user_callback, USER);
562 
563  simulation_run();
564 }
static bool initialize(void)
Read the application configuration.
static uint8_t ** spike_counters
The spike counters, as a 2D array.
static uint32_t incoming_mask
Mask for incoming_key to say which messages are for this program.
static uint32_t incoming_neuron_mask
Mask for key (that matches incoming_key/incoming_mask) to extract the neuron ID from it.
static uint32_t num_neurons
Number of neurons supported.
uint32_t n_buffer_overflows
Number of circular buffer overflows (spikes internally dropped)
uint32_t n_packets_processed
Number of spikes transferred via queue.
uint32_t n_packets_dropped_due_to_invalid_key
number of packets dropped due to invalid key
static uint32_t simulation_ticks
Simulation speed.
static uint32_t n_spikes_sent
Number of spikes sent.
static uint32_t n_packets_dropped_due_to_invalid_neuron_value
number of packets dropped due to invalid neuron id
static void spike_process(void)
Processes spikes queued by incoming_spike_callback()
uint32_t n_delays
Number of times we had to back off because the comms hardware was busy.
uint32_t n_packets_dropped_due_to_invalid_neuron_value
number of packets dropped due to invalid neuron value
static uint32_t incoming_key
Key for receiving messages.
static void background_callback(uint local_time, uint timer_count)
Background event callback.
static uint32_t colour_mask
The mask to apply to get the colour from the current timestep or key.
static uint32_t n_in_spikes
Number of input spikes.
static uint32_t n_delays
Number of times we had to back off because the comms hardware was busy.
static uint32_t colour
The colour for the current time step.
static void zero_spike_counters(uint8_t *counters, uint32_t num_items)
Sets an array of counters to zero.
static uint32_t n_processed_spikes
Number of spikes transferred via queue.
static bool clear_input_buffers_of_late_packets
Whether to clear packets each timestep.
uint32_t n_packets_received
Number of input spikes.
static uint32_t num_delay_slots
The total number of delay slots.
static void store_provenance_data(address_t provenance_region)
Writes the provenance data.
static uint32_t key
Base multicast key for sending messages.
static uint32_t num_delay_slots_mask
Mask for converting time into the current delay slot.
#define COUNTER_SATURATION_VALUE
the point where the count has saturated.
uint32_t n_packets_sent
Number of spikes sent.
static uint32_t max_keys
number of possible keys.
static uint32_t n_colour_bits
The number of colour bits (both from source and to send)
static void incoming_spike_callback(uint key, uint payload)
Handles incoming spikes (FIQ)
delay_extension_callback_priorities
values for the priority for each callback
@ TIMER
Call timer at 0 to keep it quick.
@ DMA
DMA is not actually used.
@ BACKGROUND
Background processing.
@ SDP
SDP handling is queued.
@ MC_PACKET
multicast packet reception uses FIQ
@ USER
Call user at 0 as well; will be behind timer.
static uint32_t infinite_run
True if we're running forever.
void c_main(void)
Entry point.
uint32_t n_background_queue_overloads
Background queue overloads.
#define IN_BUFFER_SIZE
the size of the circular queue for packets.
static bool has_key
bool in int form for if there is a key
static uint32_t n_backgrounds_queued
The number of background tasks queued / running.
uint32_t n_packets_lost_due_to_count_saturation
number of packets lost due to count saturation of uint8
static uint32_t n_spikes_added
Number of spikes added to delay processing.
static void user_callback(uint unused0, uint unused1)
User event callback.
static bool spike_processing
Is spike processing happening right now?
static uint32_t timer_period
Used for configuring the timer hardware.
static void timer_callback(uint timer_count, uint unused1)
Main timer callback.
static uint32_t round_to_next_pot(uint32_t v)
Rounds up to the next power of two.
static uint32_t max_backgrounds_queued
The maximum number of background tasks queued.
static uint32_t num_delay_stages
The number of delay stages.
uint32_t max_backgrounds_queued
Maximum backgrounds queued.
uint32_t n_packets_added
Number of spikes added to delay processing.
uint32_t count_input_buffer_packets_late
number of packets dropped due to out of time
static uint32_t time
Simulation time.
static uint32_t n_packets_dropped_due_to_invalid_key
number of packets dropped due to invalid key
static uint32_t n_delay_in_a_stage
The number of delays within a delay stage.
static uint32_t count_input_buffer_packets_late
number of packets late
static index_t key_n(key_t k)
Gets the neuron ID of the incoming spike.
static uint32_t saturation_count
Number of packets dropped due to count saturation.
static uint32_t neuron_bit_field_words
Size of each bitfield in ::neuron_delay_stage_config.
static uint32_t n_background_overloads
The number of times the background couldn't be added.
static bool read_parameters(struct delay_parameters *params)
Read the configuration region.
Structure of the provenance data.
Declarations for delay extensions.
@ PROVENANCE_REGION
Provenance recording region.
@ SYSTEM
General simulation system control.
@ DELAY_PARAMS
Delay parameters (see delay_parameters)
Delay configuration, as read from SDRAM where it was placed by DSG or by on-chip generation.
Functions for immediate handling of incoming spikes.
static bool in_spikes_get_next_spike(spike_t *spike)
Retrieves a spike from the input spike buffer.
Definition: in_spikes.h:66
static bool in_spikes_initialize_spike_buffer(uint32_t size)
This function initialises the input spike buffer.
Definition: in_spikes.h:51
static void in_spikes_clear(void)
clears the input spike buffer.
Definition: in_spikes.h:126
static uint32_t in_spikes_size(void)
get the size of the input spike buffer
Definition: in_spikes.h:121
static counter_t in_spikes_get_n_buffer_overflows(void)
Get the number of times that the input spike buffer overflowed.
Definition: in_spikes.h:80
static bool in_spikes_add_spike(spike_t spike)
Adds a spike to the input spike buffer.
Definition: in_spikes.h:59
uint32_t n_spikes[2]
Spike buffer counters.
static uint32_t local_time
The local time step counter.
Definition: local_only.c:68
Data type definitions for SpiNNaker Neuron-modelling.
uint32_t key_t
The type of a SpiNNaker multicast message key word.
uint32_t spike_t
The type of a spike.
static key_t spike_key(spike_t s)
helper method to retrieve the key from a spike
static int * counters
Accumulators for each motor direction.
static stdp_params params
Configuration parameters.