sPyNNaker neural_modelling  development
spike_processing_fast.c
1 /*
2  * Copyright (c) 2020 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 
17 #include "spike_processing_fast.h"
19 #include "synapses.h"
22 #include "dma_common.h"
23 #include <scamp_spin1_sync.h>
24 #include <simulation.h>
25 #include <recording.h>
26 #include <debug.h>
27 #include <wfi.h>
28 
31 typedef struct dma_buffer {
34 
38 
40  uint32_t n_bytes_transferred;
41 
43  uint32_t colour;
44 
46  uint32_t colour_mask;
47 
50 } dma_buffer;
51 
53 #define N_DMA_BUFFERS 2
54 
56 #define DMA_BUFFER_MOD_MASK 0x1
57 
60 
62 static uint32_t next_buffer_to_fill;
63 
65 static uint32_t next_buffer_to_process;
66 
69 static uint32_t count_input_buffer_packets_late;
70 
72 static uint32_t biggest_fill_size_of_input_buffer;
73 
77 
79 static uint32_t clocks_to_transfer = 0;
80 
82 static uint32_t n_successful_rewires = 0;
83 
85 static uint32_t dma_complete_count = 0;
86 
88 static uint32_t spike_processing_count = 0;
89 
91 static uint32_t max_spikes_received = 0;
92 
94 static uint32_t spikes_processed_this_time_step = 0;
95 
97 static uint32_t max_spikes_processed = 0;
98 
100 static uint32_t transfer_timer_overruns = 0;
101 
103 static uint32_t max_transfer_timer_overrun = 0;
104 
106 static uint32_t skipped_time_steps = 0;
107 
109 static uint32_t latest_spike_received_time = 0xFFFFFFFF;
110 
112 static uint32_t earliest_spike_received_time = 0;
113 
115 static uint32_t max_spikes_overflow = 0;
116 
118 static struct {
119  uint32_t time;
120  uint32_t packets_this_time_step;
122 
124 static uint32_t p_per_ts_region;
125 
127 static struct sdram_config sdram_inputs;
128 
130 static struct key_config key_config;
131 
133 static weight_t *ring_buffers;
134 
137 static inline bool is_end_of_time_step(void) {
138  return tc[T2_COUNT] == 0;
139 }
140 
142 static inline void clear_end_of_time_step(void) {
143  tc[T2_INT_CLR] = 1;
144 }
145 
149 static inline bool wait_for_dma_to_complete_or_end(void) {
150 #if LOG_LEVEL >= LOG_DEBUG
151  // Useful for checking when things are going wrong, but shouldn't be
152  // needed in normal code
153  uint32_t n_loops = 0;
154  while (!is_end_of_time_step() && !dma_done() && n_loops < 10000) {
155  n_loops++;
156  }
157  if (!is_end_of_time_step() && !dma_done()) {
158  log_error("Timeout on DMA loop: DMA stat = 0x%08x!", dma[DMA_STAT]);
159  rt_error(RTE_SWERR);
160  }
161 #else
162  // This is the normal loop, done without checking
163  while (!dma_done()) {
164  continue;
165  }
166 #endif
167  dma[DMA_CTRL] = 0x8;
168 
169  return !is_end_of_time_step();
170 }
171 
175 static inline void transfer_buffers(uint32_t time) {
176  uint32_t first_ring_buffer = synapse_row_get_first_ring_buffer_index(
178  log_debug("Writing %d bytes to 0x%08x from ring buffer %d at 0x%08x",
179  sdram_inputs.size_in_bytes, sdram_inputs.address, first_ring_buffer,
180  &ring_buffers[first_ring_buffer]);
181  do_fast_dma_write(&ring_buffers[first_ring_buffer], sdram_inputs.address,
183 }
184 
187 static inline void process_end_of_time_step(uint32_t time) {
188  // Stop interrupt processing
189  uint32_t cspr = spin1_int_disable();
190 
191  cancel_dmas();
192 
193  // Start transferring buffer data for next time step
194  transfer_buffers(time);
195  wait_for_dma_to_complete();
196 
197  // uint32_t end = tc[T1_COUNT];
198  if (tc[T1_MASK_INT]) {
199  transfer_timer_overruns++;
200  uint32_t diff = tc[T1_LOAD] - tc[T1_COUNT];
201  if (diff > max_transfer_timer_overrun) {
202  max_transfer_timer_overrun = diff;
203  }
204  }
205 
206  spin1_mode_restore(cspr);
207 }
208 
210 static inline void read_synaptic_row(spike_t spike, pop_table_lookup_result_t *result) {
212  buffer->sdram_writeback_address = result->row_address;
213  buffer->originating_spike = spike;
214  buffer->n_bytes_transferred = result->n_bytes_to_transfer;
215  buffer->colour = result->colour;
216  buffer->colour_mask = result->colour_mask;
217  do_fast_dma_read(result->row_address, buffer->row, result->n_bytes_to_transfer);
218  next_buffer_to_fill = (next_buffer_to_fill + 1) & DMA_BUFFER_MOD_MASK;
219 }
220 
225 static inline bool get_next_spike(uint32_t time, spike_t *spike) {
226  uint32_t n_spikes = in_spikes_size();
229  }
230  if (!in_spikes_get_next_spike(spike)) {
231  return false;
232  }
233  // Detect a looped back spike
234  if ((*spike & key_config.mask) == key_config.key) {
235  // Process event if not self-connected (if it is, this happens later)
236  if (!key_config.self_connected) {
239  }
240  return key_config.self_connected;
241  }
242  return true;
243 }
244 
252 static inline bool start_first_dma(uint32_t time, spike_t *spike,
253  pop_table_lookup_result_t *result) {
254 
255  do {
256  if (population_table_get_first_address(*spike, result)) {
257  read_synaptic_row(*spike, result);
258  return true;
259  }
260  } while (!is_end_of_time_step() && get_next_spike(time, spike));
261 
262  return false;
263 }
264 
270 static inline bool get_next_dma(uint32_t time, spike_t *spike,
271  pop_table_lookup_result_t *result) {
273  return true;
274  }
275 
276  while (!is_end_of_time_step() && get_next_spike(time, spike)) {
277  if (population_table_get_first_address(*spike, result)) {
278  return true;
279  }
280  }
281 
282  return false;
283 }
284 
287 static inline void handle_row_error(dma_buffer *buffer) {
288  log_error(
289  "Error processing spike 0x%.8x for address 0x%.8x (local=0x%.8x)",
290  buffer->originating_spike, buffer->sdram_writeback_address, buffer->row);
291 
292  // Print out the row for debugging
293  address_t row = (address_t) buffer->row;
294  for (uint32_t i = 0; i < (buffer->n_bytes_transferred >> 2); i++) {
295  log_error(" %u: 0x%08x", i, row[i]);
296  }
297 
298  // Print out parsed data for static synapses
300  uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region);
301  uint32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region);
302  if (fixed_synapse > (buffer->n_bytes_transferred >> 2)) {
303  log_error("Too many fixed synapses: %u", fixed_synapse);
304  rt_error(RTE_SWERR);
305  }
306  log_error("\nFixed-Fixed Region (%u synapses):", fixed_synapse);
307  for (; fixed_synapse > 0; fixed_synapse--) {
308  uint32_t synaptic_word = *synaptic_words++;
309 
310  uint32_t delay = synapse_row_sparse_delay(
312  uint32_t type = synapse_row_sparse_type(
313  synaptic_word, synapse_index_bits, synapse_type_mask);
314  uint32_t neuron = synapse_row_sparse_index(
315  synaptic_word, synapse_index_mask);
316  log_error(" Delay %u, Synapse Type %u, Neuron %u", delay, type, neuron);
317  }
318  rt_error(RTE_SWERR);
319 }
320 
324 static inline void process_current_row(uint32_t time, bool dma_in_progress) {
325  bool write_back = false;
326  dma_buffer *buffer = &dma_buffers[next_buffer_to_process];
327 
328  if (!synapses_process_synaptic_row(time, buffer->colour, buffer->colour_mask,
329  buffer->row, &write_back)) {
330  handle_row_error(buffer);
331  }
332  synaptogenesis_spike_received(time, buffer->originating_spike);
334  if (write_back) {
335  uint32_t n_bytes = synapse_row_plastic_size(buffer->row) * sizeof(uint32_t);
336  void *system_address = synapse_row_plastic_region(
337  buffer->sdram_writeback_address);
338  void *tcm_address = synapse_row_plastic_region(buffer->row);
339  // Make sure an outstanding DMA is completed before starting this one
340  if (dma_in_progress) {
341  wait_for_dma_to_complete();
342  }
343  do_fast_dma_write(tcm_address, system_address, n_bytes);
344  // Only wait for this DMA to complete if there isn't another running,
345  // as otherwise the next wait will fail!
346  if (!dma_in_progress) {
347  wait_for_dma_to_complete();
348  }
349  }
350  next_buffer_to_process = (next_buffer_to_process + 1) & DMA_BUFFER_MOD_MASK;
351  spikes_processed_this_time_step++;
352 }
353 
356 static inline void store_data(uint32_t time) {
357  // Record the number of packets still left
358  uint32_t n_spikes_left = in_spikes_size();
359  count_input_buffer_packets_late += n_spikes_left;
360  if (n_spikes_left > max_spikes_overflow) {
361  max_spikes_overflow = n_spikes_left;
362  }
363 
364  // Record the number of packets received last time step
365  p_per_ts_struct.time = time;
366  recording_record(p_per_ts_region, &p_per_ts_struct, sizeof(p_per_ts_struct));
367 
368  if (p_per_ts_struct.packets_this_time_step > max_spikes_received) {
369  max_spikes_received = p_per_ts_struct.packets_this_time_step;
370  }
371  if (spikes_processed_this_time_step > max_spikes_processed) {
372  max_spikes_processed = spikes_processed_this_time_step;
373  }
374 }
375 
377 static inline void measure_transfer_time(void) {
378  // Measure the time to do an upload to know when to schedule the timer
379  tc[T2_LOAD] = 0xFFFFFFFF;
380  tc[T2_CONTROL] = 0x82;
381  transfer_buffers(0);
382  wait_for_dma_to_complete();
383  clocks_to_transfer = (0xFFFFFFFF - tc[T2_COUNT])
385  tc[T2_CONTROL] = 0;
386  log_info("Transfer of %u bytes to 0x%08x took %u cycles",
387  sdram_inputs.size_in_bytes, sdram_inputs.address, clocks_to_transfer);
388 }
389 
393 static inline bool prepare_timestep(uint32_t time) {
394  uint32_t cspr = spin1_int_disable();
395 
396  // Reset these to ensure consistency
398  next_buffer_to_process = 0;
399 
400  // We do this here rather than during init, as it should have similar
401  // contention to the expected time of execution
402  if (clocks_to_transfer == 0) {
403  measure_transfer_time();
404  }
405 
406  // Start timer2 to tell us when to stop
407  uint32_t timer = tc[T1_COUNT];
408  if (timer < clocks_to_transfer) {
409  return false;
410  }
411  uint32_t time_until_stop = timer - clocks_to_transfer;
412  tc[T2_CONTROL] = 0;
413  tc[T2_LOAD] = time_until_stop;
414  tc[T2_CONTROL] = 0xe3;
415 
416  log_debug("Start of time step %d, timer = %d, loading with %d",
417  time, timer, time_until_stop);
418 
419  // Store recording data from last time step
420  store_data(time);
421 
422  // Clear the buffer if needed
424  in_spikes_clear();
425  }
426  p_per_ts_struct.packets_this_time_step = 0;
427  spikes_processed_this_time_step = 0;
428 
430  spin1_mode_restore(cspr);
431  return true;
432 }
433 
437 static inline void do_rewiring(uint32_t time, uint32_t n_rewires) {
438  uint32_t spike;
440  uint32_t current_buffer = 0;
441  uint32_t next_buffer = 0;
442  bool dma_in_progress = false;
443 
444  // Start the first transfer
445  uint32_t rewires_to_go = n_rewires;
446  while (rewires_to_go > 0 && !dma_in_progress) {
447  if (synaptogenesis_dynamics_rewire(time, &spike, &result)) {
448  dma_buffers[next_buffer].sdram_writeback_address = result.row_address;
449  dma_buffers[next_buffer].n_bytes_transferred = result.n_bytes_to_transfer;
450  do_fast_dma_read(result.row_address, dma_buffers[next_buffer].row,
451  result.n_bytes_to_transfer);
452  next_buffer = (next_buffer + 1) & DMA_BUFFER_MOD_MASK;
453  dma_in_progress = true;
454  }
455  rewires_to_go--;
456  }
457 
458  // Go in a loop until all done
459  while (dma_in_progress) {
460 
461  // Start the next DMA if possible
462  dma_in_progress = false;
463  while (rewires_to_go > 0 && !dma_in_progress) {
464  if (synaptogenesis_dynamics_rewire(time, &spike, &result)) {
465  dma_in_progress = true;
466  }
467  rewires_to_go--;
468  }
469 
470  // Wait for the last DMA to complete
471  wait_for_dma_to_complete();
472 
473  // Start the next DMA read
474  if (dma_in_progress) {
475  dma_buffers[next_buffer].sdram_writeback_address = result.row_address;
476  dma_buffers[next_buffer].n_bytes_transferred = result.n_bytes_to_transfer;
477  do_fast_dma_read(result.row_address, dma_buffers[next_buffer].row,
478  result.n_bytes_to_transfer);
479  next_buffer = (next_buffer + 1) & DMA_BUFFER_MOD_MASK;
480  }
481 
482  // If the row has been restructured, transfer back to SDRAM
484  time, dma_buffers[current_buffer].row)) {
486  if (dma_in_progress) {
487  wait_for_dma_to_complete();
488  }
489  do_fast_dma_write(
490  dma_buffers[current_buffer].row,
491  dma_buffers[current_buffer].sdram_writeback_address,
492  dma_buffers[current_buffer].n_bytes_transferred);
493  if (!dma_in_progress) {
494  wait_for_dma_to_complete();
495  }
496  }
497  current_buffer = (current_buffer + 1) & DMA_BUFFER_MOD_MASK;
498  }
499 }
500 
501 void spike_processing_fast_time_step_loop(uint32_t time, uint32_t n_rewires) {
502 
503  // Prepare for the start
504  if (!prepare_timestep(time)) {
505  skipped_time_steps++;
506  process_end_of_time_step(time);
507  return;
508  }
509 
510  // Do rewiring
511  do_rewiring(time, n_rewires);
512 
513  // Loop until the end of a time step is reached
514  while (true) {
515 
516  // Wait for a spike, or the timer to expire
517  uint32_t spike;
518  while (!is_end_of_time_step() && !get_next_spike(time, &spike)) {
519  // This doesn't wait for interrupt currently because there isn't
520  // a way to have a T2 interrupt without a callback function, and
521  // a callback function is too slow! This is therefore a busy wait.
522  // wait_for_interrupt();
523  }
524 
525  // If the timer has gone off, that takes precedence
526  if (is_end_of_time_step()) {
527  clear_end_of_time_step();
528  process_end_of_time_step(time);
529  return;
530  }
531 
532  // There must be a spike! Start a DMA processing loop...
534  bool dma_in_progress = start_first_dma(time, &spike, &result);
535  while (dma_in_progress && !is_end_of_time_step()) {
536 
537  // If self-connected looped back spike then process post event here
538  if (((spike & key_config.mask) == key_config.key) &&
542  }
543 
544  // See if there is another DMA to do
545  dma_in_progress = get_next_dma(time, &spike, &result);
546 
547  // Finish the current DMA before starting the next
548  if (!wait_for_dma_to_complete_or_end()) {
550  break;
551  }
553  if (dma_in_progress) {
554  read_synaptic_row(spike, &result);
555  }
556 
557  // Process the row we already have while the DMA progresses
558  process_current_row(time, dma_in_progress);
559 
560  }
561 
562  }
563 }
564 
565 static inline void check_times(void) {
566  uint32_t tc_time = tc[T1_COUNT];
567  if (tc_time > earliest_spike_received_time) {
568  earliest_spike_received_time = tc_time;
569  }
570  if (tc_time < latest_spike_received_time) {
571  latest_spike_received_time = tc_time;
572  }
573 }
574 
578 void multicast_packet_received_callback(uint key, UNUSED uint unused) {
579  log_debug("Received spike %x", key);
580  p_per_ts_struct.packets_this_time_step++;
582  check_times();
583 }
584 
588 void multicast_packet_pl_received_callback(uint key, uint payload) {
589  log_debug("Received spike %x with payload %d", key, payload);
590  p_per_ts_struct.packets_this_time_step++;
591 
592  // cycle through the packet insertion
593  for (uint count = payload; count > 0; count--) {
595  }
596  check_times();
597 }
598 
600  uint32_t row_max_n_words, uint32_t spike_buffer_size,
601  bool discard_late_packets, uint32_t pkts_per_ts_rec_region,
602  uint32_t multicast_priority, struct sdram_config sdram_inputs_param,
603  struct key_config key_config_param, weight_t *ring_buffers_param) {
604  // Allocate the DMA buffers
605  for (uint32_t i = 0; i < N_DMA_BUFFERS; i++) {
606  dma_buffers[i].row = spin1_malloc(row_max_n_words * sizeof(uint32_t));
607  if (dma_buffers[i].row == NULL) {
608  log_error("Could not initialise DMA buffers of %u words",
609  row_max_n_words);
610  return false;
611  }
612  log_debug("DMA buffer %u allocated at 0x%08x",
613  i, dma_buffers[i].row);
614  }
616  next_buffer_to_process = 0;
617 
618  // Allocate incoming spike buffer
620  return false;
621  }
622 
623  // Store parameters and data
624  clear_input_buffers_of_late_packets = discard_late_packets;
625  p_per_ts_region = pkts_per_ts_rec_region;
626  sdram_inputs = sdram_inputs_param;
627  key_config = key_config_param;
628  ring_buffers = ring_buffers_param;
629 
630  // Configure for multicast reception
631  spin1_callback_on(MC_PACKET_RECEIVED, multicast_packet_received_callback,
632  multicast_priority);
633  spin1_callback_on(MCPL_PACKET_RECEIVED, multicast_packet_pl_received_callback,
634  multicast_priority);
635 
636  // Wipe the inputs using word writes
637  for (uint32_t i = 0; i < (sdram_inputs.size_in_bytes >> 2); i++) {
638  sdram_inputs.address[i] = 0;
639  }
640 
641  return true;
642 }
643 
645  struct spike_processing_fast_provenance *prov) {
652  prov->max_spikes_processed = max_spikes_processed;
654  prov->n_transfer_timer_overruns = transfer_timer_overruns;
655  prov->n_skipped_time_steps = skipped_time_steps;
656  prov->max_transfer_timer_overrun = max_transfer_timer_overrun;
657  prov->earliest_receive = earliest_spike_received_time;
658  prov->latest_receive = latest_spike_received_time;
659  prov->max_spikes_overflow = max_spikes_overflow;
660 }
static weight_t * ring_buffers
The ring buffers to be used in the simulation.
Definition: c_main.c:118
static struct sdram_config sdram_inputs
The SDRAM input configuration data.
static bool clear_input_buffers_of_late_packets
Whether to clear packets each timestep.
static uint32_t key
Base multicast key for sending messages.
static uint32_t time
Simulation time.
static uint32_t count_input_buffer_packets_late
number of packets late
static bool in_spikes_get_next_spike(spike_t *spike)
Retrieves a spike from the input spike buffer.
Definition: in_spikes.h:66
static circular_buffer buffer
Buffer for quickly taking spikes received by a fast interrupt and queueing them for later processing ...
Definition: in_spikes.h:28
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.
uint32_t synapse_delay_mask
The mask to get the synaptic delay from a "synapse".
Definition: local_only.c:71
static uint32_t max_spikes_received
The maximum number of spikes received in any time step.
Definition: local_only.c:59
uint32_t synapse_type_index_bits
The number of bits used by the synapse type and post-neuron index.
Definition: local_only.c:74
uint32_t synapse_index_bits
The number of bits used by just the post-neuron index.
Definition: local_only.c:77
uint32_t p_per_ts_region
The region where packets-per-timestep are stored.
Definition: local_only.c:80
static struct @8 p_per_ts_struct
The number of packets received this time step for recording.
struct synaptic_row * synaptic_row_t
The type of a synaptic row.
uint32_t spike_t
The type of a spike.
Master pop(ulation) table API.
bool population_table_get_next_address(spike_t *spike, pop_table_lookup_result_t *result)
Get the next row data for a previously given spike. If no spike has been given, return False.
static bool population_table_is_next(void)
Determine if there are more items with the same key.
bool population_table_get_first_address(spike_t spike, pop_table_lookup_result_t *result)
Get the first row data for the given input spike.
A structure to hold a response to a population table lookup.
#define N_DMA_BUFFERS
The number of DMA Buffers to use.
static uint32_t spike_processing_count
the number of spikes that were processed (used in provenance generation)
static uint32_t n_successful_rewires
The number of successful rewires.
static uint32_t next_buffer_to_fill
The index of the next buffer to be filled by a DMA.
static uint32_t biggest_fill_size_of_input_buffer
tracker of how full the input buffer got.
static void multicast_packet_received_callback(uint key, uint unused)
Called when a multicast packet is received.
static dma_buffer dma_buffers[N_DMA_BUFFERS]
The DTCM buffers for the synapse rows.
static void multicast_packet_pl_received_callback(uint key, uint payload)
Called when a multicast packet is received.
static uint32_t dma_complete_count
the number of DMA completes (used in provenance generation)
Spike processing fast API.
uint32_t spike_id_mask
The mask to get the spike ID.
uint32_t n_packets_dropped_from_lateness
The number of packets that were cleared at the end of timesteps.
uint32_t max_spikes_overflow
The most spikes left at the end of any time step.
uint32_t max_filled_input_buffer_size
The maximum size of the input buffer.
uint32_t mask
The mask.
uint32_t n_dmas_complete
The number of DMAs performed.
void spike_processing_fast_time_step_loop(uint32_t time, uint32_t n_rewires)
The main loop of spike processing to be run once per time step. Note that this function will not retu...
uint32_t n_rewires
The number of rewires performed.
uint32_t self_connected
Is the node self connected.
uint32_t n_skipped_time_steps
The number of times a time step was skipped entirely.
void spike_processing_fast_store_provenance(struct spike_processing_fast_provenance *prov)
Store any provenance data gathered from spike processing.
uint32_t key
The key.
uint32_t n_input_buffer_overflows
A count of the times that the synaptic input circular buffers overflowed.
uint32_t n_transfer_timer_overruns
The number of times the transfer took longer than expected.
uint32_t max_spikes_received
The maximum number of spikes received in a time step.
bool spike_processing_fast_initialise(uint32_t row_max_n_words, uint32_t spike_buffer_size, bool discard_late_packets, uint32_t pkts_per_ts_rec_region, uint32_t multicast_priority, struct sdram_config sdram_inputs_param, struct key_config key_config_param, weight_t *ring_buffers_param)
Set up spike processing.
uint32_t n_spikes_processed
The number of spikes received and processed.
uint32_t max_spikes_processed
The maximum number of spikes processed in a time step.
uint32_t max_transfer_timer_overrun
The maximum additional time taken to transfer.
uint32_t earliest_receive
The earliest received time of a spike.
uint32_t latest_receive
The latest received time of a spike.
uint32_t colour_shift
The colour shift to apply after masking.
Provenance for spike processing.
uint32_t size_in_bytes
The size of the input data to be transferred per core.
uint8_t * address
The start address of the input data to be transferred.
uint32_t time_for_transfer_overhead
The time of the transfer in us.
static uint32_t spike_buffer_size
The size of each spike buffer in bytes.
A region of SDRAM used to transfer synapses.
spike_t originating_spike
Key of originating spike.
synaptic_row_t row
Row data.
uint32_t n_bytes_transferred
Number of bytes transferred in the read.
synaptic_row_t sdram_writeback_address
Address in SDRAM to write back plastic region to.
uint32_t colour
Spike colour.
uint32_t colour_mask
Spike colour mask.
API for synapse dynamics.
void synapse_dynamics_process_post_synaptic_event(uint32_t time, index_t neuron_index)
Inform the synapses that the neuron fired.
static index_t synapse_row_get_first_ring_buffer_index(uint32_t simulation_timestep, uint32_t synapse_type_index_bits, int32_t synapse_delay_mask)
Get the index of the first ring buffer for a given timestep.
Definition: synapse_row.h:285
static uint32_t * synapse_row_fixed_weight_controls(synapse_row_fixed_part_t *fixed)
The array of fixed weights in the row.
Definition: synapse_row.h:180
static synapse_row_fixed_part_t * synapse_row_fixed_region(synaptic_row_t row)
Get the address of the non-plastic (or fixed) region.
Definition: synapse_row.h:147
static index_t synapse_row_sparse_type(uint32_t x, uint32_t synapse_index_bits, uint32_t synapse_type_mask)
Get the type code.
Definition: synapse_row.h:201
static size_t synapse_row_num_fixed_synapses(const synapse_row_fixed_part_t *fixed)
Get the number of fixed synapses in the row.
Definition: synapse_row.h:156
static index_t synapse_row_sparse_index(uint32_t x, uint32_t synapse_index_mask)
Get the index.
Definition: synapse_row.h:190
static index_t synapse_row_sparse_delay(uint32_t x, uint32_t synapse_type_index_bits, uint32_t synapse_delay_mask)
Get the delay from an encoded synapse descriptor.
Definition: synapse_row.h:222
static synapse_row_plastic_data_t * synapse_row_plastic_region(synaptic_row_t row)
Get the address of the plastic region.
Definition: synapse_row.h:138
static size_t synapse_row_plastic_size(const synaptic_row_t row)
Get the size of the plastic region.
Definition: synapse_row.h:129
The type of the fixed part of the row. The fixed-plastic part follows.
Definition: synapse_row.h:118
void synapses_flush_ring_buffers(timer_t time)
Reset the ring buffers to 0 at the given time.
Definition: synapses.c:336
uint32_t synapse_index_mask
Mask to pick out the synapse index.
Definition: synapses.c:69
bool synapses_process_synaptic_row(uint32_t time, uint32_t spike_colour, uint32_t colour_mask, synaptic_row_t row, bool *write_back)
process a synaptic row
Definition: synapses.c:351
uint32_t synapse_type_mask
Mask to pick out the synapse type.
Definition: synapses.c:73
Operations on synapses.
This file contains the main interface for structural plasticity.
bool synaptogenesis_dynamics_rewire(uint32_t time, spike_t *spike, pop_table_lookup_result_t *result)
Trigger the process of synaptic rewiring.
void synaptogenesis_spike_received(uint32_t time, spike_t spike)
Indicates that a spike has been received.
bool synaptogenesis_row_restructure(uint32_t time, synaptic_row_t row)
Perform the actual restructuring of a row.