sPyNNaker neural_modelling 7.3.1
Loading...
Searching...
No Matches
spike_processing.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015 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#include "spike_processing.h"
21#include "synapse_row.h"
22#include "synapses.h"
24#include <simulation.h>
25#include <debug.h>
26#include <common/in_spikes.h>
27#include <recording.h>
28
51
53#define N_DMA_BUFFERS 2
54
62
64extern uint32_t time;
65
67static volatile bool dma_busy;
68
71
73static uint32_t next_buffer_to_fill;
74
76static uint32_t buffer_being_read;
77
79static volatile uint32_t rewires_to_do = 0;
80
84static uint32_t dma_n_rewires;
85
89static uint32_t dma_n_spikes;
90
92static uint32_t dma_complete_count;
93
95static uint32_t spike_processing_count;
96
98static uint32_t n_successful_rewires;
99
103
106
110
112static struct {
113 uint32_t time;
114 uint32_t packets_this_time_step;
116
118static uint32_t p_per_ts_region;
119
120/* PRIVATE FUNCTIONS - static for inlining */
121
125static inline void do_dma_read(
126 spike_t spike, pop_table_lookup_result_t *result) {
127 // Write the SDRAM address of the plastic region and the
128 // Key of the originating spike to the beginning of DMA buffer
130 next_buffer->sdram_writeback_address = result->row_address;
131 next_buffer->originating_spike = spike;
132 next_buffer->n_bytes_transferred = result->n_bytes_to_transfer;
133 next_buffer->colour = result->colour;
134 next_buffer->colour_mask = result->colour_mask;
135
136 // Start a DMA transfer to fetch this synaptic row into current
137 // buffer
139 while (!spin1_dma_transfer(
140 DMA_TAG_READ_SYNAPTIC_ROW, result->row_address, next_buffer->row, DMA_READ,
141 result->n_bytes_to_transfer)) {
142 // Do Nothing
143 }
145}
146
153static inline bool is_something_to_do(
154 spike_t *spike, pop_table_lookup_result_t *result, uint32_t *n_rewire,
155 uint32_t *n_process_spike) {
156 // Disable interrupts here as dma_busy modification is a critical section
157 uint cpsr = spin1_int_disable();
158
159 // Check for synaptic rewiring
160 while (rewires_to_do) {
162 spin1_mode_restore(cpsr);
163 if (synaptogenesis_dynamics_rewire(time, spike, result)) {
164 *n_rewire += 1;
165 return true;
166 }
167 cpsr = spin1_int_disable();
168 }
169
170 // Is there another address in the population table?
171 spin1_mode_restore(cpsr);
172 if (population_table_get_next_address(spike, result)) {
173 *n_process_spike += 1;
174 return true;
175 }
176 cpsr = spin1_int_disable();
177
178 // track for provenance
179 uint32_t input_buffer_filled_size = in_spikes_size();
180 if (biggest_fill_size_of_input_buffer < input_buffer_filled_size) {
181 biggest_fill_size_of_input_buffer = input_buffer_filled_size;
182 }
183
184 // Are there any more spikes to process?
185 while (in_spikes_get_next_spike(spike)) {
186 // Enable interrupts while looking up in the master pop table,
187 // as this can be slow
188 spin1_mode_restore(cpsr);
189 if (population_table_get_first_address(*spike, result)) {
191 *n_process_spike += 1;
192 return true;
193 }
194
195 // Disable interrupts before checking if there is another spike
196 cpsr = spin1_int_disable();
197 }
198
199 // If nothing to do, the DMA is not busy
200 dma_busy = false;
201
202 // Restore interrupts
203 spin1_mode_restore(cpsr);
204 return false;
205}
206
220static bool setup_synaptic_dma_read(dma_buffer *current_buffer,
221 uint32_t *n_rewires, uint32_t *n_synapse_processes) {
222 // Set up to store the DMA location and size to read
223 spike_t spike;
225 dma_n_spikes = 0;
226 dma_n_rewires = 0;
227
228 // Keep looking if there is something to do until a DMA can be done
229 bool setup_done = false;
230 while (!setup_done && is_something_to_do(
231 &spike, &result, &dma_n_rewires, &dma_n_spikes)) {
232 if (current_buffer != NULL &&
233 current_buffer->sdram_writeback_address == result.row_address) {
234 // If we can reuse the row, add on what we can use it for
235 // Note that only one of these will have a value of 1 with the
236 // other being set to 0, but we add both as it is simple
237 *n_rewires += dma_n_rewires;
238 *n_synapse_processes += dma_n_spikes;
239 dma_n_rewires = 0;
240 dma_n_spikes = 0;
241 // Although we can reuse the buffer, the colour might be different
242 current_buffer->colour = result.colour;
243 } else {
244 // If the row is in SDRAM, set up the transfer and we are done
245 do_dma_read(spike, &result);
246 setup_done = true;
247 }
248
249 // needs to be here to ensure that its only recording actual spike
250 // processing and not the surplus DMA requests.
252 }
253 return setup_done;
254}
255
260static inline void setup_synaptic_dma_write(
261 uint32_t dma_buffer_index, bool plastic_only) {
262 // Get pointer to current buffer
263 dma_buffer *buffer = &dma_buffers[dma_buffer_index];
264
265 // Get the number of plastic bytes and the write back address from the
266 // synaptic row
267 size_t write_size = buffer->n_bytes_transferred;
268 void *sdram_start_address = buffer->sdram_writeback_address;
269 void *dtcm_start_address = buffer->row;
270 if (plastic_only) {
271 write_size = synapse_row_plastic_size(buffer->row) * sizeof(uint32_t);
272 sdram_start_address = synapse_row_plastic_region(
273 buffer->sdram_writeback_address);
274 dtcm_start_address = synapse_row_plastic_region(buffer->row);
275 }
276
277 // Start transfer
278 while (!spin1_dma_transfer(DMA_TAG_WRITE_PLASTIC_REGION, sdram_start_address,
279 dtcm_start_address, DMA_WRITE, write_size)) {
280 // Do Nothing
281 }
282}
283
285static inline void start_dma_loop(void) {
286 // If we're not already processing synaptic DMAs,
287 // flag pipeline as busy and trigger a feed event
288 // NOTE: locking is not used here because this is assumed to be FIQ
289 if (!dma_busy) {
290 // Only set busy if successful.
291 // NOTE: Counts when unsuccessful are handled by the API
292 if (spin1_trigger_user_event(0, 0)) {
293 dma_busy = true;
294 }
295 }
296}
297
301static void multicast_packet_received_callback(uint key, UNUSED uint unused) {
302 p_per_ts_struct.packets_this_time_step += 1;
305 }
306}
307
312 p_per_ts_struct.packets_this_time_step += 1;
313
314 // cycle through the packet insertion
315 bool added = false;
316 for (uint count = payload; count > 0; count--) {
317 added = in_spikes_add_spike(key);
318 }
319 if (added) {
321 }
322}
323
327static void dma_complete_callback(UNUSED uint unused, UNUSED uint tag) {
328
329 // increment the dma complete count for provenance generation
331
332 // Get pointer to current buffer
333 uint32_t current_buffer_index = buffer_being_read;
334 dma_buffer *current_buffer = &dma_buffers[current_buffer_index];
335
336 // Start the next DMA transfer and get a count of the rewires and spikes
337 // that can be done on this row now (there might be more while the DMA
338 // was in progress). Note that either dma_n_rewires or dma_n_spikes is set
339 // to 1 here, with the other being 0. We take a copy of the count and this
340 // is the value added to for this processing, as setup_synaptic_dma will
341 // count repeats of the current spike
342 uint32_t n_rewires = dma_n_rewires;
343 uint32_t n_spikes = dma_n_spikes;
344 setup_synaptic_dma_read(current_buffer, &n_rewires, &n_spikes);
345
346 // Assume no write back but assume any write back is plastic only
347 bool write_back = false;
348 bool plastic_only = true;
349
350 // If rewiring, do rewiring first
351 for (uint32_t i = n_rewires; i > 0; i--) {
352 if (synaptogenesis_row_restructure(time, current_buffer->row)) {
353 write_back = true;
354 plastic_only = false;
356 }
357 }
358
359 // Process synaptic row repeatedly for any upcoming spikes
360 while (n_spikes > 0) {
361
362 // Process synaptic row, writing it back if it's the last time
363 // it's going to be processed
364 bool write_back_now = false;
366 time, current_buffer->colour, current_buffer->colour_mask,
367 current_buffer->row, &write_back_now)) {
368 log_error(
369 "Error processing spike 0x%.8x for address 0x%.8x"
370 " (local=0x%.8x)",
371 current_buffer->originating_spike,
372 current_buffer->sdram_writeback_address,
373 current_buffer->row);
374
375 // Print out the row for debugging
376 address_t row = (address_t) current_buffer->row;
377 for (uint32_t i = 0;
378 i < (current_buffer->n_bytes_transferred >> 2); i++) {
379 log_error("%u: 0x%08x", i, row[i]);
380 }
382 }
383
384 write_back |= write_back_now;
385 n_spikes--;
386 }
387
388 if (write_back) {
389 setup_synaptic_dma_write(current_buffer_index, plastic_only);
390 }
391}
392
396void user_event_callback(UNUSED uint unused0, UNUSED uint unused1) {
397 // Reset the counters as this is a new process
398 dma_n_rewires = 0;
399 dma_n_spikes = 0;
400
402 // If the DMA buffer is full of valid data, attempt to reuse it on the
403 // next data to be used, as this might be able to make use of the buffer
404 // without transferring data
406 } else {
407 // If the DMA buffer is invalid, just do the first transfer possible
409 }
410}
411
412/* INTERFACE FUNCTIONS - cannot be static */
414 uint32_t n_spikes = in_spikes_size();
418 dma_busy = false;
419 }
420
421 // Record the number of packets received last timer tick
422 p_per_ts_struct.time = time;
424 p_per_ts_struct.packets_this_time_step = 0;
425
426 // Record the count whether clearing or not for provenance
428}
429
431 size_t row_max_n_words, uint mc_packet_callback_priority,
432 uint user_event_priority, uint incoming_spike_buffer_size,
433 bool clear_input_buffers_of_late_packets_init,
434 uint32_t packets_per_timestep_region) {
435 // Allocate the DMA buffers
436 for (uint32_t i = 0; i < N_DMA_BUFFERS; i++) {
437 dma_buffers[i].row = spin1_malloc(row_max_n_words * sizeof(uint32_t));
438 if (dma_buffers[i].row == NULL) {
439 log_error("Could not initialise DMA buffers with %u words", row_max_n_words);
440 return false;
441 }
442 }
443 dma_busy = false;
445 clear_input_buffers_of_late_packets_init;
448 p_per_ts_region = packets_per_timestep_region;
449
450 // Allocate incoming spike buffer
451 if (!in_spikes_initialize_spike_buffer(incoming_spike_buffer_size)) {
452 return false;
453 }
454
455 // Set up the callbacks
457 multicast_packet_received_callback, mc_packet_callback_priority);
459 multicast_packet_pl_received_callback, mc_packet_callback_priority);
462 spin1_callback_on(USER_EVENT, user_event_callback, user_event_priority);
463
464 return true;
465}
466
475
476bool spike_processing_do_rewiring(int number_of_rewires) {
477 // disable interrupts
478 uint cpsr = spin1_int_disable();
479 rewires_to_do += number_of_rewires;
481 // enable interrupts
482 spin1_mode_restore(cpsr);
483 return true;
484}
uint32_t timer_t
uint32_t * address_t
void log_error(const char *message,...)
static uint32_t key
Base multicast key for sending messages.
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 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.
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.
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.
bool recording_record(channel_index_t channel, void *data, size_t size_bytes)
RTE_SWERR
void rt_error(uint code,...)
bool simulation_dma_transfer_done_callback_on(uint tag, callback_t callback)
#define N_DMA_BUFFERS
The number of DMA Buffers to use.
static void start_dma_loop(void)
Start the DMA processing loop if not already running.
void user_event_callback(uint unused0, uint unused1)
Called when a user event is received.
static uint32_t spike_processing_count
the number of spikes that were processed (used in provenance generation)
bool spike_processing_initialise(size_t row_max_n_words, uint mc_packet_callback_priority, uint user_event_priority, uint incoming_spike_buffer_size, bool clear_input_buffers_of_late_packets_init, uint32_t packets_per_timestep_region)
Initialise the spike processing system.
static bool setup_synaptic_dma_read(dma_buffer *current_buffer, uint32_t *n_rewires, uint32_t *n_synapse_processes)
Set up a new synaptic DMA read.
static uint32_t dma_n_spikes
The number of spikes to do when the DMA completes.
static void dma_complete_callback(uint unused, uint tag)
Called when a DMA completes.
bool spike_processing_do_rewiring(int number_of_rewires)
Set the number of times spike_processing has to attempt rewiring.
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 uint32_t buffer_being_read
The index of the buffer currently being filled by a DMA read.
static volatile uint32_t rewires_to_do
Number of outstanding synaptogenic rewires.
static void multicast_packet_received_callback(uint key, uint unused)
Called when a multicast packet is received.
static bool clear_input_buffers_of_late_packets
Whether if we should clear packets from the input buffer at the end of a timer tick.
static dma_buffer dma_buffers[N_DMA_BUFFERS]
The DTCM buffers for the synapse rows.
static volatile bool dma_busy
True if the DMA "loop" is currently running.
static void do_dma_read(spike_t spike, pop_table_lookup_result_t *result)
Perform a DMA read of a synaptic row.
static void multicast_packet_pl_received_callback(uint key, uint payload)
Called when a multicast packet is received.
static uint32_t p_per_ts_region
the region to record the packets per timestep in
void spike_processing_clear_input_buffer(timer_t time)
clears the input buffer of packets
static bool is_something_to_do(spike_t *spike, pop_table_lookup_result_t *result, uint32_t *n_rewire, uint32_t *n_process_spike)
Check if there is anything to do. If not, DMA is not busy.
void spike_processing_store_provenance(struct spike_processing_provenance *prov)
Get provenance data for Spike processing.
spike_processing_dma_tags
DMA tags.
@ DMA_TAG_READ_SYNAPTIC_ROW
Tag of a DMA read of a full synaptic row.
@ DMA_TAG_WRITE_PLASTIC_REGION
Tag of a DMA write of the plastic region of a synaptic row.
static void setup_synaptic_dma_write(uint32_t dma_buffer_index, bool plastic_only)
Set up a DMA write of synaptic data.
static uint32_t dma_complete_count
the number of DMA completes (used in provenance generation)
uint32_t time
The current timer tick value.
Definition c_main.c:94
static struct @13 p_per_ts_struct
the number of packets received this time step
static uint32_t count_input_buffer_packets_late
How many packets were lost from the input buffer because of late arrival.
static uint32_t dma_n_rewires
The number of rewires to do when the DMA completes.
Spike processing API.
uint32_t n_spikes_processed
The number of spikes received and processed.
uint32_t n_input_buffer_overflows
A count of the times that the synaptic input circular buffers overflowed.
uint32_t n_rewires
The number of rewires performed.
uint32_t max_filled_input_buffer_size
The maximum size of the input buffer.
uint32_t n_packets_dropped_from_lateness
The number of packets that were cleared at the end of timesteps.
uint32_t n_dmas_complete
The number of DMAs performed.
Provenance for spike processing.
MCPL_PACKET_RECEIVED
MC_PACKET_RECEIVED
USER_EVENT
#define NULL
uint spin1_trigger_user_event(uint arg0, uint arg1)
uint spin1_dma_transfer(uint tag, void *system_address, void *tcm_address, uint direction, uint length)
void spin1_dma_flush(void)
uint spin1_int_disable(void)
DMA_READ
DMA_WRITE
void spin1_mode_restore(uint value)
void spin1_callback_on(uint event_id, callback_t cback, int priority)
unsigned int uint
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.
implementation for handling the processing of synapse rows.
static synapse_row_plastic_data_t * synapse_row_plastic_region(synaptic_row_t row)
Get the address of the plastic region.
static size_t synapse_row_plastic_size(const synaptic_row_t row)
Get the size of the plastic region.
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
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.