sPyNNaker neural_modelling 7.2.2
Loading...
Searching...
No Matches
spike_source_poisson.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014 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
24#include <common/maths-util.h>
25#include <common/send_mc.h>
26#include <data_specification.h>
27#include <recording.h>
28#include <debug.h>
29#include <normal.h>
30#include <simulation.h>
31#include <spin1_api.h>
32#include <bit_field.h>
33#include <stdfix-full-iso.h>
34#include <limits.h>
35#include <circular_buffer.h>
36
37#include "profile_tags.h"
38#include <profiler.h>
39#include <wfi.h>
40
41#ifndef UNUSED
42#define UNUSED __attribute__((__unused__))
43#endif
44
45// ----------------------------------------------------------------------
46
47#define END_OF_TIME 0xFFFFFFFF
48
69
71typedef struct timed_out_spikes {
73 uint32_t time;
75 uint32_t n_buffers;
77 uint32_t out_spikes[];
79
91
93#define NUMBER_OF_REGIONS_TO_RECORD 1
95#define BYTE_TO_WORD_CONVERTER 4
97#define ISI_SCALE_FACTOR 1000
98
100typedef enum ssp_callback_priorities {
104 SDP = 0,
106 DMA = 1,
108 TIMER = 2
110
112typedef struct {
113 uint32_t x;
114 uint32_t y;
115 uint32_t z;
116 uint32_t c;
117} rng_seed_t;
118
144
151
152__attribute__((aligned(4)))
153typedef struct source_details {
154 unsigned long accum rate;
155 unsigned long accum start;
156 unsigned long accum duration;
157} source_details;
158
160static uint32_t *keys;
161
163typedef struct source_info {
165 uint32_t n_rates;
167 uint32_t index;
169 source_details details[];
171
178
179typedef struct source_expand_region {
181 uint32_t rate_changed;
182 // The number of expander items in the region
183 uint32_t n_items;
184 // The expander items. Because each of these are dynamic they have to be
185 // implied here.
186 source_expand_details items[];
188
190struct sdram_config {
192 uint32_t *address;
194 uint32_t size_in_bytes;
197 uint32_t offset;
199 uint16_t weights[];
200};
201
202
205
208
211
213static uint32_t recording_flags = 0;
214
217static uint32_t time;
218
220static uint32_t simulation_ticks = 0;
221
223static uint32_t infinite_run;
224
227
230
232static uint32_t n_spike_buffer_words;
233
235static uint32_t spike_buffer_size;
236
238static uint32_t timer_period;
239
242
244static uint16_t *input_this_timestep;
245
248
251
253static uint32_t colour;
254
256static uint32_t colour_mask;
257
260static uint32_t n_saturations = 0;
261
277
281static inline uint32_t n_spikes_poisson_fast(UFRACT exp_minus_lambda) {
282 UFRACT p = UFRACT_CONST(1.0);
283 uint32_t k = 0;
284
285 do {
286 k++;
287 // p = p * ulrbits(uni_rng(seed_arg));
288 // Possibly faster multiplication by using DRL's routines
289 p = ulrbits(__stdfix_smul_ulr(bitsulr(p), rng()));
290 } while (bitsulr(p) > bitsulr(exp_minus_lambda));
291 return k - 1;
292}
293
296static inline REAL n_steps_until_next(void) {
297 REAL A = REAL_CONST(0.0);
298 uint32_t U, U0, USTAR;
299
300 while (true) {
301 U = rng();
302 U0 = U;
303
304 do {
305 USTAR = rng();
306 if (U < USTAR) {
307 return A + (REAL) ulrbits(U0);
308 }
309
310 U = rng();
311 } while (U < USTAR);
312
313 A += 1.0k;
314 }
315}
316
317
324 uint32_t mean_inter_spike_interval_in_ticks) {
325 // Round (dist variate * ISI_SCALE_FACTOR), convert to uint32
326 uint32_t value = (uint32_t) roundk(
328 // Now multiply by the mean ISI
329 uint32_t exp_variate = value * mean_inter_spike_interval_in_ticks;
330 // Note that this will be compared to ISI_SCALE_FACTOR in the main loop!
331 return exp_variate;
332}
333
339static inline uint32_t fast_spike_source_get_num_spikes(
340 UFRACT exp_minus_lambda) {
341 // If the value of exp_minus_lambda is very small then it's not worth
342 // using the algorithm, so just return 0
343 if (bitsulr(exp_minus_lambda) == bitsulr(UFRACT_CONST(0.0))) {
344 return 0;
345 }
346 return n_spikes_poisson_fast(exp_minus_lambda);
347}
348
356 REAL sqrt_lambda) {
357 // First we do x = (inv_gauss_cdf(U(0, 1)) * 0.5) + sqrt(lambda)
358 uint32_t U = rng();
359 REAL x = (norminv_urt(U) * HALF) + sqrt_lambda;
360 // Then we return int(roundk(x * x))
361 return (uint32_t) roundk(x * x, 15);
362}
363
368void set_spike_source_rate(uint32_t sub_id, UREAL rate) {
369
370 UREAL rate_per_tick = ukbits(
371 (__U64(bitsuk(rate)) * __U64(bitsulr(ssp_params.seconds_per_tick))) >> 32);
372 log_debug("Setting rate of %u to %KHz (%K per tick)",
373 sub_id, rate, rate_per_tick);
374 spike_source_t *spike_source = &source[sub_id];
375
376 if (rate_per_tick >= ssp_params.slow_rate_per_tick_cutoff) {
377 spike_source->is_fast_source = 1;
378 spike_source->mean_isi_ticks = 0;
379 spike_source->time_to_spike_ticks = 0;
380 if (rate_per_tick >= ssp_params.fast_rate_per_tick_cutoff) {
381 spike_source->sqrt_lambda = SQRTU(rate_per_tick);
382 spike_source->exp_minus_lambda = UFRACT_CONST(0);
383 log_debug(" fast, sqrt_lambda=%K", spike_source->sqrt_lambda);
384 } else {
385 spike_source->exp_minus_lambda = EXPU(rate_per_tick * -1.0k);
386 spike_source->sqrt_lambda = 0.0K;
387 log_debug(" fast, exp_minus_lambda=%K", (UREAL) spike_source->exp_minus_lambda);
388 }
389 } else {
390 if (rate > 0.0K) {
391 spike_source->mean_isi_ticks =
392 (uint32_t) ((bitsuk(ts_per_second)) / bitsuk(rate));
393 log_debug(" slow, isi ticks = %u", spike_source->mean_isi_ticks);
394 } else {
395 spike_source->mean_isi_ticks = 0;
396 log_debug(" slow, isi ticks = 0");
397 }
398
399 spike_source->exp_minus_lambda = UFRACT_CONST(0);
400 spike_source->sqrt_lambda = 0.0K;
401 spike_source->is_fast_source = 0;
402 spike_source->time_to_spike_ticks =
404 }
405}
406
407// ----------------------------------------------------------------------
408
411static void store_provenance_data(address_t provenance_region) {
412 log_debug("writing other provenance data");
413 struct poisson_extension_provenance *prov = (void *) provenance_region;
414
415 // store the data into the provenance data region
417 log_debug("finished other provenance data");
418}
419
420static inline uint32_t ms_to_ticks(unsigned long accum ms) {
421 return (uint32_t) ((ms * ssp_params.ticks_per_ms) + 0.5k);
422}
423
424static inline void set_spike_source_details(uint32_t id, bool rate_changed) {
425 uint32_t index = source_data[id]->index;
426 log_debug("Source %u is at index %u", id, index);
427 source_details details = source_data[id]->details[index];
428 if (rate_changed) {
429 log_debug("Setting rate of %u to %k at %u", id, (s1615) details.rate, time);
430 set_spike_source_rate(id, details.rate);
431 }
432 spike_source_t *p = &(source[id]);
433 p->start_ticks = ms_to_ticks(details.start);
434 log_debug("Start of %u is %u", id, p->start_ticks);
435 if (details.duration == END_OF_TIME) {
436 log_debug("Duration of %u is forever", id);
437 p->end_ticks = END_OF_TIME;
438 } else {
439 uint32_t duration_ticks = ms_to_ticks(details.duration);
440 p->end_ticks = p->start_ticks + duration_ticks;
441 log_debug("Duration of %u is %u, end = %u", id, duration_ticks, p->end_ticks);
442 }
443 if ((index + 1) >= source_data[id]->n_rates) {
444 log_debug("Next of %u never happens", id);
445 p->next_ticks = END_OF_TIME;
446 } else {
447 accum next_start = source_data[id]->details[index + 1].start;
448 p->next_ticks = ms_to_ticks(next_start);
449 log_debug("Next of %u at %u", id, p->next_ticks);
450 }
451}
452
456static inline bit_field_t out_spikes_bitfield(uint32_t n) {
458}
459
461static inline void reset_spikes(void) {
462 spikes->n_buffers = 0;
463 for (uint32_t n = n_spike_buffers_allocated; n > 0; n--) {
464 clear_bit_field(out_spikes_bitfield(n - 1), n_spike_buffer_words);
465 }
466}
467
468
469#if LOG_LEVEL >= LOG_DEBUG
473 spike_source_t *p = &source[s];
474 log_info("atom %d", s);
475 log_info("scaled_start = %u", p->start_ticks);
476 log_info("scaled end = %u", p->end_ticks);
477 log_info("scaled next = %u", p->next_ticks);
478 log_info("is_fast_source = %d", p->is_fast_source);
479 log_info("exp_minus_lambda = %K", (UREAL) p->exp_minus_lambda);
480 log_info("sqrt_lambda = %K", p->sqrt_lambda);
481 log_info("isi_val = %u", p->mean_isi_ticks);
482 log_info("time_to_spike = %u", p->time_to_spike_ticks);
483}
484
486static void print_spike_sources(void) {
487 for (index_t s = 0; s < ssp_params.n_spike_sources; s++) {
489 }
490}
491#endif
492
497static bool read_global_parameters(global_parameters *sdram_globals) {
498 log_info("read global_parameters: starting");
499 ssp_params = *sdram_globals;
500 ts_per_second = ukbits(1000 * bitsuk(ssp_params.ticks_per_ms));
501
502 uint32_t keys_size = sizeof(uint32_t) * ssp_params.n_spike_sources;
503 keys = spin1_malloc(keys_size);
504 if (keys == NULL) {
505 log_error("Couldn't allocate space %u for %u keys",
506 keys_size, ssp_params.n_spike_sources);
507 }
508 spin1_memcpy(keys, &(sdram_globals[1]), keys_size);
509
511
512 log_info("\tset rate mask = %08x",
514 log_info("\tseed = %u %u %u %u", ssp_params.spike_source_seed.c,
518
519 log_info("\tspike sources = %u, starting at %u",
521 log_info("seconds_per_tick = %K", (UREAL) ssp_params.seconds_per_tick);
522 log_info("ticks_per_ms = %K\n", ssp_params.ticks_per_ms);
523 log_info("ts_per_second = %K", ts_per_second);
524 log_info("slow_rate_per_tick_cutoff = %K",
526 log_info("fast_rate_per_tick_cutoff = %K",
528#if LOG_LEVEL >= LOG_DEBUG
529 for (uint32_t i = 0; i < ssp_params.n_spike_sources; i++) {
530 log_debug("Key %u: 0x%08x", i, keys[i]);
531 }
532#endif
533
534 log_info("read_global_parameters: completed successfully");
535 return true;
536}
537
540static inline void read_next_rates(uint32_t id) {
541 if (source_data[id]->index < source_data[id]->n_rates) {
542 source_data[id]->index++;
543 set_spike_source_details(id, true);
544 }
545}
546
552static bool read_rates(source_info *sdram_sources, bool rate_changed, uint32_t next_time) {
553 // Allocate DTCM for array of spike sources and copy block of data
554 if (ssp_params.n_spike_sources > 0) {
555 // the first time around, the array is set to NULL, afterwards,
556 // assuming all goes well, there's an address here.
557 if (source == NULL) {
558 source = spin1_malloc(
560 // if failed to alloc memory, report and fail.
561 if (source == NULL) {
562 log_error("Failed to allocate local sources");
563 return false;
564 }
565 source_data = spin1_malloc(
567 if (source_data == NULL) {
568 log_error("Failed to allocate SDRAM source links");
569 return false;
570 }
571
572 // Copy the address of each source
573 source_info *sdram_source = sdram_sources;
574 for (uint32_t i = 0; i < ssp_params.n_spike_sources; i++) {
575 source_data[i] = sdram_source;
576 sdram_source = (source_info *)
577 &sdram_source->details[sdram_source->n_rates];
578 }
579 }
580
581 // Put the correct values into the current source information
582 for (uint32_t i = 0; i < ssp_params.n_spike_sources; i++) {
583
584 // Find the index for the current time
585 uint32_t index = 0;
586 uint32_t n_rates = source_data[i]->n_rates;
587 while ((index + 1) < n_rates
588 && next_time >= ms_to_ticks(source_data[i]->details[index + 1].start)) {
589 index++;
590 }
591 bool new_index = source_data[i]->index != index;
592 source_data[i]->index = index;
593 set_spike_source_details(i, rate_changed || new_index);
594 }
595 }
596 log_info("read_poisson_parameters: completed successfully");
597 return true;
598}
599
600static bool expand_rates(source_expand_region *items, source_info *sdram_sources) {
601
602 if (!items->rate_changed) {
603 return false;
604 }
605
606 // We need a pointer here as each item is dynamically sized. This pointer
607 // will be updated each time with the start of the next item to be read
608 source_expand_details *item = &(items->items[0]);
609
610 // Similarly, we need a pointer for the current SDRAM source
611 source_info *source = &(sdram_sources[0]);
612
613 // Go though each expander item, which says how many times to repeat
614 for (uint32_t i = 0; i < items->n_items; i++) {
615
616 // Copy SDRAM data to local
617 uint32_t n_rates = item->info.n_rates;
618 log_debug("Reading %u rates", n_rates);
619 source_details details[n_rates];
620 for (uint32_t k = 0; k < n_rates; k++) {
621 details[k] = item->info.details[k];
622 log_debug("Repeating rate %k %u times",
623 (accum) details[k].rate, item->count);
624 }
625
626 // Repeat the same thing this many times
627 for (uint32_t j = 0; j < item->count; j++) {
628 source->n_rates = n_rates;
629 source->index = 0;
630 for (uint32_t k = 0; k < n_rates; k++) {
631 source->details[k] = details[k];
632 }
633
634 // Update the source point to just after the last item written
635 source = (source_info *) &(source->details[n_rates]);
636 }
637
638 // Update the item pointer to just after the last item read
639 item = (source_expand_details *) &(item->info.details[n_rates]);
640 }
641
642 items->rate_changed = false;
643 return true;
644}
645
650 // Get the system region
651 void *recording_region = data_specification_get_region(
652 SPIKE_HISTORY_REGION, ds_regions);
653
654 bool success = recording_initialize(&recording_region, &recording_flags);
655 log_info("Recording flags = 0x%08x", recording_flags);
656
657 return success;
658}
659
662static inline void expand_spike_recording_buffer(uint32_t n_spikes) {
663 uint32_t new_size = 8 + (n_spikes * spike_buffer_size);
664 timed_out_spikes *new_spikes = spin1_malloc(new_size);
665 if (new_spikes == NULL) {
666 log_error("Cannot reallocate spike buffer");
668 }
669
670 // bzero the new buffer
671 uint32_t *data = (uint32_t *) new_spikes;
672 for (uint32_t n = new_size >> 2; n > 0; n--) {
673 data[n - 1] = 0;
674 }
675
676 // Copy over old buffer if we have it
677 if (spikes != NULL) {
678 spin1_memcpy(new_spikes, spikes,
681 }
682
683 spikes = new_spikes;
685}
686
691static bool initialize(void) {
692 log_info("Initialise: started");
693
694 // Get the address this core's DTCM data starts at from SRAM
697
698 // Read the header
699 if (!data_specification_read_header(ds_regions)) {
700 return false;
701 }
702
703 // Get the timing details and set up the simulation interface
705 data_specification_get_region(SYSTEM, ds_regions),
706 APPLICATION_NAME_HASH, &timer_period, &simulation_ticks,
707 &infinite_run, &time, SDP, DMA)) {
708 return false;
709 }
710
713 data_specification_get_region(PROVENANCE_REGION, ds_regions));
714
715 // setup recording region
716 if (!initialise_recording(ds_regions)) {
717 return false;
718 }
719
720 // Setup regions that specify spike source array data
722 data_specification_get_region(POISSON_PARAMS, ds_regions))) {
723 return false;
724 }
725
726 void *rates_region = data_specification_get_region(RATES, ds_regions);
727 bool rates_changed = expand_rates(
728 data_specification_get_region(EXPANDER_REGION, ds_regions),
729 rates_region);
730 if (!read_rates(rates_region, rates_changed, 0)) {
731 return false;
732 }
733
734 // print spike sources for debug purposes
735#if LOG_LEVEL >= LOG_DEBUG
737#endif
738
739 // Set up recording buffer
741 n_spike_buffer_words = get_bit_field_size(ssp_params.n_spike_sources);
742 spike_buffer_size = n_spike_buffer_words * sizeof(uint32_t);
744
745 // Setup profiler
747 data_specification_get_region(PROFILER_REGION, ds_regions));
748
749 // Setup SDRAM transfer
750 struct sdram_config *sdram_conf = data_specification_get_region(
751 SDRAM_PARAMS_REGION, ds_regions);
752 uint32_t sdram_inputs_size = sizeof(struct sdram_config) + (
753 ssp_params.n_spike_sources * sizeof(uint16_t));
754 sdram_inputs = spin1_malloc(sdram_inputs_size);
755 if (sdram_inputs == NULL) {
756 log_error("Could not allocate %d bytes for SDRAM inputs",
757 sdram_inputs_size);
758 return false;
759 }
760 spin1_memcpy(sdram_inputs, sdram_conf, sdram_inputs_size);
761 log_info("Writing output to address 0x%08x, size in total %d,"
762 "offset in half-words %d, size to write %d", sdram_inputs->address,
764 ssp_params.n_spike_sources * sizeof(uint16_t));
765 if (sdram_inputs->size_in_bytes != 0) {
767 if (input_this_timestep == NULL) {
768 log_error("Could not allocate %d bytes for input this timestep",
770 return false;
771 }
773 for (uint32_t i = 0; i < ssp_params.n_spike_sources; i++) {
774 log_debug("weight[%u] = %u", i, sdram_inputs->weights[i]);
775 }
776 }
777
778 // Allocate buffer to allow rate change (2 ints) per source
780 (ssp_params.n_spike_sources * 2) + 1);
781 if (rate_change_buffer == NULL) {
782 log_error("Could not allocate rate change buffer!");
783 return false;
784 }
785
786 log_info("Initialise: completed successfully");
787
788 return true;
789}
790
792static void resume_callback(void) {
794
797
798 // If we are resetting, re-read the seed
799 bool rates_changed = false;
800 if (time == UINT32_MAX) {
801 if (!read_global_parameters(data_specification_get_region(
802 POISSON_PARAMS, ds_regions))) {
803 log_error("failed to reread the Poisson params");
805 }
806 rates_changed = true;
807 }
808
809 void *rates_region = data_specification_get_region(RATES, ds_regions);
810 bool expand_rates_changed = expand_rates(
811 data_specification_get_region(EXPANDER_REGION, ds_regions),
812 rates_region);
813 rates_changed = rates_changed || expand_rates_changed;
814
815 if (!read_rates(rates_region, rates_changed, time + 1)) {
816 log_error("failed to reread the Poisson rates from SDRAM");
818 }
819
820 log_info("Successfully resumed Poisson spike source at time: %u", time);
821
822 // print spike sources for debug purposes
823#if LOG_LEVEL >= LOG_DEBUG
825#endif
826}
827
831static inline void mark_spike(uint32_t neuron_id, uint32_t n_spikes) {
832 if (recording_flags > 0) {
835 }
836 if (spikes->n_buffers < n_spikes) {
838 }
839 for (uint32_t n = n_spikes; n > 0; n--) {
840 bit_field_set(out_spikes_bitfield(n - 1), neuron_id);
841 }
842 }
843}
844
847static inline void record_spikes(uint32_t time) {
848 if ((spikes != NULL) && (spikes->n_buffers > 0)) {
849 spikes->time = time;
851 reset_spikes();
852 }
853}
854
855static inline void add_sdram_spikes(uint32_t s_id, uint32_t num_spikes) {
856 uint32_t accumulation = input_this_timestep[sdram_inputs->offset + s_id] +
857 (sdram_inputs->weights[s_id] * num_spikes);
858 uint32_t sat_test = accumulation & 0xFFFF0000;
859 if (sat_test) {
860 accumulation = 0xFFFF;
862 }
863 input_this_timestep[sdram_inputs->offset + s_id] = (uint16_t) accumulation;
864}
865
870 if ((time >= source->start_ticks) && (time < source->end_ticks)) {
871 // Get number of spikes to send this tick
872 uint32_t num_spikes = 0;
873
874 // If sqrt_lambda has been set then use the Gaussian algorithm for
875 // faster sources
877 profiler_write_entry_disable_irq_fiq(
878 PROFILER_ENTER | PROFILER_PROB_FUNC);
881 profiler_write_entry_disable_irq_fiq(
882 PROFILER_EXIT | PROFILER_PROB_FUNC);
883 } else {
884 // Call the fast source Poisson algorithm
885 profiler_write_entry_disable_irq_fiq(
886 PROFILER_ENTER | PROFILER_PROB_FUNC);
889 profiler_write_entry_disable_irq_fiq(
890 PROFILER_EXIT | PROFILER_PROB_FUNC);
891 }
892
893 log_debug("Generating %d spikes", num_spikes);
894
895 // If there are any
896 if (num_spikes > 0) {
897 // Write spike to out spikes
898 mark_spike(s_id, num_spikes);
899
900 // If no key has been given, do not send spikes to fabric
901 if (ssp_params.has_key) {
902 // Send spikes
903 const uint32_t spike_key = keys[s_id] | colour;
904 send_spike_mc_payload(spike_key, num_spikes);
905 } else if (sdram_inputs->address != 0) {
906 add_sdram_spikes(s_id, num_spikes);
907 }
908 }
909 }
910}
911
916 if ((time >= source->start_ticks) && (time < source->end_ticks)
917 && (source->mean_isi_ticks != 0)) {
918 uint32_t count = 0;
919 // Mark a spike while the "timer" is below the scale factor value
921 count++;
922
923 // Update time to spike (note, this might not get us back above
924 // the scale factor, particularly if the mean_isi is smaller)
925 profiler_write_entry_disable_irq_fiq(
926 PROFILER_ENTER | PROFILER_PROB_FUNC);
929 profiler_write_entry_disable_irq_fiq(
930 PROFILER_EXIT | PROFILER_PROB_FUNC);
931 }
932 if (count) {
933 // Write spike to out_spikes
934 mark_spike(s_id, count);
935
936 // if no key has been given, do not send spike to fabric.
937 if (ssp_params.has_key) {
938 // Send package
939 const uint32_t spike_key = keys[s_id] | colour;
940 send_spike_mc_payload(spike_key, count);
941 } else if (sdram_inputs->address != 0) {
942 add_sdram_spikes(s_id, count);
943 }
944 }
945
946 // Now we have finished for this tick, subtract the scale factor
948 }
949}
950
957static void timer_callback(UNUSED uint timer_count, UNUSED uint unused) {
958 profiler_write_entry_disable_irq_fiq(PROFILER_ENTER | PROFILER_TIMER);
959
960 time++;
961
962 log_debug("Timer tick %u", time);
963
964 // If a fixed number of simulation ticks are specified and these have passed
966 // go into pause and resume state to avoid another tick
968
969 profiler_write_entry_disable_irq_fiq(PROFILER_EXIT | PROFILER_TIMER);
970
971 // Finalise any recordings that are in progress, writing back the final
972 // amounts of samples recorded to SDRAM
973 if (recording_flags > 0) {
975 }
976
978
979 // Subtract 1 from the time so this tick gets done again on the next
980 // run
981 time--;
983 return;
984 }
985
986 // Set the colour for the time step
988
989 // Do any rate changes
990 while (circular_buffer_size(rate_change_buffer) >= 2) {
991 uint32_t id = 0;
992 UREAL rate = 0.0k;
993 circular_buffer_get_next(rate_change_buffer, &id);
994 circular_buffer_get_next(rate_change_buffer, (uint32_t *) &rate);
995 set_spike_source_rate(id, rate);
996 }
997
998 // Reset the inputs this timestep if using them
999 if (sdram_inputs->address != 0) {
1001 }
1002
1003 // Loop through spike sources and see if they need updating
1004 // NOTE: This full loop needs to happen first with processing in a second
1005 // separate loop. This is to ensure that the random generator use matches
1006 // between a single run and a split run (as slow sources can produce
1007 // multiple spikes in a single time step).
1008 for (index_t s_id = 0; s_id < ssp_params.n_spike_sources; s_id++) {
1009 spike_source_t *spike_source = &source[s_id];
1010
1011 // Move to the next tick now if needed
1012 if (time >= spike_source->next_ticks) {
1013 log_debug("Moving to next rate at time %d", time);
1014 read_next_rates(s_id);
1015#if LOG_LEVEL >= LOG_DEBUG
1016 print_spike_source(s_id);
1017#endif
1018 }
1019 }
1020
1021 // Loop through the sources and process them
1022 for (index_t s_id = 0; s_id < ssp_params.n_spike_sources; s_id++) {
1023 spike_source_t *spike_source = &source[s_id];
1024 if (spike_source->is_fast_source) {
1025 process_fast_source(s_id, spike_source);
1026 } else {
1027 process_slow_source(s_id, spike_source);
1028 }
1029 }
1030
1031 profiler_write_entry_disable_irq_fiq(PROFILER_EXIT | PROFILER_TIMER);
1032
1033 // If transferring over SDRAM, transfer now
1034 if (sdram_inputs->address != 0) {
1037 }
1038
1039 // Record output spikes if required
1040 if (recording_flags > 0) {
1042 }
1043}
1044
1049 uint32_t id = key & ssp_params.set_rate_neuron_id_mask;
1050 if ((id < ssp_params.first_source_id) ||
1052 return;
1053 }
1054 // The above condition prevents this from being negative
1055 uint32_t sub_id = (uint32_t) id - ssp_params.first_source_id;
1056 circular_buffer_add(rate_change_buffer, sub_id);
1057 circular_buffer_add(rate_change_buffer, payload);
1058}
1059
1061void c_main(void) {
1062 // Load DTCM data
1063 time = 0;
1064 if (!initialize()) {
1065 log_error("Error in initialisation - exiting!");
1067 }
1068
1069 // Start the time at "-1" so that the first tick will be 0
1070 time = UINT32_MAX;
1071
1072 // Set timer tick (in microseconds)
1073 spin1_set_timer_tick(timer_period);
1074
1075 // Register callback
1079
1081}
uint32_t * bit_field_t
uint32_t index_t
circular_buffer circular_buffer_initialize(uint32_t size)
uint32_t * address_t
data_specification_metadata_t * data_specification_get_data_address(void)
bool data_specification_read_header(data_specification_metadata_t *ds_regions)
void log_error(const char *message,...)
void log_debug(const char *message,...)
void log_info(const char *message,...)
static uint32_t key
Base multicast key for sending messages.
uint32_t n_spikes[2]
Spike buffer counters.
maths-util.h - first created 7/10/2013 version 0.1
#define REAL_CONST(x)
Define a constant of type REAL.
Definition maths-util.h:104
unsigned accum UREAL
Type used for "unsigned real" numbers.
Definition maths-util.h:94
#define REAL_COMPARE(x, op, y)
Compare two REAL numbers.
Definition maths-util.h:192
#define HALF
A REAL 0.5.
Definition maths-util.h:121
#define EXPU(x)
This calculates the exponential (to base e) of the argument.
Definition maths-util.h:145
accum REAL
Type used for "real" numbers.
Definition maths-util.h:91
#define UFRACT_CONST(x)
Define a constant of type UFRACT.
Definition maths-util.h:116
#define SQRTU(x)
This calculates the square-root of the argument.
Definition maths-util.h:135
unsigned long fract UFRACT
Type used for "unsigned fractional" numbers.
Definition maths-util.h:100
#define ZERO
A REAL 0.0.
Definition maths-util.h:123
static key_t spike_key(spike_t s)
helper method to retrieve the key from a spike
@ PROFILER_TIMER
timer
void profiler_init(uint32_t *data_region)
void profiler_finalise(void)
bool recording_initialize(void **recording_data_address, uint32_t *recording_flags)
void recording_finalise(void)
bool recording_record(channel_index_t channel, void *data, size_t size_bytes)
void recording_reset(void)
RTE_SWERR
void sark_free(void *ptr)
void rt_error(uint code,...)
void sark_word_set(void *dest, uint data, uint n)
void simulation_handle_pause_resume(resume_callback_t callback)
void simulation_set_provenance_function(prov_callback_t provenance_function, address_t provenance_data_address)
bool simulation_is_finished(void)
void simulation_ready_to_read(void)
void simulation_run(void)
bool simulation_initialise(address_t address, uint32_t expected_application_magic_number, uint32_t *timer_period, uint32_t *simulation_ticks_pointer, uint32_t *infinite_run_pointer, uint32_t *time_pointer, int sdp_packet_callback_priority, int dma_transfer_complete_priority)
Tags for profiling of the spike source poisson.
static void process_slow_source(index_t s_id, spike_source_t *source)
Handle a slow spike source.
static void print_spike_source(index_t s)
Print a spike source.
uint32_t n_buffers
Number of spike-recording buffers.
static bool initialize(void)
Initialise the model by reading in the regions and checking recording data.
static void expand_spike_recording_buffer(uint32_t n_spikes)
Expand the space for recording spikes.
uint32_t count
The number of items to expand.
uint16_t weights[]
The weight to send for each active Poisson source.
uint32_t size_in_bytes
The size of the input data to be transferred per core.
static uint16_t * input_this_timestep
The inputs to be sent at the end of this timestep.
static circular_buffer rate_change_buffer
Buffer for rate change packets.
uint32_t n_colour_bits
Number of bits to use for colour.
region
spike source array region IDs in human readable form
@ PROFILER_REGION
profiling region
@ SPIKE_HISTORY_REGION
spike history recording region
@ PROVENANCE_REGION
provenance region
@ SYSTEM
simulation interface master control
@ EXPANDER_REGION
Expanding of parameters.
@ POISSON_PARAMS
application configuration; global_parameters
@ RATES
rates to apply; source_info
@ SDRAM_PARAMS_REGION
SDRAM transfer parameters region.
static uint32_t simulation_ticks
the number of timer ticks that this model should run for before exiting.
static bool initialise_recording(data_specification_metadata_t *ds_regions)
Initialise the recording parts of the model.
static void mark_spike(uint32_t neuron_id, uint32_t n_spikes)
records spikes as needed
UREAL fast_rate_per_tick_cutoff
The border rate between fast and faster sources.
uint8_t * address
The start address of the input data to be transferred.
uint32_t time
Time of recording.
static global_parameters ssp_params
The global_parameters for the sub-population.
static UREAL ts_per_second
The timesteps per second.
uint32_t first_source_id
The ID of the first source relative to the population as a whole.
static uint32_t faster_spike_source_get_num_spikes(REAL sqrt_lambda)
Determine how many spikes to transmit this timer tick, for a faster source (where λ is large enough t...
static REAL n_steps_until_next(void)
How many time steps until the next spike for a slow Poisson source.
static source_info ** source_data
Array of pointers to sequences of rate data.
static uint32_t colour_mask
The mask to apply to the time to get the colour.
static bool read_rates(source_info *sdram_sources, bool rate_changed, uint32_t next_time)
Read the rates of the Poisson.
uint32_t rate_changed
Determine if any rates have been changed.
uint32_t n_saturations
number of saturations
source_details details[]
Array of rates.
static bool read_global_parameters(global_parameters *sdram_globals)
Read the global parameters stored in Poisson parameter region.
static uint32_t colour
The colour of the current time step.
uint32_t index
Where in the array of rate descriptors we are.
static void read_next_rates(uint32_t id)
Get the next chunk of rates read.
uint32_t out_spikes[]
Spike recording buffers; sort of a bit_field_t[].
uint32_t n_rates
The number of rates.
static uint32_t rng(void)
Random number generation for the Poisson sources. This is a local version for speed of operation.
static void record_spikes(uint32_t time)
writing spikes to SDRAM
uint32_t end_ticks
When the current control regime ends, in timer ticks.
callback_priorities
Priorities for interrupt handlers.
@ TIMER
Regular timer interrupt is lowest priority.
@ MULTICAST
Multicast packet reception uses the FIQ.
@ DMA
DMA complete handling is medium priority.
@ SDP
SDP handling is highest ordinary priority.
static void print_spike_sources(void)
Print all spike sources.
static void reset_spikes(void)
Reset the spike buffer by clearing the bit field.
uint32_t start_ticks
When the current control regime starts, in timer ticks.
static void store_provenance_data(address_t provenance_region)
Writes the provenance data.
static uint32_t fast_spike_source_get_num_spikes(UFRACT exp_minus_lambda)
Determine how many spikes to transmit this timer tick, for a fast source.
UREAL ticks_per_ms
The number of ticks per millisecond for setting the start and duration.
static uint32_t * keys
The keys to send spikes with.
uint32_t max_spikes_per_tick
Maximum expected spikes per tick (for recording)
uint32_t is_fast_source
Flag for whether we're in fast or slow mode.
static struct sdram_config * sdram_inputs
Where synaptic input is to be written.
static uint32_t n_spikes_poisson_fast(UFRACT exp_minus_lambda)
How many spikes to generate for a fast Poisson source.
static spike_source_t * source
The currently applied rate descriptors.
void set_spike_source_rate(uint32_t sub_id, UREAL rate)
Set the spike source rate as required.
uint32_t time_to_spike_ticks
Planned time to spike, in ticks.
UREAL sqrt_lambda
sqrt(λ)
static uint32_t recording_flags
keeps track of which types of recording should be done to this model.
static uint32_t n_spike_buffers_allocated
The number of recording spike buffers that have been allocated.
static uint32_t infinite_run
the int that represents the bool for if the run is infinite or not.
static timed_out_spikes * spikes
The recorded spikes.
source_info info
The details for the given number of items.
void c_main(void)
The entry point for this model.
static uint32_t slow_spike_source_get_time_to_spike(uint32_t mean_inter_spike_interval_in_ticks)
Determine the time in timer ticks multiplied by ISI_SCALE_FACTOR until the next spike is to occur giv...
uint32_t next_ticks
When we should load the next control regime, in timer ticks.
uint32_t mean_isi_ticks
Mean interspike interval, in ticks.
static uint32_t n_saturations
static void timer_callback(uint timer_count, uint unused)
Timer interrupt callback.
uint32_t set_rate_neuron_id_mask
The mask to work out the neuron ID when setting the rate.
static uint32_t n_spike_buffer_words
The number of words needed for 1 bit per source.
static uint32_t timer_period
The timer period.
UREAL slow_rate_per_tick_cutoff
The border rate between slow and fast sources.
UFRACT exp_minus_lambda
exp(-λ)
static void process_fast_source(index_t s_id, spike_source_t *source)
Handle a fast spike source.
UFRACT seconds_per_tick
The time between ticks in seconds for setting the rate.
static uint32_t time
rng_seed_t spike_source_seed
The seed for the Poisson generation process.
uint32_t has_key
True if there is a key to transmit, False otherwise.
static bit_field_t out_spikes_bitfield(uint32_t n)
Set specific spikes for recording.
static void multicast_packet_callback(uint key, uint payload)
Multicast callback used to set rate when injected in a live example.
#define ISI_SCALE_FACTOR
A scale factor to allow the use of integers for "inter-spike intervals".
static void resume_callback(void)
Run any functions needed at resume time.
uint32_t n_spike_sources
The number of sources in this sub-population.
static uint32_t spike_buffer_size
The size of each spike buffer in bytes.
Parameters of the SpikeSourcePoisson.
Structure of the provenance data.
An RNG seed of 4 words.
A region of SDRAM used to transfer synapses.
Collection of rates to apply over time to a particular spike source.
data structure for Poisson sources
data structure for recording spikes
MCPL_PACKET_RECEIVED
TIMER_TICK
#define NULL
uint spin1_dma_transfer(uint tag, void *system_address, void *tcm_address, uint direction, uint length)
void spin1_memcpy(void *dst, void const *src, uint len)
DMA_WRITE
void spin1_callback_on(uint event_id, callback_t cback, int priority)
unsigned int uint
#define __U64(x)
accum s1615