static inline void _print_synaptic_row(synaptic_row_t synaptic_row) { #if LOG_LEVEL >= LOG_DEBUG log_debug("Synaptic row, at address %08x Num plastic words:%u\n", (uint32_t )synaptic_row, synapse_row_plastic_size(synaptic_row)); if (synaptic_row == NULL) { return; } 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); log_debug("Fixed region %u fixed synapses (%u plastic control words):\n", n_fixed_synapses, synapse_row_num_plastic_controls(fixed_region_address)); 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); log_debug("%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", synapse_row_sparse_delay(synapse), synapse_types_get_type_char(synapse_row_sparse_type(synapse)), synapse_row_sparse_index(synapse), SYNAPSE_DELAY_MASK, SYNAPSE_TYPE_INDEX_BITS); } // If there's a plastic region if (synapse_row_plastic_size(synaptic_row) > 0) { log_debug("----------------------------------------\n"); address_t plastic_region_address = synapse_row_plastic_region(synaptic_row); synapse_dynamics_print_plastic_synapses( plastic_region_address, fixed_region_address, ring_buffer_to_input_left_shifts); } log_debug("----------------------------------------\n"); #else use(synaptic_row); #endif // LOG_LEVEL >= LOG_DEBUG }
// This is the "inner loop" of the neural simulation. // Every spike event could cause upto 256 different weights to // be put into the ring buffer. 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); #ifdef SYNAPSE_BENCHMARK num_fixed_pre_synaptic_events += fixed_synapse; #endif // SYNAPSE_BENCHMARK for (; fixed_synapse > 0; fixed_synapse--) { // Get the next 32 bit word from the synaptic_row // (should autoincrement pointer in single instruction) uint32_t synaptic_word = *synaptic_words++; // Extract components from this word uint32_t delay = synapse_row_sparse_delay(synaptic_word); uint32_t combined_synapse_neuron_index = synapse_row_sparse_type_index( synaptic_word); uint32_t weight = synapse_row_sparse_weight(synaptic_word); // Convert into ring buffer offset uint32_t ring_buffer_index = synapses_get_ring_buffer_index_combined( delay + time, combined_synapse_neuron_index); // Add weight to current ring buffer value uint32_t accumulation = ring_buffers[ring_buffer_index] + weight; // If 17th bit is set, saturate accumulator at UINT16_MAX (0xFFFF) // **NOTE** 0x10000 can be expressed as an ARM literal, // but 0xFFFF cannot. Therefore, we use (0x10000 - 1) // to obtain this value uint32_t sat_test = accumulation & 0x10000; if (sat_test) { accumulation = sat_test - 1; saturation_count += 1; } // Store saturated value back in ring-buffer ring_buffers[ring_buffer_index] = accumulation; } }
void synapse_dynamics_print_plastic_synapses( address_t plastic_region_address, address_t fixed_region_address, uint32_t *ring_buffer_to_input_buffer_left_shifts) { use(plastic_region_address); use(fixed_region_address); use(ring_buffer_to_input_buffer_left_shifts); #if LOG_LEVEL >= LOG_DEBUG // Extract seperate arrays of weights (from plastic region), // Control words (from fixed region) and number of plastic synapses weight_t *plastic_words = _plastic_synapses(plastic_region_address); const control_t *control_words = synapse_row_plastic_controls( fixed_region_address); size_t plastic_synapse = synapse_row_num_plastic_controls( fixed_region_address); const pre_event_history_t *event_history = _plastic_event_history( plastic_region_address); log_debug( "Plastic region %u synapses pre-synaptic event buffer count:%u:\n", plastic_synapse, event_history->count_minus_one + 1); // Loop through plastic synapses for (uint32_t i = 0; i < plastic_synapse; i++) { // Get next weight and control word (autoincrementing control word) uint32_t weight = *plastic_words++; uint32_t control_word = *control_words++; uint32_t synapse_type = synapse_row_sparse_type(control_word); log_debug("%08x [%3d: (w: %5u (=", control_word, i, weight); synapses_print_weight( weight, ring_buffer_to_input_buffer_left_shifts[synapse_type]); log_debug("nA) d: %2u, %s, n = %3u)] - {%08x %08x}\n", synapse_row_sparse_delay(control_word), synapse_types_get_type_char(synapse_row_sparse_type( control_word)), synapse_row_sparse_index(control_word), SYNAPSE_DELAY_MASK, SYNAPSE_TYPE_INDEX_BITS); } #endif // LOG_LEVEL >= LOG_DEBUG }
bool synapse_dynamics_process_plastic_synapses( address_t plastic_region_address, address_t fixed_region_address, weight_t *ring_buffers, uint32_t time) { // Extract seperate arrays of plastic synapses (from plastic region), // Control words (from fixed region) and number of plastic synapses plastic_synapse_t *plastic_words = _plastic_synapses( plastic_region_address); const control_t *control_words = synapse_row_plastic_controls( fixed_region_address); size_t plastic_synapse = synapse_row_num_plastic_controls( fixed_region_address); #ifdef SYNAPSE_BENCHMARK num_plastic_pre_synaptic_events += plastic_synapse; #endif // SYNAPSE_BENCHMARK // Get event history from synaptic row pre_event_history_t *event_history = _plastic_event_history( plastic_region_address); // Get last pre-synaptic event from event history // **NOTE** at this level we don't care about individual synaptic delays const uint32_t last_pre_time = event_history->times[event_history->count_minus_one]; // Loop through plastic synapses for (; plastic_synapse > 0; plastic_synapse--) { // Get next control word (autoincrementing) uint32_t control_word = *control_words++; // Extract control-word components // **NOTE** cunningly, control word is just the same as lower // 16-bits of 32-bit fixed synapse so same functions can be used uint32_t delay = synapse_row_sparse_delay(control_word); uint32_t type = synapse_row_sparse_type(control_word); uint32_t index = synapse_row_sparse_index(control_word); uint32_t type_index = synapse_row_sparse_type_index(control_word); // Create update state from the plastic synaptic word update_state_t current_state = synapse_structure_get_update_state( *plastic_words, type); // Update the synapse state final_state_t final_state = _plasticity_update_synapse( time, last_pre_time, delay, current_state, event_history, &post_event_history[index]); // Convert into ring buffer offset uint32_t ring_buffer_index = synapses_get_ring_buffer_index_combined( delay + time, type_index); // Add weight to ring-buffer entry // **NOTE** Dave suspects that this could be a potential location // for overflow ring_buffers[ring_buffer_index] += synapse_structure_get_final_weight( final_state); // Write back updated synaptic word to plastic region *plastic_words++ = synapse_structure_get_final_synaptic_word( final_state); } log_debug("Adding pre-synaptic event to trace at time:%u", time); // Add pre-event const pre_trace_t last_pre_trace = event_history->traces[event_history->count_minus_one]; pre_events_add(time, event_history, timing_add_pre_spike( time, last_pre_time, last_pre_trace)); return true; }