20#include "local_only_impl.h"
21#include "local_only_2d_common.h"
25#include "../population_table/population_table.h"
84 uint32_t n_connectors_total;
85 uint32_t n_weights_total;
97static lc_weight_t *weights;
99static inline void log_div_const(
const char *name,
div_const d) {
100 log_debug(
" %s=(m: %u, sh1: %u, sh2: %u)", name, d.m, d.sh1, d.sh2);
104bool local_only_impl_initialise(
void *address){
105 log_info(
"+++++++++++++++++ CONV init ++++++++++++++++++++");
109 config = spin1_malloc(n_bytes);
111 log_error(
"Can't allocate memory for config!");
116 log_info(
"post_start = %u, %u, post_end = %u, %u, post_shape = %u, %u",
122 if (
config->n_sources == 0) {
130 uint32_t n_connector_bytes =
sizeof(
connector) *
config->n_connectors_total;
131 connectors = spin1_malloc(n_connector_bytes);
132 if (connectors == NULL) {
133 log_error(
"Can't allocate %u bytes of memory for %u connectors!",
134 n_connector_bytes,
config->n_connectors_total);
137 spin1_memcpy(connectors, sdram_connectors, n_connector_bytes);
140 lc_weight_t *kernel_weights =
141 (lc_weight_t *) &(sdram_connectors[
config->n_connectors_total]);
142 uint32_t n_weight_bytes =
sizeof(lc_weight_t) *
config->n_weights_total;
143 weights = spin1_malloc(n_weight_bytes);
144 if (weights == NULL) {
145 log_error(
"Can't allocate %u bytes of memory for %u weights!",
146 n_weight_bytes,
config->n_weights_total);
152 for (uint32_t i = 0; i <
config->n_sources; i++) {
154 log_debug(
"Source %u: key=0x%08x, mask=0x%08x, start=%u, count=%u",
157 log_debug(
" core_mask=0x%08x, mask_shift=0x%08x",
159 log_debug(
" height_per_core=%u, width_per_core=%u",
161 log_debug(
" height_last_core=%u, width_last_core=%u",
163 log_debug(
" cores_per_height=%u, cores_per_width=%u",
170 for (uint32_t i = 0; i <
config->n_connectors_total; i++) {
185 int16_t half_kh, int16_t half_kw) {
200static inline void do_convolution_operation(
206 log_debug(
"pre row %d, col %d AS post row %d, col %d",
207 pre_coord.row, pre_coord.col, post_coord.row, post_coord.col);
209 uint32_t sat_flag = 0xFFFF0000;
210 uint32_t sat_value = 0xFFFF;
213 for (int32_t r = -half_kh, kr = 0; r <= half_kh; r++, kr++) {
214 int32_t tmp_row = post_coord.row + r;
215 if ((tmp_row < config->post_start.row) || (tmp_row >
config->post_end.row)) {
218 for (int32_t c = -half_kw, kc = 0; c <= half_kw; c++, kc++) {
219 int32_t tmp_col = post_coord.col + c;
220 if ((tmp_col < config->post_start.col) || (tmp_col >
config->post_end.col)) {
225 uint32_t post_index =
226 ((tmp_row -
config->post_start.row) *
config->post_shape.width)
227 + (tmp_col -
config->post_start.col);
228 uint32_t k = (kr * kw) + kc;
229 lc_weight_t weight = connector_weights[k];
233 uint32_t rb_index = 0;
246 log_debug(
"Updating ring_buffers[%u] for post neuron %u = %u, %u, with weight %u",
247 rb_index, post_index, tmp_col, tmp_row, weight);
250 uint32_t accumulation =
ring_buffers[rb_index] + weight;
251 uint32_t sat_test = accumulation & sat_flag;
253 accumulation = sat_value;
260static inline uint32_t get_core_row(uint32_t core_id,
source_info *s_info) {
264static inline uint32_t get_core_col(uint32_t core_id, uint32_t core_row,
269static inline bool is_last_core_on_row(uint32_t core_col,
source_info *s_info) {
273static inline bool is_last_core_in_col(uint32_t core_row,
source_info *s_info) {
277static inline bool key_to_index_lookup(uint32_t spike,
source_info **rs_info) {
278 for (uint32_t i = 0; i <
config->n_sources; i++) {
295void local_only_impl_process_spike(
296 uint32_t time, uint32_t spike, uint16_t*
ring_buffers) {
300 if (!key_to_index_lookup(spike, &s_info)) {
301 log_debug(
"Spike %x didn't match any connectors!", spike);
305 uint32_t core_id = get_core_id(spike, s_info->
key_info);
306 uint32_t core_row = get_core_row(core_id, s_info);
307 uint32_t core_col = get_core_col(core_id, core_row, s_info);
308 bool last_core_on_row = is_last_core_on_row(core_col, s_info);
309 bool last_core_in_col = is_last_core_in_col(core_row, s_info);
310 uint32_t source_height = 0;
311 uint32_t source_width = 0;
313 if (last_core_on_row) {
320 if (last_core_in_col) {
325 uint32_t local_id = get_local_id(spike, s_info->
key_info);
326 uint32_t neurons_per_core = source_width * source_height;
328 log_debug(
"Spike %x, on core %u (%u, %u), is last (%u, %u), local %u",
329 spike, core_id, core_col, core_row, last_core_on_row, last_core_in_col,
339 uint32_t last_neuron = first_neuron + neurons_per_core;
340 log_debug(
"Connector %u, delay stage = %u, first = %u, last = %u",
342 if (local_id < first_neuron || local_id >= last_neuron) {
346 uint32_t local_neuron_id = local_id - first_neuron;
347 uint32_t local_row = div_by_const(local_neuron_id, source_width_d);
348 uint32_t local_col = local_neuron_id - (local_row * source_width);
357 log_debug(
"Local coord = %u, %u, Pre coord = %u, %u",
358 local_col, local_row, pre_coord.col, pre_coord.col);
static weight_t * ring_buffers
The ring buffers to be used in the simulation.
void log_error(const char *message,...)
void log_debug(const char *message,...)
void log_info(const char *message,...)
uint32_t synapse_delay_mask
The mask to get the synaptic delay from a "synapse".
uint32_t synapse_type_index_bits
The number of bits used by the synapse type and post-neuron index.
uint32_t synapse_index_bits
The number of bits used by just the post-neuron index.
div_const source_width_last_div
Division by last core width.
key_info key_info
Information about the key.
uint32_t source_height_last_core
The source population height on the last core in a column.
uint32_t cores_per_source_width
Number of cores in a width of the source.
uint32_t source_height_per_core
The source population height per core.
uint32_t cores_per_source_height
The number cores in a height of the source.
div_const cores_per_width_div
Division by cores per source width.
uint32_t source_width_per_core
The source population width per core.
div_const source_width_div
Used to calculate division by the source width per core efficiently.
uint32_t source_width_last_core
The source population width on the last core on a row.
A region of SDRAM used to transfer synapses.
Collection of rates to apply over time to a particular spike source.
void spin1_memcpy(void *dst, void const *src, uint len)
div_const pool_stride_width_div
1 / pooling stride width
div_const stride_width_div
1 / stride width;
uint16_t kernel_index
The index of the weights for the kernel.
lc_shape_t padding
The shape of the padding.
div_const stride_height_div
1 / stride height
uint16_t delay
The delay in time steps.
uint16_t positive_synapse_type
The index of the synapse for positive weights.
lc_shape_t kernel
The shape of the kernel.
uint16_t negative_synapse_type
The index of the synapse for negative weights.
uint16_t delay_stage
The delay stage.
div_const pool_stride_height_div
1 / pooling stride height
Structure for constants for precise constant integer division (see div_by_const)
uint32_t start
The index into connectors for this entry.
uint32_t count
The number of entries in connectors for this entry.
uint32_t key
The key to match against the incoming message.
uint32_t mask_shift
The shift to apply to the key to get the core part.
uint32_t mask
The mask to select the relevant bits of key for matching.
uint32_t core_mask
The mask to apply to the key once shifted to get the core index.
A coordinate in terms of rows and columns (y and x)
A shape in terms of height and width.
static index_t synapse_row_get_ring_buffer_index(uint32_t simulation_timestep, uint32_t synapse_type_index, uint32_t neuron_index, uint32_t synapse_type_index_bits, uint32_t synapse_index_bits, uint32_t synapse_delay_mask)
Get the index of the ring buffer for a given timestep, synapse type and neuron index.