diff --git a/neural_modelling/src/common/neuron-typedefs.h b/neural_modelling/src/common/neuron-typedefs.h index c148eee3a2..2b6a338407 100644 --- a/neural_modelling/src/common/neuron-typedefs.h +++ b/neural_modelling/src/common/neuron-typedefs.h @@ -95,8 +95,28 @@ static inline payload_t spike_payload(UNUSED spike_t s) { #endif /*SPIKES_WITH_PAYLOADS*/ #endif /*__SPIKE_T__*/ -//! The type of a synaptic row -typedef address_t synaptic_row_t; +//! \brief The type of a synaptic row. +//! \details There is no definition of `struct synaptic row` because it is a +//! form of memory structure that C cannot encode as a single `struct`. +//! +//! It's actually this, with multiple variable length arrays intermixed with +//! size counts: +//! ~~~~~~{.c} +//! struct synaptic_row { +//! uint32_t n_plastic_synapse_words; +//! uint32_t plastic_synapse_data[n_plastic_synapse_words]; // VLA +//! uint32_t n_fixed_synapse_words; +//! uint32_t n_plastic_controls; +//! uint32_t fixed_synapse_data[n_fixed_synapse_words]; // VLA +//! control_t plastic_control_data[n_plastic_controls]; // VLA +//! } +//! ~~~~~~ +//! +//! The relevant implementation structures are: +//! * ::synapse_row_plastic_part_t +//! * ::synapse_row_fixed_part_t +//! * ::single_synaptic_row_t +typedef struct synaptic_row *synaptic_row_t; //! The type of an input typedef REAL input_t; diff --git a/neural_modelling/src/neuron/direct_synapses.c b/neural_modelling/src/neuron/direct_synapses.c index bc03caddd7..1f1db85780 100644 --- a/neural_modelling/src/neuron/direct_synapses.c +++ b/neural_modelling/src/neuron/direct_synapses.c @@ -21,41 +21,50 @@ #include #include -//! The size of the fixed synapse buffer, in words -#define SIZE_OF_SINGLE_FIXED_SYNAPSE 4 +//! \brief The type of a singleton synaptic row. +//! \details The counts are constant. See ::synapse_row_plastic_part_t and +//! ::synapse_row_fixed_part_t for what this is a packed version of. +typedef struct single_synaptic_row_t { + const uint32_t n_plastic; //!< Number of plastic synapses. Always zero + const uint32_t n_fixed; //!< Number of fixed synapses. Always one + const uint32_t n_plastic_controls; //!< Number of plastic controls. Always zero + uint32_t synapse_datum; //!< The value of the single synapse +} single_synaptic_row_t; //! Working buffer for direct synapse access -static uint32_t single_fixed_synapse[SIZE_OF_SINGLE_FIXED_SYNAPSE]; +static single_synaptic_row_t single_fixed_synapse = {0, 1, 0, 0}; + +//! The layout of the direct matrix region +typedef struct { + const uint32_t size; //!< Size of data, _not_ number of elements + const uint32_t data[]; //!< Direct matrix data +} direct_matrix_data_t; bool direct_synapses_initialise( - address_t direct_matrix_address, address_t *direct_synapses_address) { + void *direct_matrix_address, address_t *direct_synapses_address) { + direct_matrix_data_t *direct_matrix = direct_matrix_address; // Work out the positions of the direct and indirect synaptic matrices // and copy the direct matrix to DTCM - uint32_t direct_matrix_size = direct_matrix_address[0]; + uint32_t direct_matrix_size = direct_matrix->size; log_info("Direct matrix malloc size is %d", direct_matrix_size); if (direct_matrix_size != 0) { - *direct_synapses_address = spin1_malloc(direct_matrix_size); - if (*direct_synapses_address == NULL) { + void *dtcm_copy = spin1_malloc(direct_matrix_size); + if (dtcm_copy == NULL) { log_error("Not enough memory to allocate direct matrix"); return false; } log_debug("Copying %u bytes of direct synapses to 0x%08x", - direct_matrix_size, *direct_synapses_address); - spin1_memcpy(*direct_synapses_address, &direct_matrix_address[1], - direct_matrix_size); + direct_matrix_size, dtcm_copy); + spin1_memcpy(dtcm_copy, direct_matrix->data, direct_matrix_size); + *direct_synapses_address = dtcm_copy; } - // Set up for single fixed synapses - // (data that is consistent per direct row) - single_fixed_synapse[0] = 0; - single_fixed_synapse[1] = 1; - single_fixed_synapse[2] = 0; - return true; } -synaptic_row_t direct_synapses_get_direct_synapse(address_t row_address) { - single_fixed_synapse[3] = (uint32_t) row_address[0]; - return (synaptic_row_t) single_fixed_synapse; +synaptic_row_t direct_synapses_get_direct_synapse(void *row_address) { + uint32_t *data = row_address; + single_fixed_synapse.synapse_datum = *data; + return (synaptic_row_t) &single_fixed_synapse; } diff --git a/neural_modelling/src/neuron/direct_synapses.h b/neural_modelling/src/neuron/direct_synapses.h index 388d98da86..5ed7571993 100644 --- a/neural_modelling/src/neuron/direct_synapses.h +++ b/neural_modelling/src/neuron/direct_synapses.h @@ -27,11 +27,11 @@ //! the DTCM address for the direct matrix //! \return true if successful, false otherwise. bool direct_synapses_initialise( - address_t direct_matrix_address, address_t *direct_synapses_address); + void *direct_matrix_address, address_t *direct_synapses_address); //! \brief Get the synapse for a given direct synaptic row. //! \param[in] row_address: the row address to read. //! \return the synaptic row synapse data. -synaptic_row_t direct_synapses_get_direct_synapse(address_t row_address); +synaptic_row_t direct_synapses_get_direct_synapse(void *row_address); #endif /* _DIRECT_SYNAPSES_H_ */ diff --git a/neural_modelling/src/neuron/plasticity/stdp/synapse_dynamics_stdp_mad_impl.c b/neural_modelling/src/neuron/plasticity/stdp/synapse_dynamics_stdp_mad_impl.c index 7172242748..83adf64362 100644 --- a/neural_modelling/src/neuron/plasticity/stdp/synapse_dynamics_stdp_mad_impl.c +++ b/neural_modelling/src/neuron/plasticity/stdp/synapse_dynamics_stdp_mad_impl.c @@ -430,11 +430,10 @@ uint32_t synapse_dynamics_get_plastic_saturation_count(void) { } bool synapse_dynamics_find_neuron( - uint32_t id, address_t row, weight_t *weight, uint16_t *delay, + uint32_t id, synaptic_row_t row, weight_t *weight, uint16_t *delay, uint32_t *offset, uint32_t *synapse_type) { - address_t fixed_region = synapse_row_fixed_region(row); - synapse_row_plastic_data_t *plastic_data = (void *) - synapse_row_plastic_region(row); + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); + synapse_row_plastic_data_t *plastic_data = synapse_row_plastic_region(row); const plastic_synapse_t *plastic_words = plastic_data->synapses; const control_t *control_words = synapse_row_plastic_controls(fixed_region); int32_t plastic_synapse = synapse_row_num_plastic_controls(fixed_region); @@ -458,10 +457,9 @@ bool synapse_dynamics_find_neuron( return false; } -bool synapse_dynamics_remove_neuron(uint32_t offset, address_t row) { - address_t fixed_region = synapse_row_fixed_region(row); - synapse_row_plastic_data_t *plastic_data = (void *) - synapse_row_plastic_region(row); +bool synapse_dynamics_remove_neuron(uint32_t offset, synaptic_row_t row) { + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); + synapse_row_plastic_data_t *plastic_data = synapse_row_plastic_region(row); plastic_synapse_t *plastic_words = plastic_data->synapses; control_t *control_words = synapse_row_plastic_controls(fixed_region); int32_t plastic_synapse = synapse_row_num_plastic_controls(fixed_region); @@ -474,12 +472,11 @@ bool synapse_dynamics_remove_neuron(uint32_t offset, address_t row) { control_words[plastic_synapse - 1] = 0; // Decrement FP - fixed_region[1]--; - + fixed_region->num_plastic--; return true; } -//! \brief packing all of the information into the required plastic control word +//! \brief Pack all of the information into the required plastic control word //! \param[in] id: The spike ID //! \param[in] delay: The delay //! \param[in] type: The synapse type @@ -493,14 +490,13 @@ static inline control_t control_conversion( return new_control; } -bool synapse_dynamics_add_neuron(uint32_t id, address_t row, +bool synapse_dynamics_add_neuron(uint32_t id, synaptic_row_t row, weight_t weight, uint32_t delay, uint32_t type) { plastic_synapse_t new_weight = synapse_structure_create_synapse(weight); control_t new_control = control_conversion(id, delay, type); - address_t fixed_region = synapse_row_fixed_region(row); - synapse_row_plastic_data_t *plastic_data = (void *) - synapse_row_plastic_region(row); + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); + synapse_row_plastic_data_t *plastic_data = synapse_row_plastic_region(row); plastic_synapse_t *plastic_words = plastic_data->synapses; control_t *control_words = synapse_row_plastic_controls(fixed_region); int32_t plastic_synapse = synapse_row_num_plastic_controls(fixed_region); @@ -512,10 +508,11 @@ bool synapse_dynamics_add_neuron(uint32_t id, address_t row, control_words[plastic_synapse] = new_control; // Increment FP - fixed_region[1]++; + fixed_region->num_plastic++; return true; } -uint32_t synapse_dynamics_n_connections_in_row(address_t fixed) { +uint32_t synapse_dynamics_n_connections_in_row( + synapse_row_fixed_part_t *fixed) { return synapse_row_num_plastic_controls(fixed); } diff --git a/neural_modelling/src/neuron/plasticity/synapse_dynamics.h b/neural_modelling/src/neuron/plasticity/synapse_dynamics.h index f678072d67..c6ad87ed21 100644 --- a/neural_modelling/src/neuron/plasticity/synapse_dynamics.h +++ b/neural_modelling/src/neuron/plasticity/synapse_dynamics.h @@ -36,17 +36,18 @@ bool synapse_dynamics_initialise( address_t address, uint32_t n_neurons, uint32_t n_synapse_types, uint32_t *ring_buffer_to_input_buffer_left_shifts); -//! \brief Processes the dynamics of the synapses +//! \brief Process the dynamics of the synapses //! \param[in,out] plastic_region_address: Where the plastic data is -//! \param[in] fixed_region_address: Where the fixed data is +//! \param[in] fixed_region: Where the fixed data is //! \param[in,out] ring_buffers: The ring buffers //! \param[in] time: The current simulation time //! \return ??? bool synapse_dynamics_process_plastic_synapses( - address_t plastic_region_address, address_t fixed_region_address, + address_t plastic_region_address, + synapse_row_fixed_part_t *fixed_region, weight_t *ring_buffers, uint32_t time); -//! \brief Informs the synapses that the neuron fired +//! \brief Inform the synapses that the neuron fired //! \param[in] time: The current simulation time //! \param[in] neuron_index: Which neuron are we processing void synapse_dynamics_process_post_synaptic_event( @@ -61,19 +62,20 @@ input_t synapse_dynamics_get_intrinsic_bias( //! \brief Print the synapse dynamics //! \param[in] plastic_region_address: Where the plastic data is -//! \param[in] fixed_region_address: Where the fixed data is +//! \param[in] fixed_region: Where the fixed data is //! \param[in] ring_buffer_to_input_buffer_left_shifts: //! How to interpret the values from the ring buffers void synapse_dynamics_print_plastic_synapses( - address_t plastic_region_address, address_t fixed_region_address, + address_t plastic_region_address, + synapse_row_fixed_part_t *fixed_region, uint32_t *ring_buffer_to_input_buffer_left_shifts); -//! \brief returns the counters for plastic pre synaptic events based on (if +//! \brief Get the counters for plastic pre synaptic events based on (if //! the model was compiled with SYNAPSE_BENCHMARK parameter) or returns 0 //! \return counters for plastic pre synaptic events or 0 uint32_t synapse_dynamics_get_plastic_pre_synaptic_events(void); -//! \brief returns the number of ring buffer saturation events due to adding +//! \brief Get the number of ring buffer saturation events due to adding //! plastic weights. //! \return counter for saturation events or 0 uint32_t synapse_dynamics_get_plastic_saturation_count(void); @@ -82,7 +84,7 @@ uint32_t synapse_dynamics_get_plastic_saturation_count(void); // Synaptic rewiring functions //----------------------------------------------------------------------------- -//! \brief Searches the synaptic row for the the connection with the +//! \brief Search the synaptic row for the the connection with the //! specified post-synaptic ID //! \param[in] id: the (core-local) ID of the neuron to search for in the //! synaptic row @@ -90,17 +92,17 @@ uint32_t synapse_dynamics_get_plastic_saturation_count(void); //! \param[out] weight: address to contain the weight of the connection //! \param[out] delay: address to contain the delay of the connection //! \param[out] offset: address to contain the offset of the connection -//! \param[out] synapse_type: address to contain the synapse type of the connection +//! \param[out] synapse_type: the synapse type of the connection //! \return was the search successful? bool synapse_dynamics_find_neuron( - uint32_t id, address_t row, weight_t *weight, uint16_t *delay, + uint32_t id, synaptic_row_t row, weight_t *weight, uint16_t *delay, uint32_t *offset, uint32_t *synapse_type); //! \brief Remove the entry at the specified offset in the synaptic row //! \param[in] offset: the offset in the row at which to remove the entry //! \param[in] row: the core-local address of the synaptic row //! \return was the removal successful? -bool synapse_dynamics_remove_neuron(uint32_t offset, address_t row); +bool synapse_dynamics_remove_neuron(uint32_t offset, synaptic_row_t row); //! \brief Add an entry in the synaptic row //! \param[in] id: the (core-local) ID of the post-synaptic neuron to be added @@ -110,12 +112,12 @@ bool synapse_dynamics_remove_neuron(uint32_t offset, address_t row); //! \param[in] type: the type of the connection (e.g. inhibitory) //! \return was the addition successful? bool synapse_dynamics_add_neuron( - uint32_t id, address_t row, weight_t weight, + uint32_t id, synaptic_row_t row, weight_t weight, uint32_t delay, uint32_t type); //! \brief Get the number of connections in the given row //! \param[in] fixed: the fixed region of the synaptic row //! \return The number of connections in the row -uint32_t synapse_dynamics_n_connections_in_row(address_t fixed); +uint32_t synapse_dynamics_n_connections_in_row(synapse_row_fixed_part_t *fixed); #endif // _SYNAPSE_DYNAMICS_H_ diff --git a/neural_modelling/src/neuron/plasticity/synapse_dynamics_static_impl.c b/neural_modelling/src/neuron/plasticity/synapse_dynamics_static_impl.c index 4caabb5207..2158699102 100644 --- a/neural_modelling/src/neuron/plasticity/synapse_dynamics_static_impl.c +++ b/neural_modelling/src/neuron/plasticity/synapse_dynamics_static_impl.c @@ -71,7 +71,7 @@ void synapse_dynamics_process_post_synaptic_event( //--------------------------------------- bool synapse_dynamics_process_plastic_synapses( UNUSED address_t plastic_region_address, - UNUSED address_t fixed_region_address, + UNUSED synapse_row_fixed_part_t *fixed_region, UNUSED weight_t *ring_buffer, UNUSED uint32_t time) { log_error("There should be no plastic synapses!"); return false; @@ -85,7 +85,7 @@ input_t synapse_dynamics_get_intrinsic_bias( void synapse_dynamics_print_plastic_synapses( UNUSED address_t plastic_region_address, - UNUSED address_t fixed_region_address, + UNUSED synapse_row_fixed_part_t *fixed_region, UNUSED uint32_t *ring_buffer_to_input_left_shifts) { } @@ -98,9 +98,9 @@ uint32_t synapse_dynamics_get_plastic_saturation_count(void) { } bool synapse_dynamics_find_neuron( - uint32_t id, address_t row, weight_t *weight, uint16_t *delay, + uint32_t id, synaptic_row_t row, weight_t *weight, uint16_t *delay, uint32_t *offset, uint32_t *synapse_type) { - address_t fixed_region = synapse_row_fixed_region(row); + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); int32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); @@ -125,16 +125,16 @@ bool synapse_dynamics_find_neuron( return false; } -bool synapse_dynamics_remove_neuron(uint32_t offset, address_t row) { - address_t fixed_region = synapse_row_fixed_region(row); +bool synapse_dynamics_remove_neuron(uint32_t offset, synaptic_row_t row) { + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); int32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); - // Delete control word at offset (contains weight) - synaptic_words[offset] = synaptic_words[fixed_synapse-1]; + // Delete control word at offset (contains weight) + synaptic_words[offset] = synaptic_words[fixed_synapse - 1]; // Decrement FF - fixed_region[0] = fixed_region[0] - 1; + fixed_region->num_fixed--; return true; } @@ -151,9 +151,9 @@ static inline uint32_t _fixed_synapse_convert( } bool synapse_dynamics_add_neuron( - uint32_t id, address_t row, weight_t weight, + uint32_t id, synaptic_row_t row, weight_t weight, uint32_t delay, uint32_t type) { - address_t fixed_region = synapse_row_fixed_region(row); + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); int32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); uint32_t new_synapse = _fixed_synapse_convert(id, weight, delay, type); @@ -161,11 +161,12 @@ bool synapse_dynamics_add_neuron( // Add control word at offset synaptic_words[fixed_synapse] = new_synapse; - // Increment FF - fixed_region[0] = fixed_region[0] + 1; + // Increment FF + fixed_region->num_fixed++; return true; } -uint32_t synapse_dynamics_n_connections_in_row(address_t fixed) { +uint32_t synapse_dynamics_n_connections_in_row( + synapse_row_fixed_part_t *fixed) { return synapse_row_num_fixed_synapses(fixed); } diff --git a/neural_modelling/src/neuron/population_table/population_table.h b/neural_modelling/src/neuron/population_table/population_table.h index 0570ac01fb..963d03d680 100644 --- a/neural_modelling/src/neuron/population_table/population_table.h +++ b/neural_modelling/src/neuron/population_table/population_table.h @@ -39,7 +39,7 @@ extern uint32_t failed_bit_field_reads; //! they don't hit anything extern uint32_t bit_field_filtered_packets; -//! \brief Sets up the table +//! \brief Set up the table //! \param[in] table_address: The address of the start of the table data //! \param[in] synapse_rows_address: The address of the start of the synapse //! data @@ -63,7 +63,8 @@ bool population_table_load_bitfields(filter_region_t *filter_region); //! \param[out] n_bytes_to_transfer: Updated with the number of bytes to read //! \return True if there is a row to read, False if not bool population_table_get_first_address( - spike_t spike, address_t* row_address, size_t* n_bytes_to_transfer); + spike_t spike, synaptic_row_t* row_address, + size_t* n_bytes_to_transfer); //! \brief Get the next row data for a previously given spike. If no spike has //! been given, return False. @@ -72,7 +73,7 @@ bool population_table_get_first_address( //! \param[out] n_bytes_to_transfer: Updated with the number of bytes to read //! \return True if there is a row to read, False if not bool population_table_get_next_address( - spike_t *spike, address_t* row_address, size_t* n_bytes_to_transfer); - + spike_t *spike, synaptic_row_t* row_address, + size_t* n_bytes_to_transfer); #endif // _POPULATION_TABLE_H_ diff --git a/neural_modelling/src/neuron/population_table/population_table_binary_search_impl.c b/neural_modelling/src/neuron/population_table/population_table_binary_search_impl.c index 11d0ee7dae..00ce14fbfd 100644 --- a/neural_modelling/src/neuron/population_table/population_table_binary_search_impl.c +++ b/neural_modelling/src/neuron/population_table/population_table_binary_search_impl.c @@ -88,6 +88,15 @@ typedef union { // delayed and undelayed tables #define INVALID_ADDRESS ((1 << N_ADDRESS_BITS) - 1) +//! \brief The memory layout in SDRAM of the first part of the population table +//! configuration. Address list data (array of ::address_and_row_length) is +//! packed on the end. +typedef struct { + uint32_t table_length; + uint32_t addr_list_length; + master_population_table_entry data[]; +} pop_table_config_t; + //! The master population table. This is sorted. static master_population_table_entry *master_population_table; @@ -143,9 +152,8 @@ static inline uint32_t get_direct_address(address_and_row_length entry) { } //! \brief Get the standard address offset out of an entry -//! -//! The address is in units of four words, so this multiplies by 16 (= up -//! shifts by 4) +//! \details The address is in units of four words, so this multiplies by 16 +//! (= up shifts by 4) //! \param[in] entry: the table entry //! \return a row address (which is an offset) static inline uint32_t get_offset(address_and_row_length entry) { @@ -226,8 +234,7 @@ static inline uint32_t get_extended_neuron_id( } //! \brief Prints the master pop table. -//! -//! For debugging +//! \details For debugging static inline void print_master_population_table(void) { log_info("Master_population\n"); for (uint32_t i = 0; i < master_population_table_length; i++) { @@ -414,14 +421,14 @@ bool population_table_initialise( address_t table_address, address_t synapse_rows_address, address_t direct_rows_address, uint32_t *row_max_n_words) { log_debug("Population_table_initialise: starting"); + pop_table_config_t *config = (pop_table_config_t *) table_address; - master_population_table_length = table_address[0]; + master_population_table_length = config->table_length; log_debug("Master pop table length is %d\n", master_population_table_length); log_debug("Master pop table entry size is %d\n", sizeof(master_population_table_entry)); uint32_t n_master_pop_bytes = master_population_table_length * sizeof(master_population_table_entry); - uint32_t n_master_pop_words = n_master_pop_bytes >> 2; log_debug("Pop table size is %d\n", n_master_pop_bytes); // only try to malloc if there's stuff to malloc. @@ -433,7 +440,7 @@ bool population_table_initialise( } } - uint32_t address_list_length = table_address[1]; + uint32_t address_list_length = config->addr_list_length; uint32_t n_address_list_bytes = address_list_length * sizeof(address_list_entry); @@ -452,9 +459,8 @@ bool population_table_initialise( address_list_length, n_address_list_bytes); // Copy the master population table - spin1_memcpy(master_population_table, &table_address[2], - n_master_pop_bytes); - spin1_memcpy(address_list, &table_address[2 + n_master_pop_words], + spin1_memcpy(master_population_table, config->data, n_master_pop_bytes); + spin1_memcpy(address_list, &config->data[master_population_table_length], n_address_list_bytes); // Store the base address @@ -472,7 +478,8 @@ bool population_table_initialise( } bool population_table_get_first_address( - spike_t spike, address_t* row_address, size_t* n_bytes_to_transfer) { + spike_t spike, synaptic_row_t *row_address, + size_t *n_bytes_to_transfer) { // locate the position in the binary search / array log_debug("Searching for key %d", spike); @@ -547,7 +554,7 @@ bool population_table_get_first_address( bool population_table_get_next_address( spike_t *spike, address_t *row_address, size_t *n_bytes_to_transfer) { // If there are no more items in the list, return false - if (items_to_go <= 0) { + if (items_to_go == 0) { return false; } @@ -559,10 +566,9 @@ bool population_table_get_next_address( // If the row is a direct row, indicate this by specifying the // n_bytes_to_transfer is 0 if (item.is_single) { - *row_address = (address_t) (get_direct_address(item) + + *row_address = (synaptic_row_t) (get_direct_address(item) + (last_neuron_id * sizeof(uint32_t))); *n_bytes_to_transfer = 0; - is_valid = true; } else { uint32_t row_length = get_row_length(item); @@ -570,16 +576,15 @@ bool population_table_get_next_address( uint32_t stride = (row_length + N_SYNAPSE_ROW_HEADER_WORDS); uint32_t neuron_offset = last_neuron_id * stride * sizeof(uint32_t); - *row_address = (address_t) (block_address + neuron_offset); + *row_address = (synaptic_row_t) (block_address + neuron_offset); *n_bytes_to_transfer = stride * sizeof(uint32_t); - log_debug( - "neuron_id = %u, block_address = 0x%.8x," - "row_length = %u, row_address = 0x%.8x, n_bytes = %u", - last_neuron_id, block_address, row_length, *row_address, - *n_bytes_to_transfer); + log_debug("neuron_id = %u, block_address = 0x%.8x, " + "row_length = %u, row_address = 0x%.8x, n_bytes = %u", + last_neuron_id, block_address, row_length, *row_address, + *n_bytes_to_transfer); *spike = last_spike; - is_valid = true; } + is_valid = true; } next_item++; diff --git a/neural_modelling/src/neuron/spike_processing.c b/neural_modelling/src/neuron/spike_processing.c index 064f7f9edb..876b2404b6 100644 --- a/neural_modelling/src/neuron/spike_processing.c +++ b/neural_modelling/src/neuron/spike_processing.c @@ -32,7 +32,7 @@ //! about the read. typedef struct dma_buffer { //! Address in SDRAM to write back plastic region to - address_t sdram_writeback_address; + synaptic_row_t sdram_writeback_address; //! \brief Key of originating spike //! \details used to allow row data to be re-used for multiple spikes @@ -42,7 +42,7 @@ typedef struct dma_buffer { uint32_t n_bytes_transferred; //! Row data - address_t row; + synaptic_row_t row; } dma_buffer; //! The number of DMA Buffers to use @@ -74,15 +74,17 @@ static uint32_t buffer_being_read; //! Number of outstanding synaptogenic rewirings static volatile uint32_t rewires_to_do = 0; -//! The number of rewires to do when the DMA completes. When a DMA is first set -//! up, only this or dma_n_spikes can be 1 with the other being 0. +//! \brief The number of rewires to do when the DMA completes. +//! \details When a DMA is first set up, only this or ::dma_n_spikes can be 1 +//! with the other being 0. static uint32_t dma_n_rewires; -//! The number of spikes to do when the DMA completes. When a DMA is first set -//! up, only this or dma_n_rewires can be 1 with the other being 0. +//! \brief The number of spikes to do when the DMA completes. +//! \details When a DMA is first set up, only this or ::dma_n_rewires can be 1 +//! with the other being 0. static uint32_t dma_n_spikes; -//! the number of dma completes (used in provenance generation) +//! the number of DMA completes (used in provenance generation) static uint32_t dma_complete_count; //! the number of spikes that were processed (used in provenance generation) @@ -91,15 +93,15 @@ static uint32_t spike_processing_count; //! The number of successful rewires static uint32_t n_successful_rewires; -//! count how many packets were lost from the input buffer because of late -//! arrival +//! \breif How many packets were lost from the input buffer because of +//! late arrival static uint32_t count_input_buffer_packets_late; //! tracker of how full the input buffer got. static uint32_t biggest_fill_size_of_input_buffer; -//! bool that governs if we should clear packets from the input buffer at the -//! end of a timer tick. +//! \brief Whether if we should clear packets from the input buffer at the +//! end of a timer tick. static bool clear_input_buffers_of_late_packets; //! the number of packets received this time step @@ -114,15 +116,15 @@ static uint32_t p_per_ts_region; /* PRIVATE FUNCTIONS - static for inlining */ //! \brief Perform a DMA read of a synaptic row -//! \param[in] row_address: Where in SDRAM to read the row from +//! \param[in] row: Where in SDRAM to read the row from //! \param[in] n_bytes_to_transfer: The size of the synaptic row //! \param[in] spike: The spike that triggered this read static inline void do_dma_read( - address_t row_address, size_t n_bytes_to_transfer, spike_t spike) { + synaptic_row_t row, size_t n_bytes_to_transfer, spike_t spike) { // Write the SDRAM address of the plastic region and the // Key of the originating spike to the beginning of DMA buffer dma_buffer *next_buffer = &dma_buffers[next_buffer_to_fill]; - next_buffer->sdram_writeback_address = row_address; + next_buffer->sdram_writeback_address = row; next_buffer->originating_spike = spike; next_buffer->n_bytes_transferred = n_bytes_to_transfer; @@ -130,7 +132,7 @@ static inline void do_dma_read( // buffer buffer_being_read = next_buffer_to_fill; while (!spin1_dma_transfer( - DMA_TAG_READ_SYNAPTIC_ROW, row_address, next_buffer->row, DMA_READ, + DMA_TAG_READ_SYNAPTIC_ROW, row, next_buffer->row, DMA_READ, n_bytes_to_transfer)) { // Do Nothing } @@ -138,7 +140,7 @@ static inline void do_dma_read( } //! \brief Check if there is anything to do. If not, DMA is not busy -//! \param[out] row_address: +//! \param[out] row: //! The address of the synaptic row that has been processed //! \param[out] n_bytes_to_transfer: The size of the processed synaptic row //! \param[out] spike: The spike being processed @@ -146,7 +148,7 @@ static inline void do_dma_read( //! \param[in,out] n_process_spike: Accumulator of number of processed spikes //! \return True if there's something to do static inline bool is_something_to_do( - address_t *row_address, size_t *n_bytes_to_transfer, + synaptic_row_t *row, size_t *n_bytes_to_transfer, spike_t *spike, uint32_t *n_rewire, uint32_t *n_process_spike) { // Disable interrupts here as dma_busy modification is a critical section uint cpsr = spin1_int_disable(); @@ -155,7 +157,7 @@ static inline bool is_something_to_do( while (rewires_to_do) { rewires_to_do--; spin1_mode_restore(cpsr); - if (synaptogenesis_dynamics_rewire(time, spike, row_address, + if (synaptogenesis_dynamics_rewire(time, spike, row, n_bytes_to_transfer)) { *n_rewire += 1; return true; @@ -165,8 +167,7 @@ static inline bool is_something_to_do( // Is there another address in the population table? spin1_mode_restore(cpsr); - if (population_table_get_next_address( - spike, row_address, n_bytes_to_transfer)) { + if (population_table_get_next_address(spike, row, n_bytes_to_transfer)) { *n_process_spike += 1; return true; } @@ -184,7 +185,7 @@ static inline bool is_something_to_do( // as this can be slow spin1_mode_restore(cpsr); if (population_table_get_first_address( - *spike, row_address, n_bytes_to_transfer)) { + *spike, row, n_bytes_to_transfer)) { synaptogenesis_spike_received(time, *spike); *n_process_spike += 1; return true; @@ -217,7 +218,7 @@ static inline bool is_something_to_do( static void setup_synaptic_dma_read(dma_buffer *current_buffer, uint32_t *n_rewires, uint32_t *n_synapse_processes) { // Set up to store the DMA location and size to read - address_t row_address; + synaptic_row_t row; size_t n_bytes_to_transfer; spike_t spike; dma_n_spikes = 0; @@ -225,10 +226,10 @@ static void setup_synaptic_dma_read(dma_buffer *current_buffer, // Keep looking if there is something to do until a DMA can be done bool setup_done = false; - while (!setup_done && is_something_to_do(&row_address, - &n_bytes_to_transfer, &spike, &dma_n_rewires, &dma_n_spikes)) { + while (!setup_done && is_something_to_do(&row, &n_bytes_to_transfer, + &spike, &dma_n_rewires, &dma_n_spikes)) { if (current_buffer != NULL && - current_buffer->sdram_writeback_address == row_address) { + current_buffer->sdram_writeback_address == row) { // If we can reuse the row, add on what we can use it for // Note that only one of these will have a value of 1 with the // other being set to 0, but we add both as it is simple @@ -239,7 +240,7 @@ static void setup_synaptic_dma_read(dma_buffer *current_buffer, } else if (n_bytes_to_transfer == 0) { // If the row is in DTCM, process the row now synaptic_row_t single_fixed_synapse = - direct_synapses_get_direct_synapse(row_address); + direct_synapses_get_direct_synapse(row); bool write_back; synapses_process_synaptic_row( time, single_fixed_synapse, &write_back); @@ -247,7 +248,7 @@ static void setup_synaptic_dma_read(dma_buffer *current_buffer, dma_n_spikes = 0; } else { // If the row is in SDRAM, set up the transfer and we are done - do_dma_read(row_address, n_bytes_to_transfer, spike); + do_dma_read(row, n_bytes_to_transfer, spike); setup_done = true; } @@ -269,16 +270,17 @@ static inline void setup_synaptic_dma_write( // Get the number of plastic bytes and the write back address from the // synaptic row size_t write_size = buffer->n_bytes_transferred; - address_t sdram_start_address = buffer->sdram_writeback_address; - address_t dtcm_start_address = buffer->row; + void *sdram_start_address = buffer->sdram_writeback_address; + void *dtcm_start_address = buffer->row; if (plastic_only) { write_size = synapse_row_plastic_size(buffer->row) * sizeof(uint32_t); - sdram_start_address = synapse_row_plastic_region(sdram_start_address); - dtcm_start_address = synapse_row_plastic_region(dtcm_start_address); + sdram_start_address = synapse_row_plastic_region( + buffer->sdram_writeback_address); + dtcm_start_address = synapse_row_plastic_region(buffer->row); } log_debug("Writing back %u bytes of plastic region to %08x for spike %u", - write_size, sdram_start_address, buffer->originating_spike); + write_size, sdram_start_address, buffer->originating_spike); // Start transfer while (!spin1_dma_transfer(DMA_TAG_WRITE_PLASTIC_REGION, sdram_start_address, diff --git a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/elimination/elimination.h b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/elimination/elimination.h index 3b6bfe72a6..4e4bb21b98 100644 --- a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/elimination/elimination.h +++ b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/elimination/elimination.h @@ -40,6 +40,6 @@ elimination_params_t *synaptogenesis_elimination_init(uint8_t **data); //! \return if row was modified static inline bool synaptogenesis_elimination_rule( current_state_t *current_state, const elimination_params_t *params, - uint32_t time, address_t row); + uint32_t time, synaptic_row_t row); #endif // _ELIMINATION_H_ diff --git a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h index bd76cc5af2..3a6bb3d4bc 100644 --- a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h +++ b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/elimination/elimination_random_by_weight_impl.h @@ -42,7 +42,7 @@ struct elimination_params { static inline bool synaptogenesis_elimination_rule( current_state_t *restrict current_state, const elimination_params_t *params, - UNUSED uint32_t time, address_t restrict row) { + UNUSED uint32_t time, synaptic_row_t restrict row) { uint32_t random_number = mars_kiss64_seed(*(current_state->local_seed)); // Is weight depressed? diff --git a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/formation/formation.h b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/formation/formation.h index 1fed93419a..a8f25371e9 100644 --- a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/formation/formation.h +++ b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/formation/formation.h @@ -42,6 +42,6 @@ formation_params_t *synaptogenesis_formation_init(uint8_t **data); //! \return if row was modified static inline bool synaptogenesis_formation_rule( current_state_t *current_state, const formation_params_t *params, - uint32_t time, address_t row); + uint32_t time, synaptic_row_t row); #endif // _FORMATION_H_ diff --git a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h index c8c71283d9..acc5ff9eca 100644 --- a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h +++ b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/formation/formation_distance_dependent_impl.h @@ -71,7 +71,7 @@ static int my_abs(int a) { //! \return if row was modified static inline bool synaptogenesis_formation_rule( current_state_t *current_state, const formation_params_t *params, - UNUSED uint32_t time, address_t row) { + UNUSED uint32_t time, synaptic_row_t row) { // Compute distances // To do this I need to take the DIV and MOD of the // post-synaptic neuron ID, of the pre-synaptic neuron ID diff --git a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/sp_structs.h b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/sp_structs.h index 5bcf52cc3a..84781d0cfe 100644 --- a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/sp_structs.h +++ b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/sp_structs.h @@ -186,7 +186,7 @@ static inline bool sp_structs_get_sub_pop_info( //! \param[in,out] row: The row of the synaptic matrix to be updated //! \return True if the synapse was removed static inline bool sp_structs_remove_synapse( - current_state_t *restrict current_state, address_t restrict row) { + current_state_t *restrict current_state, synaptic_row_t restrict row) { if (!synapse_dynamics_remove_neuron(current_state->offset, row)) { return false; } @@ -199,7 +199,7 @@ static inline bool sp_structs_remove_synapse( //! \param[in,out] row: The row of the synaptic matrix to be updated //! \return True if the synapse was added static inline bool sp_structs_add_synapse( - current_state_t *restrict current_state, address_t restrict row) { + current_state_t *restrict current_state, synaptic_row_t restrict row) { uint32_t appr_scaled_weight = current_state->pre_population_info->weight; uint32_t actual_delay; diff --git a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/topographic_map_impl.c b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/topographic_map_impl.c index 99fc57caa0..ffe95b50bc 100644 --- a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/topographic_map_impl.c +++ b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis/topographic_map_impl.c @@ -187,7 +187,7 @@ bool synaptogenesis_dynamics_initialise(address_t sdram_sp_address) { } bool synaptogenesis_dynamics_rewire( - uint32_t time, spike_t *spike, address_t *synaptic_row_address, + uint32_t time, spike_t *spike, synaptic_row_t *synaptic_row, uint32_t *n_bytes) { // Randomly choose a postsynaptic (application neuron) @@ -204,7 +204,7 @@ bool synaptogenesis_dynamics_rewire( // Select an arbitrary synaptic element for the neurons uint32_t row_offset = post_id * rewiring_data.s_max; uint32_t column_offset = rand_int(rewiring_data.s_max, - rewiring_data.local_seed); + rewiring_data.local_seed); uint32_t total_offset = row_offset + column_offset; post_to_pre_entry entry = post_to_pre_table[total_offset]; uint32_t pre_app_pop = 0, pre_sub_pop = 0, m_pop_index = 0, neuron_id = 0; @@ -225,15 +225,13 @@ bool synaptogenesis_dynamics_rewire( m_pop_index = key_atom_info->m_pop_index; } - if (!population_table_get_first_address( - *spike, synaptic_row_address, n_bytes)) { + if (!population_table_get_first_address(*spike, synaptic_row, n_bytes)) { log_error("FAIL@key %d", *spike); rt_error(RTE_SWERR); } uint32_t index = 0; while (index < m_pop_index) { - if (!population_table_get_next_address( - spike, synaptic_row_address, n_bytes)) { + if (!population_table_get_next_address(spike, synaptic_row, n_bytes)) { log_error("FAIL@key %d, index %d (failed at %d)", *spike, m_pop_index, index); rt_error(RTE_SWERR); @@ -258,39 +256,46 @@ bool synaptogenesis_dynamics_rewire( return true; } -bool synaptogenesis_row_restructure(uint32_t time, address_t row) { - current_state_t *current_state = _get_state(); - +//! \brief Performs the actual restructuring of a row +//! \details Supporting function for synaptogenesis_row_restructure() +//! \param[in] time: The time of the restructure +//! \param[in] row: The row to restructure +//! \param[in] current_state: The current state of the world +//! \return True if the row was changed and needs to be written back +static inline bool row_restructure( + uint32_t time, synaptic_row_t restrict row, + current_state_t *restrict current_state) { // the selected pre- and postsynaptic IDs are in current_state - bool return_value; if (current_state->element_exists) { // find the offset of the neuron in the current row - if (synapse_dynamics_find_neuron( + if (!synapse_dynamics_find_neuron( current_state->post_syn_id, row, ¤t_state->weight, ¤t_state->delay, ¤t_state->offset, ¤t_state->synapse_type)) { - return_value = synaptogenesis_elimination_rule(current_state, - elimination_params[current_state->post_to_pre.pop_index], - time, row); - } else { log_debug("Post neuron %d not in row", current_state->post_syn_id); - return_value = false; + return false; } + return synaptogenesis_elimination_rule(current_state, + elimination_params[current_state->post_to_pre.pop_index], + time, row); } else { // Can't form if the row is full uint32_t no_elems = synapse_dynamics_n_connections_in_row( synapse_row_fixed_region(row)); if (no_elems >= rewiring_data.s_max) { log_debug("row is full"); - return_value = false; - } else { - return_value = synaptogenesis_formation_rule(current_state, - formation_params[current_state->post_to_pre.pop_index], - time, row); + return false; } + return synaptogenesis_formation_rule(current_state, + formation_params[current_state->post_to_pre.pop_index], + time, row); } +} +bool synaptogenesis_row_restructure(uint32_t time, synaptic_row_t row) { + current_state_t *current_state = _get_state(); + bool return_value = row_restructure(time, row, current_state); _free_state(current_state); return return_value; } diff --git a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics.h b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics.h index e2f1e0f579..8edd3777b6 100644 --- a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics.h +++ b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics.h @@ -35,40 +35,40 @@ bool synaptogenesis_dynamics_initialise( address_t sdram_sp_address); -//! \brief Function called (usually on a timer from c_main()) to -//! trigger the process of synaptic rewiring +//! \brief Trigger the process of synaptic rewiring +//! \details Usually called on a timer registered in c_main() //! \param[in] time: the current timestep //! \param[out] spike: variable to hold the spike -//! \param[out] synaptic_row_address: variable to hold the address of the row +//! \param[out] synaptic_row: variable to hold the address of the row //! \param[out] n_bytes: variable to hold the size of the row //! \return True if a row is to be transferred, false otherwise bool synaptogenesis_dynamics_rewire(uint32_t time, - spike_t *spike, address_t *synaptic_row_address, uint32_t *n_bytes); + spike_t *spike, synaptic_row_t *synaptic_row, uint32_t *n_bytes); -//! \brief Performs the actual restructuring of a row +//! \brief Perform the actual restructuring of a row //! \param[in] time: The time of the restructure //! \param[in] row: The row to restructure //! \return True if the row was changed and needs to be written back -bool synaptogenesis_row_restructure(uint32_t time, address_t row); +bool synaptogenesis_row_restructure(uint32_t time, synaptic_row_t row); -//! \brief retrieve the period of rewiring +//! \brief Get the period of rewiring //! \return Based on synaptogenesis_is_fast(), this can either be how many times //! rewiring happens in a timestep, or how many timesteps have to pass until //! rewiring happens. int32_t synaptogenesis_rewiring_period(void); -//! \brief controls whether rewiring is attempted multiple times per timestep +//! \brief Get whether rewiring is attempted multiple times per timestep //! or after a number of timesteps. //! \return true if the result of synaptogenesis_rewiring_period() is the number //! of attempts to try per timestep. bool synaptogenesis_is_fast(void); -//! Indicates that a spike has been received +//! \brief Indicates that a spike has been received //! \param[in] time: The time that the spike was received at //! \param[in] spike: The received spike void synaptogenesis_spike_received(uint32_t time, spike_t spike); -//! Prints a certain data object +//! Print a certain data object void print_post_to_pre_entry(void); #endif // _SYNAPTOGENESIS_DYNAMICS_H_ diff --git a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics_static_impl.c b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics_static_impl.c index b08404eae3..7e188945fe 100644 --- a/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics_static_impl.c +++ b/neural_modelling/src/neuron/structural_plasticity/synaptogenesis_dynamics_static_impl.c @@ -29,12 +29,12 @@ bool synaptogenesis_dynamics_initialise(UNUSED address_t sdram_sp_address) { bool synaptogenesis_dynamics_rewire( UNUSED uint32_t time, UNUSED spike_t *spike, - UNUSED address_t *synaptic_row_address, UNUSED uint32_t *n_bytes) { + UNUSED synaptic_row_t *synaptic_row, UNUSED uint32_t *n_bytes) { return false; } bool synaptogenesis_row_restructure( - UNUSED uint32_t time, UNUSED address_t row) { + UNUSED uint32_t time, UNUSED synaptic_row_t row) { return false; } diff --git a/neural_modelling/src/neuron/synapse_row.h b/neural_modelling/src/neuron/synapse_row.h index afdf051289..662a1c2a09 100644 --- a/neural_modelling/src/neuron/synapse_row.h +++ b/neural_modelling/src/neuron/synapse_row.h @@ -118,53 +118,75 @@ typedef uint16_t control_t; //! Number of header words per synaptic row #define N_SYNAPSE_ROW_HEADER_WORDS 3 -//! \brief Returns the size of the plastic region +//! The type of the plastic-plastic part of the row +typedef struct { + size_t size; //!< The number of plastic words in `data` + uint32_t data[]; //!< The plastic words, followed by the fixed part +} synapse_row_plastic_part_t; + +//! The type of the fixed part of the row. The fixed-plastic part follows. +typedef struct { + size_t num_fixed; //!< The number of fixed synapses in `data` + size_t num_plastic; //!< The number of plastic controls in `data` + uint32_t data[]; //!< The data, first the fixed then the plastic +} synapse_row_fixed_part_t; + +//! \brief Get the size of the plastic region //! \param[in] row: The synaptic row //! \return The size of the plastic region of the row -static inline size_t synapse_row_plastic_size(address_t row) { - return (size_t) row[0]; +static inline size_t synapse_row_plastic_size(const synaptic_row_t row) { + const synapse_row_plastic_part_t *the_row = + (const synapse_row_plastic_part_t *) row; + return the_row->size; } -//! \brief Returns the address of the plastic region +//! \brief Get the address of the plastic region //! \param[in] row: The synaptic row //! \return Address of the plastic region of the row -static inline address_t synapse_row_plastic_region(address_t row) { - return (address_t) &row[1]; +static inline void *synapse_row_plastic_region(synaptic_row_t row) { + synapse_row_plastic_part_t *the_row = (synapse_row_plastic_part_t *) row; + return the_row->data; } -//! \brief Returns the address of the non-plastic (or fixed) region +//! \brief Get the address of the non-plastic (or fixed) region //! \param[in] row: The synaptic row //! \return Address of the fixed region of the row -static inline address_t synapse_row_fixed_region(address_t row) { - return (address_t) &row[synapse_row_plastic_size(row) + 1]; +static inline synapse_row_fixed_part_t *synapse_row_fixed_region( + synaptic_row_t row) { + synapse_row_plastic_part_t *the_row = (synapse_row_plastic_part_t *) row; + return (synapse_row_fixed_part_t *) &the_row->data[the_row->size]; } -//! \brief The number of fixed synapses in the row +//! \brief Get the number of fixed synapses in the row //! \param[in] fixed: The fixed region of the synaptic row //! \return Size of the fixed region of the row (in words) -static inline size_t synapse_row_num_fixed_synapses(address_t fixed) { - return (size_t) fixed[0]; +static inline size_t synapse_row_num_fixed_synapses( + const synapse_row_fixed_part_t *fixed) { + return fixed->num_fixed; } -//! \brief The number of plastic controls in the row +//! \brief Get the number of plastic controls in the row //! \param[in] fixed: The fixed region of the synaptic row //! \return Size of the fixed-plastic region of the row (in _half_ words) -static inline size_t synapse_row_num_plastic_controls(address_t fixed) { - return (size_t) fixed[1]; +static inline size_t synapse_row_num_plastic_controls( + const synapse_row_fixed_part_t *fixed) { + return fixed->num_plastic; } -//! \brief The array of plastic controls in the row +//! \brief Get the array of plastic controls in the row //! \param[in] fixed: The fixed region of the synaptic row //! \return Address of the fixed-plastic region of the row -static inline control_t* synapse_row_plastic_controls(address_t fixed) { - return (control_t*) &fixed[2 + synapse_row_num_fixed_synapses(fixed)]; +static inline control_t *synapse_row_plastic_controls( + synapse_row_fixed_part_t *fixed) { + return (control_t *) &fixed->data[fixed->num_fixed]; } //! \brief The array of fixed weights in the row //! \param[in] fixed: The fixed region of the synaptic row //! \return Address of the fixed-fixed region of the row -static inline uint32_t *synapse_row_fixed_weight_controls(address_t fixed) { - return &fixed[2]; +static inline uint32_t *synapse_row_fixed_weight_controls( + synapse_row_fixed_part_t *fixed) { + return fixed->data; } // The following are offset calculations into the ring buffers diff --git a/neural_modelling/src/neuron/synapses.c b/neural_modelling/src/neuron/synapses.c index 939a448cb8..cf20011607 100644 --- a/neural_modelling/src/neuron/synapses.c +++ b/neural_modelling/src/neuron/synapses.c @@ -99,26 +99,23 @@ static inline void print_synaptic_row(synaptic_row_t synaptic_row) { log_debug("----------------------------------------\n"); // Get details of fixed region - address_t fixed_region_address = synapse_row_fixed_region(synaptic_row); - address_t fixed_synapses = - synapse_row_fixed_weight_controls(fixed_region_address); - size_t n_fixed_synapses = - synapse_row_num_fixed_synapses(fixed_region_address); + synapse_row_fixed_part_t *fixed_region = + synapse_row_fixed_region(synaptic_row); + address_t fixed_synapses = synapse_row_fixed_weight_controls(fixed_region); + size_t n_fixed_synapses = synapse_row_num_fixed_synapses(fixed_region); log_debug("Fixed region %u fixed synapses (%u plastic control words):\n", - n_fixed_synapses, - synapse_row_num_plastic_controls(fixed_region_address)); + n_fixed_synapses, synapse_row_num_plastic_controls(fixed_region)); for (uint32_t i = 0; i < n_fixed_synapses; i++) { uint32_t synapse = fixed_synapses[i]; uint32_t synapse_type = synapse_row_sparse_type( synapse, synapse_index_bits, synapse_type_mask); - log_debug("%08x [%3d: (w: %5u (=", + io_printf(IO_BUF, "%08x [%3d: (w: %5u (=", synapse, i, synapse_row_sparse_weight(synapse)); synapses_print_weight(synapse_row_sparse_weight(synapse), ring_buffer_to_input_left_shifts[synapse_type]); - log_debug( - "nA) d: %2u, %s, n = %3u)] - {%08x %08x}\n", + io_printf(IO_BUF, "nA) d: %2u, %s, n = %3u)] - {%08x %08x}\n", synapse_row_sparse_delay(synapse, synapse_type_index_bits), get_type_char(synapse_type), synapse_row_sparse_index(synapse, synapse_index_mask), @@ -131,7 +128,7 @@ static inline void print_synaptic_row(synaptic_row_t synaptic_row) { address_t plastic_region_address = synapse_row_plastic_region(synaptic_row); synapse_dynamics_print_plastic_synapses( - plastic_region_address, fixed_region_address, + plastic_region_address, fixed_region, ring_buffer_to_input_left_shifts); } @@ -142,8 +139,7 @@ static inline void print_synaptic_row(synaptic_row_t synaptic_row) { } //! \brief Print the contents of the ring buffers. -//! -//! Only does anything when debugging. +//! \details Only does anything when debugging. //! \param[in] time: The current timestamp static inline void print_ring_buffers(uint32_t time) { #if LOG_LEVEL >= LOG_DEBUG @@ -181,8 +177,7 @@ static inline void print_ring_buffers(uint32_t time) { } //! \brief Print the neuron inputs. -//! -//! Only does anything when debugging. +//! \details Only does anything when debugging. static inline void print_inputs(void) { #if LOG_LEVEL >= LOG_DEBUG log_debug("Inputs\n"); @@ -191,18 +186,15 @@ static inline void print_inputs(void) { } -//! \brief This is the "inner loop" of the neural simulation. -//! -//! Every spike event could cause up to 256 different weights to -//! be put into the ring buffer. -//! \param[in] fixed_region_address: The fixed region of the synaptic matrix +//! \brief The "inner loop" of the neural simulation. +//! \details Every spike event could cause up to 256 different weights to +//! be put into the ring buffer. +//! \param[in] fixed_region: The fixed region of the synaptic matrix //! \param[in] time: The current simulation time static inline void process_fixed_synapses( - address_t fixed_region_address, uint32_t time) { - register uint32_t *synaptic_words = - synapse_row_fixed_weight_controls(fixed_region_address); - register uint32_t fixed_synapse = - synapse_row_num_fixed_synapses(fixed_region_address); + synapse_row_fixed_part_t *fixed_region, uint32_t time) { + uint32_t *synaptic_words = synapse_row_fixed_weight_controls(fixed_region); + uint32_t fixed_synapse = synapse_row_num_fixed_synapses(fixed_region); num_fixed_pre_synaptic_events += fixed_synapse; @@ -241,7 +233,7 @@ static inline void process_fixed_synapses( } } -//! private method for doing output debug data on the synapses +//! Print output debug data on the synapses static inline void print_synapse_parameters(void) { // only if the models are compiled in debug mode will this method contain // said lines. @@ -366,7 +358,7 @@ bool synapses_process_synaptic_row( uint32_t time, synaptic_row_t row, bool *write_back) { // Get address of non-plastic region from row - address_t fixed_region_address = synapse_row_fixed_region(row); + synapse_row_fixed_part_t *fixed_region = synapse_row_fixed_region(row); // **TODO** multiple optimised synaptic row formats //if (plastic_tag(row) == 0) { @@ -379,7 +371,7 @@ bool synapses_process_synaptic_row( profiler_write_entry_disable_fiq( PROFILER_ENTER | PROFILER_PROCESS_PLASTIC_SYNAPSES); if (!synapse_dynamics_process_plastic_synapses(plastic_region_address, - fixed_region_address, ring_buffers, time)) { + fixed_region, ring_buffers, time)) { return false; } profiler_write_entry_disable_fiq( @@ -393,19 +385,18 @@ bool synapses_process_synaptic_row( // **NOTE** this is done after initiating DMA in an attempt // to hide cost of DMA behind this loop to improve the chance // that the DMA controller is ready to read next synaptic row afterwards - process_fixed_synapses(fixed_region_address, time); + process_fixed_synapses(fixed_region, time); //} return true; } -//! \brief returns the number of times the synapses have saturated their -//! weights. +//! \brief Get the number of times the synapses have saturated their weights. //! \return the number of times the synapses have saturated. uint32_t synapses_get_saturation_count(void) { return saturation_count; } -//! \brief returns the counters for plastic and fixed pre synaptic events +//! \brief Get the counters for plastic and fixed pre synaptic events //! based on (if the model was compiled with SYNAPSE_BENCHMARK parameter) or //! returns 0 //! \return the counter for plastic and fixed pre synaptic events or 0 @@ -420,7 +411,7 @@ void synapses_flush_ring_buffers(void) { } } -//! \brief allows clearing of DTCM used by synapses +//! \brief Clear DTCM used by synapses //! \return true if successful bool synapses_shut_down(void) { sark_free(ring_buffer_to_input_left_shifts); diff --git a/neural_modelling/src/synapse_expander/matrix_generators/matrix_generator_static.h b/neural_modelling/src/synapse_expander/matrix_generators/matrix_generator_static.h index 8c38b6b273..110d9511e5 100644 --- a/neural_modelling/src/synapse_expander/matrix_generators/matrix_generator_static.h +++ b/neural_modelling/src/synapse_expander/matrix_generators/matrix_generator_static.h @@ -58,25 +58,13 @@ static void matrix_generator_static_free(UNUSED void *generator) { */ #define SYNAPSE_DELAY_MASK 0xFF -/** - * \brief The position of the plastic-plastic size within a row - */ -#define STATIC_PLASTIC_PLASTIC_SIZE 0 - -/** - * \brief The position of the fixed-plastic size within a row - */ -#define STATIC_FIXED_PLASTIC_SIZE 2 - -/** - * \brief The position of the fixed-fixed size within a row - */ -#define STATIC_FIXED_FIXED_SIZE 1 - -/** - * \brief The starting position of the fixed-fixed data within a row - */ -#define STATIC_FIXED_FIXED_OFFSET 3 +//! The layout of a purely static row of a synaptic matrix. +typedef struct { + uint32_t plastic_plastic_size; //!< the plastic-plastic size within a row + uint32_t fixed_fixed_size; //!< the fixed-fixed size within a row + uint32_t fixed_plastic_size; //!< the fixed-plastic size within a row + uint32_t fixed_fixed_data[]; //!< the fixed-fixed data within a row +} *static_row_t; /** * \brief Build a static synaptic word from components @@ -105,16 +93,16 @@ static uint32_t build_static_word( /** * \brief How to generate a row of a static synaptic matrix - * \param[in] generator: The data for the matrix generator, returned by the - * initialise function + * \param[in] generator: + * The data for the matrix generator, returned by the initialise function * \param[out] synaptic_matrix: The address of the synaptic matrix to write to - * \param[out] delayed_synaptic_matrix: The address of the synaptic matrix to - * write delayed connections to + * \param[out] delayed_synaptic_matrix: + * The address of the synaptic matrix to write delayed connections to * \param[in] n_pre_neurons: The number of pre neurons to generate for * \param[in] pre_neuron_index: The index of the first pre neuron * \param[in] max_row_n_words: The maximum number of words in a normal row - * \param[in] max_delayed_row_n_words: The maximum number of words in a - * delayed row + * \param[in] max_delayed_row_n_words: + * The maximum number of words in a delayed row * \param[in] synapse_type_bits: The number of bits used for the synapse type * \param[in] synapse_index_bits: The number of bits used for the neuron id * \param[in] synapse_type: The synapse type of each connection @@ -137,19 +125,19 @@ static void matrix_generator_static_write_row( // Row address and position for each possible delay stage (including no // delay stage) - address_t row_address[max_stage]; + static_row_t row[max_stage]; // The space available on each row uint16_t space[max_stage]; // The normal row position and space available - might be 0 if all delayed - row_address[0] = NULL; + row[0] = NULL; space[0] = max_row_n_words; if (synaptic_matrix != NULL) { - row_address[0] = + row[0] = (static_row_t) &synaptic_matrix[pre_neuron_index * (max_row_n_words + 3)]; } - log_debug("row[0] = 0x%08x", row_address[0]); + log_debug("row[0] = 0x%08x", row[0]); // The delayed row positions and space available if (delayed_synaptic_matrix != NULL) { @@ -158,28 +146,29 @@ static void matrix_generator_static_write_row( uint32_t single_matrix_size = n_pre_neurons * (max_delayed_row_n_words + 3); for (uint32_t i = 1; i < max_stage; i++) { - row_address[i] = &delayed_address[single_matrix_size * (i - 1)]; + row[i] = (static_row_t) + &delayed_address[single_matrix_size * (i - 1)]; space[i] = max_delayed_row_n_words; - log_debug("row[%u] = 0x%08x", i, row_address[i]); + log_debug("row[%u] = 0x%08x", i, row[i]); } } else { for (uint32_t i = 1; i < max_stage; i++) { - row_address[i] = NULL; + row[i] = NULL; space[i] = 0; - log_debug("row[%u] = 0x%08x", i, row_address[i]); + log_debug("row[%u] = 0x%08x", i, row[i]); } } // The address to write synapses to on each stage address_t write_address[max_stage]; for (uint32_t i = 0; i < max_stage; i++) { - if (row_address[i] != NULL) { + if (row[i] != NULL) { log_debug("Row size at 0x%08x for stage %u", - &row_address[i][STATIC_FIXED_FIXED_SIZE], i); - row_address[i][STATIC_FIXED_FIXED_SIZE] = 0; - row_address[i][STATIC_PLASTIC_PLASTIC_SIZE] = 0; - row_address[i][STATIC_FIXED_PLASTIC_SIZE] = 0; - write_address[i] = &row_address[i][STATIC_FIXED_FIXED_OFFSET]; + &row[i]->fixed_fixed_size, i); + row[i]->fixed_fixed_size = 0; + row[i]->plastic_plastic_size = 0; + row[i]->fixed_plastic_size = 0; + write_address[i] = row[i]->fixed_fixed_data; } else { write_address[i] = NULL; } @@ -222,7 +211,7 @@ static void matrix_generator_static_write_row( write_address[delay.stage] = &write_address[delay.stage][1]; // Increment the size of the current row - row_address[delay.stage][STATIC_FIXED_FIXED_SIZE]++; + row[delay.stage]->fixed_fixed_size++; space[delay.stage]--; } } diff --git a/neural_modelling/src/synapse_expander/matrix_generators/matrix_generator_stdp.h b/neural_modelling/src/synapse_expander/matrix_generators/matrix_generator_stdp.h index 12cc647979..0256c812fe 100644 --- a/neural_modelling/src/synapse_expander/matrix_generators/matrix_generator_stdp.h +++ b/neural_modelling/src/synapse_expander/matrix_generators/matrix_generator_stdp.h @@ -33,30 +33,18 @@ */ #define SYNAPSE_DELAY_MASK 0xFF -/** - * \brief The position of the plastic-plastic size within the row - */ -#define STDP_PLASTIC_PLASTIC_SIZE 0 - -/** - * \brief The position of the plastic-plastic data within the row - */ -#define STDP_PLASTIC_PLASTIC_OFFSET 1 - -/** - * \brief The position of the fixed-fixed size within the fixed region - */ -#define STDP_FIXED_FIXED_SIZE 0 - -/** - * \brief The position of the fixed-plastic size within the fixed region - */ -#define STDP_FIXED_PLASTIC_SIZE 1 - -/** - * \brief The position of the fixed-plastic data within the fixed region - */ -#define STDP_FIXED_PLASTIC_OFFSET 2 +//! The layout of the initial plastic synapse part of the row +typedef struct { + uint32_t plastic_plastic_size; //!< the plastic-plastic size within the row + uint16_t plastic_plastic_data[]; //!< the plastic-plastic data within the row +} *row_plastic_t; + +//! The layout of the fixed synapse region of the row; the fixed-fixed region is empty +typedef struct { + uint32_t fixed_fixed_size; //!< the fixed-fixed size within the fixed region + uint32_t fixed_plastic_size; //!< the fixed-plastic size within the fixed region + uint16_t fixed_plastic_data[]; //!< the fixed-plastic data within the fixed region +} *row_fixed_t; //! Data for the generator struct matrix_generator_stdp { @@ -69,7 +57,7 @@ struct matrix_generator_stdp { }; /** - * \brief How to initialise the STDP synaptic matrix generator + * \brief Initialise the STDP synaptic matrix generator * \param[in,out] region: Region to read parameters from. Should be updated * to position just after parameters after calling. * \return A data item to be passed in to other functions later on @@ -87,7 +75,7 @@ void *matrix_generator_stdp_initialize(address_t *region) { } /** - * \brief How to free any data for the STDP synaptic matrix generator + * \brief Free any data for the STDP synaptic matrix generator * \param[in] generator: The generator to free */ void matrix_generator_stdp_free(void *generator) { @@ -95,7 +83,7 @@ void matrix_generator_stdp_free(void *generator) { } /** - * \brief Build a fixed-plastic half-word from the components + * \brief Build a fixed-plastic half-word from its components * \param[in] delay: The delay of the synapse * \param[in] type: The synapse type * \param[in] post_index: The core-relative index of the target neuron @@ -120,17 +108,17 @@ static uint16_t build_fixed_plastic_half_word( } /** - * \brief How to generate a row of a STDP synaptic matrix - * \param[in] generator: The data for the matrix generator, returned by the - * initialise function + * \brief Generate a row of a STDP synaptic matrix + * \param[in] generator: + * The data for the matrix generator, returned by the initialise function * \param[out] synaptic_matrix: The address of the synaptic matrix to write to - * \param[out] delayed_synaptic_matrix: The address of the synaptic matrix to - * write delayed connections to + * \param[out] delayed_synaptic_matrix: + * The address of the synaptic matrix to write delayed connections to * \param[in] n_pre_neurons: The number of pre neurons to generate for * \param[in] pre_neuron_index: The index of the first pre neuron * \param[in] max_row_n_words: The maximum number of words in a normal row - * \param[in] max_delayed_row_n_words: The maximum number of words in a - * delayed row + * \param[in] max_delayed_row_n_words: + * The maximum number of words in a delayed row * \param[in] synapse_type_bits: The number of bits used for the synapse type * \param[in] synapse_index_bits: The number of bits used for the neuron id * \param[in] synapse_type: The synapse type of each connection @@ -152,7 +140,7 @@ void matrix_generator_stdp_write_row( struct matrix_generator_stdp *obj = generator; // Row address for each possible delay stage (including no delay stage) - address_t row_address[max_stage]; + row_plastic_t row[max_stage]; // Space available in each row uint16_t space_half_words[max_stage]; @@ -162,10 +150,11 @@ void matrix_generator_stdp_write_row( uint32_t n_delay_row_words = max_delayed_row_n_words + 3; // The normal row position and space available - might be 0 if all delayed - row_address[0] = NULL; + row[0] = NULL; space_half_words[0] = max_row_n_words * 2; if (synaptic_matrix != NULL) { - row_address[0] = &synaptic_matrix[pre_neuron_index * n_row_words]; + row[0] = (row_plastic_t) + &synaptic_matrix[pre_neuron_index * n_row_words]; } // The delayed row positions and space available @@ -174,23 +163,23 @@ void matrix_generator_stdp_write_row( &delayed_synaptic_matrix[pre_neuron_index * n_delay_row_words]; uint32_t single_matrix_size = n_pre_neurons * n_delay_row_words; for (uint32_t i = 1; i < max_stage; i++) { - row_address[i] = &delayed_address[single_matrix_size * (i - 1)]; + row[i] = (row_plastic_t) + &delayed_address[single_matrix_size * (i - 1)]; space_half_words[i] = max_delayed_row_n_words * 2; } } else { for (uint32_t i = 1; i < max_stage; i++) { - row_address[i] = NULL; + row[i] = NULL; space_half_words[i] = 0; } } // Add the header half words (zero initialised) to each row for (uint32_t i = 0; i < max_stage; i++) { - if (row_address[i] != NULL) { - row_address[i][STDP_PLASTIC_PLASTIC_SIZE] = + if (row[i] != NULL) { + row[i]->plastic_plastic_size = obj->n_half_words_per_pp_row_header >> 1; - uint16_t *header = (uint16_t *) - &row_address[i][STDP_PLASTIC_PLASTIC_OFFSET]; + uint16_t *header = row[i]->plastic_plastic_data; for (uint32_t j = 0; j < obj->n_half_words_per_pp_row_header; j++) { header[j] = 0; @@ -205,10 +194,9 @@ void matrix_generator_stdp_write_row( uint16_t n_half_words_per_row[max_stage]; for (uint32_t i = 0; i < max_stage; i++) { n_half_words_per_row[i] = 0; - if (row_address[i] != NULL) { - pp_address[i] = (uint16_t *) &row_address[i][ - STDP_PLASTIC_PLASTIC_OFFSET + - (obj->n_half_words_per_pp_row_header >> 1)]; + if (row[i] != NULL) { + pp_address[i] = &row[i]->plastic_plastic_data[ + obj->n_half_words_per_pp_row_header]; } else { pp_address[i] = NULL; } @@ -222,7 +210,7 @@ void matrix_generator_stdp_write_row( struct delay_value delay = get_delay(delays[synapse], max_stage); // Check that the position is valid - if (pp_address[delay.stage] == NULL) { + if (delay.stage >= max_stage || pp_address[delay.stage] == NULL) { log_error("Delay stage %u has not been initialised", delay.stage); rt_error(RTE_SWERR); } @@ -243,36 +231,32 @@ void matrix_generator_stdp_write_row( weight_words[i] = 0; } weight_words[obj->weight_half_word] = weight; - n_half_words_per_row[delay.stage] += - obj->n_half_words_per_pp_synapse; + n_half_words_per_row[delay.stage] += obj->n_half_words_per_pp_synapse; space_half_words[delay.stage] -= obj->n_half_words_per_pp_synapse; } // Add padding to any rows that are not word-aligned // and set the size in words for (uint32_t i = 0; i < max_stage; i++) { - if (row_address[i] != NULL) { + if (row[i] != NULL) { if (n_half_words_per_row[i] & 0x1) { - pp_address[i][0] = 0; - pp_address[i] = &pp_address[i][1]; + *pp_address[i]++ = 0; n_half_words_per_row[i]++; } - row_address[i][STDP_PLASTIC_PLASTIC_SIZE] += - n_half_words_per_row[i] >> 1; + row[i]->plastic_plastic_size += n_half_words_per_row[i] >> 1; } } // PP address is now fixed region address // Set the fixed-fixed size to 0 and point to the fixed-plastic region - uint32_t *fixed_address[max_stage]; + row_fixed_t fixed[max_stage]; uint16_t *fp_address[max_stage]; for (uint32_t i = 0; i < max_stage; i++) { - fixed_address[i] = (uint32_t *) pp_address[i]; - if (pp_address[i] != NULL) { - fp_address[i] = (uint16_t *) - &fixed_address[i][STDP_FIXED_PLASTIC_OFFSET]; - fixed_address[i][STDP_FIXED_FIXED_SIZE] = 0; - fixed_address[i][STDP_FIXED_PLASTIC_SIZE] = 0; + fixed[i] = (row_fixed_t) pp_address[i]; + if (fixed[i] != NULL) { + fp_address[i] = fixed[i]->fixed_plastic_data; + fixed[i]->fixed_fixed_size = 0; + fixed[i]->fixed_plastic_size = 0; } else { fp_address[i] = NULL; } @@ -291,10 +275,9 @@ void matrix_generator_stdp_write_row( synapse_index_bits); // Write the half-word - fp_address[delay.stage][0] = fp_half_word; - fp_address[delay.stage] = &fp_address[delay.stage][1]; + *fp_address[delay.stage]++ = fp_half_word; // Increment the size of the current row - fixed_address[delay.stage][STDP_FIXED_PLASTIC_SIZE]++; + fixed[delay.stage]->fixed_plastic_size++; } }