sPyNNaker neural_modelling 7.1.1
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
150
151__attribute__((aligned(4)))
152typedef struct source_details {
153 unsigned long accum rate;
154 unsigned long accum start;
155 unsigned long accum duration;
156} source_details;
157
159static uint32_t *keys;
160
162typedef struct source_info {
164 uint32_t n_rates;
166 uint32_t index;
168 source_details details[];
170
177
178typedef struct source_expand_region {
180 uint32_t rate_changed;
181 // The number of expander items in the region
182 uint32_t n_items;
183 // The expander items. Because each of these are dynamic they have to be
184 // implied here.
185 source_expand_details items[];
187
189struct sdram_config {
191 uint32_t *address;
193 uint32_t size_in_bytes;
196 uint32_t offset;
198 uint16_t weights[];
199};
200
201
204
207
210
212static uint32_t recording_flags = 0;
213
216static uint32_t time;
217
219static uint32_t simulation_ticks = 0;
220
222static uint32_t infinite_run;
223
226
229
231static uint32_t n_spike_buffer_words;
232
234static uint32_t spike_buffer_size;
235
237static uint32_t timer_period;
238
241
243static uint16_t *input_this_timestep;
244
247
250
252static uint32_t colour;
253
255static uint32_t colour_mask;
256
272
276static inline uint32_t n_spikes_poisson_fast(UFRACT exp_minus_lambda) {
277 UFRACT p = UFRACT_CONST(1.0);
278 uint32_t k = 0;
279
280 do {
281 k++;
282 // p = p * ulrbits(uni_rng(seed_arg));
283 // Possibly faster multiplication by using DRL's routines
284 p = ulrbits(__stdfix_smul_ulr(bitsulr(p), rng()));
285 } while (bitsulr(p) > bitsulr(exp_minus_lambda));
286 return k - 1;
287}
288
291static inline REAL n_steps_until_next(void) {
292 REAL A = REAL_CONST(0.0);
293 uint32_t U, U0, USTAR;
294
295 while (true) {
296 U = rng();
297 U0 = U;
298
299 do {
300 USTAR = rng();
301 if (U < USTAR) {
302 return A + (REAL) ulrbits(U0);
303 }
304
305 U = rng();
306 } while (U < USTAR);
307
308 A += 1.0k;
309 }
310}
311
312
319 uint32_t mean_inter_spike_interval_in_ticks) {
320 // Round (dist variate * ISI_SCALE_FACTOR), convert to uint32
321 uint32_t value = (uint32_t) roundk(
323 // Now multiply by the mean ISI
324 uint32_t exp_variate = value * mean_inter_spike_interval_in_ticks;
325 // Note that this will be compared to ISI_SCALE_FACTOR in the main loop!
326 return exp_variate;
327}
328
334static inline uint32_t fast_spike_source_get_num_spikes(
335 UFRACT exp_minus_lambda) {
336 // If the value of exp_minus_lambda is very small then it's not worth
337 // using the algorithm, so just return 0
338 if (bitsulr(exp_minus_lambda) == bitsulr(UFRACT_CONST(0.0))) {
339 return 0;
340 }
341 return n_spikes_poisson_fast(exp_minus_lambda);
342}
343
351 REAL sqrt_lambda) {
352 // First we do x = (inv_gauss_cdf(U(0, 1)) * 0.5) + sqrt(lambda)
353 uint32_t U = rng();
354 REAL x = (norminv_urt(U) * HALF) + sqrt_lambda;
355 // Then we return int(roundk(x * x))
356 return (uint32_t) roundk(x * x, 15);
357}
358
363void set_spike_source_rate(uint32_t sub_id, unsigned long accum rate) {
364
365 REAL rate_per_tick = kbits(
366 (__U64(bitsk(rate)) * __U64(bitsulr(ssp_params.seconds_per_tick))) >> 32);
367 log_debug("Setting rate of %u to %kHz (%k per tick)",
368 sub_id, rate, rate_per_tick);
369 spike_source_t *spike_source = &source[sub_id];
370
371 if (rate_per_tick >= ssp_params.slow_rate_per_tick_cutoff) {
372 spike_source->is_fast_source = 1;
373 spike_source->mean_isi_ticks = 0;
374 spike_source->time_to_spike_ticks = 0;
375 if (rate_per_tick >= ssp_params.fast_rate_per_tick_cutoff) {
376 spike_source->sqrt_lambda = SQRT(rate_per_tick);
377 spike_source->exp_minus_lambda = UFRACT_CONST(0);
378 } else {
379 spike_source->exp_minus_lambda = (UFRACT) EXP(-rate_per_tick);
380 spike_source->sqrt_lambda = ZERO;
381 }
382 } else {
383 if (rate > 0) {
384 spike_source->mean_isi_ticks =
385 (uint32_t) ((bitsulk((unsigned long accum) ts_per_second)) / bitsulk(rate));
386 } else {
387 spike_source->mean_isi_ticks = 0;
388 }
389
390 spike_source->exp_minus_lambda = UFRACT_CONST(0);
391 spike_source->sqrt_lambda = ZERO;
392 spike_source->is_fast_source = 0;
393 spike_source->time_to_spike_ticks =
395 }
396}
397
398// ----------------------------------------------------------------------
399
402static void store_provenance_data(address_t provenance_region) {
403 log_debug("writing other provenance data");
404 struct poisson_extension_provenance *prov = (void *) provenance_region;
405
406 // store the data into the provenance data region
407 prov->times_tdma_fell_behind = 0;
408 log_debug("finished other provenance data");
409}
410
411static inline uint32_t ms_to_ticks(unsigned long accum ms) {
412 return (uint32_t) ((ms * ssp_params.ticks_per_ms) + 0.5k);
413}
414
415static inline void set_spike_source_details(uint32_t id, bool rate_changed) {
416 uint32_t index = source_data[id]->index;
417 log_debug("Source %u is at index %u", id, index);
418 source_details details = source_data[id]->details[index];
419 if (rate_changed) {
420 log_debug("Setting rate of %u to %k at %u", id, (s1615) details.rate, time);
421 set_spike_source_rate(id, details.rate);
422 }
423 spike_source_t *p = &(source[id]);
424 p->start_ticks = ms_to_ticks(details.start);
425 log_debug("Start of %u is %u", id, p->start_ticks);
426 if (details.duration == END_OF_TIME) {
427 log_debug("Duration of %u is forever", id);
428 p->end_ticks = END_OF_TIME;
429 } else {
430 uint32_t duration_ticks = ms_to_ticks(details.duration);
431 p->end_ticks = p->start_ticks + duration_ticks;
432 log_debug("Duration of %u is %u, end = %u", id, duration_ticks, p->end_ticks);
433 }
434 if ((index + 1) >= source_data[id]->n_rates) {
435 log_debug("Next of %u never happens", id);
436 p->next_ticks = END_OF_TIME;
437 } else {
438 accum next_start = source_data[id]->details[index + 1].start;
439 p->next_ticks = ms_to_ticks(next_start);
440 log_debug("Next of %u at %u", id, p->next_ticks);
441 }
442}
443
447static inline bit_field_t out_spikes_bitfield(uint32_t n) {
449}
450
452static inline void reset_spikes(void) {
453 spikes->n_buffers = 0;
454 for (uint32_t n = n_spike_buffers_allocated; n > 0; n--) {
455 clear_bit_field(out_spikes_bitfield(n - 1), n_spike_buffer_words);
456 }
457}
458
459
460#if LOG_LEVEL >= LOG_DEBUG
464 spike_source_t *p = &source[s];
465 log_info("atom %d", s);
466 log_info("scaled_start = %u", p->start_ticks);
467 log_info("scaled end = %u", p->end_ticks);
468 log_info("scaled next = %u", p->next_ticks);
469 log_info("is_fast_source = %d", p->is_fast_source);
470 log_info("exp_minus_lambda = %k", (REAL) p->exp_minus_lambda);
471 log_info("sqrt_lambda = %k", p->sqrt_lambda);
472 log_info("isi_val = %u", p->mean_isi_ticks);
473 log_info("time_to_spike = %u", p->time_to_spike_ticks);
474}
475
477static void print_spike_sources(void) {
478 for (index_t s = 0; s < ssp_params.n_spike_sources; s++) {
480 }
481}
482#endif
483
488static bool read_global_parameters(global_parameters *sdram_globals) {
489 log_info("read global_parameters: starting");
490 ssp_params = *sdram_globals;
491 ts_per_second = ukbits(1000 * bitsuk(ssp_params.ticks_per_ms));
492
493 uint32_t keys_size = sizeof(uint32_t) * ssp_params.n_spike_sources;
494 keys = spin1_malloc(keys_size);
495 if (keys == NULL) {
496 log_error("Couldn't allocate space %u for %u keys",
497 keys_size, ssp_params.n_spike_sources);
498 }
499 spin1_memcpy(keys, &(sdram_globals[1]), keys_size);
500
502
503 log_info("\tset rate mask = %08x",
505 log_info("\tseed = %u %u %u %u", ssp_params.spike_source_seed.c,
509
510 log_info("\tspike sources = %u, starting at %u",
512 log_info("seconds_per_tick = %k\n", (REAL) ssp_params.seconds_per_tick);
513 log_info("ticks_per_ms = %k\n", ssp_params.ticks_per_ms);
514 log_info("ts_per_second = %k", ts_per_second);
515 log_info("slow_rate_per_tick_cutoff = %k\n",
517 log_info("fast_rate_per_tick_cutoff = %k\n",
519#if LOG_LEVEL >= LOG_DEBUG
520 for (uint32_t i = 0; i < ssp_params.n_spike_sources; i++) {
521 log_debug("Key %u: 0x%08x", i, keys[i]);
522 }
523#endif
524
525 log_info("read_global_parameters: completed successfully");
526 return true;
527}
528
531static inline void read_next_rates(uint32_t id) {
532 if (source_data[id]->index < source_data[id]->n_rates) {
533 source_data[id]->index++;
534 set_spike_source_details(id, true);
535 }
536}
537
543static bool read_rates(source_info *sdram_sources, bool rate_changed, uint32_t next_time) {
544 // Allocate DTCM for array of spike sources and copy block of data
545 if (ssp_params.n_spike_sources > 0) {
546 // the first time around, the array is set to NULL, afterwards,
547 // assuming all goes well, there's an address here.
548 if (source == NULL) {
549 source = spin1_malloc(
551 // if failed to alloc memory, report and fail.
552 if (source == NULL) {
553 log_error("Failed to allocate local sources");
554 return false;
555 }
556 source_data = spin1_malloc(
558 if (source_data == NULL) {
559 log_error("Failed to allocate SDRAM source links");
560 return false;
561 }
562
563 // Copy the address of each source
564 source_info *sdram_source = sdram_sources;
565 for (uint32_t i = 0; i < ssp_params.n_spike_sources; i++) {
566 source_data[i] = sdram_source;
567 sdram_source = (source_info *)
568 &sdram_source->details[sdram_source->n_rates];
569 }
570 }
571
572 // Put the correct values into the current source information
573 for (uint32_t i = 0; i < ssp_params.n_spike_sources; i++) {
574
575 // Find the index for the current time
576 uint32_t index = 0;
577 uint32_t n_rates = source_data[i]->n_rates;
578 while ((index + 1) < n_rates
579 && next_time >= ms_to_ticks(source_data[i]->details[index + 1].start)) {
580 index++;
581 }
582 bool new_index = source_data[i]->index != index;
583 source_data[i]->index = index;
584 set_spike_source_details(i, rate_changed || new_index);
585 }
586 }
587 log_info("read_poisson_parameters: completed successfully");
588 return true;
589}
590
591static bool expand_rates(source_expand_region *items, source_info *sdram_sources) {
592
593 if (!items->rate_changed) {
594 return false;
595 }
596
597 // We need a pointer here as each item is dynamically sized. This pointer
598 // will be updated each time with the start of the next item to be read
599 source_expand_details *item = &(items->items[0]);
600
601 // Similarly, we need a pointer for the current SDRAM source
602 source_info *source = &(sdram_sources[0]);
603
604 // Go though each expander item, which says how many times to repeat
605 for (uint32_t i = 0; i < items->n_items; i++) {
606
607 // Copy SDRAM data to local
608 uint32_t n_rates = item->info.n_rates;
609 log_debug("Reading %u rates", n_rates);
610 source_details details[n_rates];
611 for (uint32_t k = 0; k < n_rates; k++) {
612 details[k] = item->info.details[k];
613 log_debug("Repeating rate %k %u times",
614 (accum) details[k].rate, item->count);
615 }
616
617 // Repeat the same thing this many times
618 for (uint32_t j = 0; j < item->count; j++) {
619 source->n_rates = n_rates;
620 source->index = 0;
621 for (uint32_t k = 0; k < n_rates; k++) {
622 source->details[k] = details[k];
623 }
624
625 // Update the source point to just after the last item written
626 source = (source_info *) &(source->details[n_rates]);
627 }
628
629 // Update the item pointer to just after the last item read
630 item = (source_expand_details *) &(item->info.details[n_rates]);
631 }
632
633 items->rate_changed = false;
634 return true;
635}
636
641 // Get the system region
642 void *recording_region = data_specification_get_region(
643 SPIKE_HISTORY_REGION, ds_regions);
644
645 bool success = recording_initialize(&recording_region, &recording_flags);
646 log_info("Recording flags = 0x%08x", recording_flags);
647
648 return success;
649}
650
653static inline void expand_spike_recording_buffer(uint32_t n_spikes) {
654 uint32_t new_size = 8 + (n_spikes * spike_buffer_size);
655 timed_out_spikes *new_spikes = spin1_malloc(new_size);
656 if (new_spikes == NULL) {
657 log_error("Cannot reallocate spike buffer");
659 }
660
661 // bzero the new buffer
662 uint32_t *data = (uint32_t *) new_spikes;
663 for (uint32_t n = new_size >> 2; n > 0; n--) {
664 data[n - 1] = 0;
665 }
666
667 // Copy over old buffer if we have it
668 if (spikes != NULL) {
669 spin1_memcpy(new_spikes, spikes,
672 }
673
674 spikes = new_spikes;
676}
677
682static bool initialize(void) {
683 log_info("Initialise: started");
684
685 // Get the address this core's DTCM data starts at from SRAM
688
689 // Read the header
690 if (!data_specification_read_header(ds_regions)) {
691 return false;
692 }
693
694 // Get the timing details and set up the simulation interface
696 data_specification_get_region(SYSTEM, ds_regions),
697 APPLICATION_NAME_HASH, &timer_period, &simulation_ticks,
698 &infinite_run, &time, SDP, DMA)) {
699 return false;
700 }
701
704 data_specification_get_region(PROVENANCE_REGION, ds_regions));
705
706 // setup recording region
707 if (!initialise_recording(ds_regions)) {
708 return false;
709 }
710
711 // Setup regions that specify spike source array data
713 data_specification_get_region(POISSON_PARAMS, ds_regions))) {
714 return false;
715 }
716
717 void *rates_region = data_specification_get_region(RATES, ds_regions);
718 bool rates_changed = expand_rates(
719 data_specification_get_region(EXPANDER_REGION, ds_regions),
720 rates_region);
721 if (!read_rates(rates_region, rates_changed, 0)) {
722 return false;
723 }
724
725 // print spike sources for debug purposes
726#if LOG_LEVEL >= LOG_DEBUG
728#endif
729
730 // Set up recording buffer
732 n_spike_buffer_words = get_bit_field_size(ssp_params.n_spike_sources);
733 spike_buffer_size = n_spike_buffer_words * sizeof(uint32_t);
735
736 // Setup profiler
738 data_specification_get_region(PROFILER_REGION, ds_regions));
739
740 // Setup SDRAM transfer
741 struct sdram_config *sdram_conf = data_specification_get_region(
742 SDRAM_PARAMS_REGION, ds_regions);
743 uint32_t sdram_inputs_size = sizeof(struct sdram_config) + (
744 ssp_params.n_spike_sources * sizeof(uint16_t));
745 sdram_inputs = spin1_malloc(sdram_inputs_size);
746 if (sdram_inputs == NULL) {
747 log_error("Could not allocate %d bytes for SDRAM inputs",
748 sdram_inputs_size);
749 return false;
750 }
751 spin1_memcpy(sdram_inputs, sdram_conf, sdram_inputs_size);
752 log_info("Writing output to address 0x%08x, size in total %d,"
753 "offset in half-words %d, size to write %d", sdram_inputs->address,
755 ssp_params.n_spike_sources * sizeof(uint16_t));
756 if (sdram_inputs->size_in_bytes != 0) {
758 if (input_this_timestep == NULL) {
759 log_error("Could not allocate %d bytes for input this timestep",
761 return false;
762 }
764 for (uint32_t i = 0; i < ssp_params.n_spike_sources; i++) {
765 log_debug("weight[%u] = %u", i, sdram_inputs->weights[i]);
766 }
767 }
768
769 // Allocate buffer to allow rate change (2 ints) per source
772 if (rate_change_buffer == NULL) {
773 log_error("Could not allocate rate change buffer!");
774 return false;
775 }
776
777 log_info("Initialise: completed successfully");
778
779 return true;
780}
781
783static void resume_callback(void) {
785
788
789 // If we are resetting, re-read the seed
790 bool rates_changed = false;
791 if (time == UINT32_MAX) {
792 if (!read_global_parameters(data_specification_get_region(
793 POISSON_PARAMS, ds_regions))) {
794 log_error("failed to reread the Poisson params");
796 }
797 rates_changed = true;
798 }
799
800 void *rates_region = data_specification_get_region(RATES, ds_regions);
801 bool expand_rates_changed = expand_rates(
802 data_specification_get_region(EXPANDER_REGION, ds_regions),
803 rates_region);
804 rates_changed = rates_changed || expand_rates_changed;
805
806 if (!read_rates(rates_region, rates_changed, time + 1)) {
807 log_error("failed to reread the Poisson rates from SDRAM");
809 }
810
811 log_info("Successfully resumed Poisson spike source at time: %u", time);
812
813 // print spike sources for debug purposes
814#if LOG_LEVEL >= LOG_DEBUG
816#endif
817}
818
822static inline void mark_spike(uint32_t neuron_id, uint32_t n_spikes) {
823 if (recording_flags > 0) {
826 }
827 if (spikes->n_buffers < n_spikes) {
829 }
830 for (uint32_t n = n_spikes; n > 0; n--) {
831 bit_field_set(out_spikes_bitfield(n - 1), neuron_id);
832 }
833 }
834}
835
838static inline void record_spikes(uint32_t time) {
839 if ((spikes != NULL) && (spikes->n_buffers > 0)) {
840 spikes->time = time;
842 reset_spikes();
843 }
844}
845
850 if ((time >= source->start_ticks) && (time < source->end_ticks)) {
851 // Get number of spikes to send this tick
852 uint32_t num_spikes = 0;
853
854 // If sqrt_lambda has been set then use the Gaussian algorithm for
855 // faster sources
857 profiler_write_entry_disable_irq_fiq(
858 PROFILER_ENTER | PROFILER_PROB_FUNC);
861 profiler_write_entry_disable_irq_fiq(
862 PROFILER_EXIT | PROFILER_PROB_FUNC);
863 } else {
864 // Call the fast source Poisson algorithm
865 profiler_write_entry_disable_irq_fiq(
866 PROFILER_ENTER | PROFILER_PROB_FUNC);
869 profiler_write_entry_disable_irq_fiq(
870 PROFILER_EXIT | PROFILER_PROB_FUNC);
871 }
872
873 log_debug("Generating %d spikes", num_spikes);
874
875 // If there are any
876 if (num_spikes > 0) {
877 // Write spike to out spikes
878 mark_spike(s_id, num_spikes);
879
880 // If no key has been given, do not send spikes to fabric
881 if (ssp_params.has_key) {
882 // Send spikes
883 const uint32_t spike_key = keys[s_id] | colour;
884 send_spike_mc_payload(spike_key, num_spikes);
885 } else if (sdram_inputs->address != 0) {
887 sdram_inputs->weights[s_id] * num_spikes;
888 }
889 }
890 }
891}
892
897 if ((time >= source->start_ticks) && (time < source->end_ticks)
898 && (source->mean_isi_ticks != 0)) {
899 uint32_t count = 0;
900 // Mark a spike while the "timer" is below the scale factor value
902 count++;
903
904 // Update time to spike (note, this might not get us back above
905 // the scale factor, particularly if the mean_isi is smaller)
906 profiler_write_entry_disable_irq_fiq(
907 PROFILER_ENTER | PROFILER_PROB_FUNC);
910 profiler_write_entry_disable_irq_fiq(
911 PROFILER_EXIT | PROFILER_PROB_FUNC);
912 }
913 if (count) {
914 // Write spike to out_spikes
915 mark_spike(s_id, count);
916
917 // if no key has been given, do not send spike to fabric.
918 if (ssp_params.has_key) {
919 // Send package
920 const uint32_t spike_key = keys[s_id] | colour;
921 send_spike_mc_payload(spike_key, count);
922 } else if (sdram_inputs->address != 0) {
924 sdram_inputs->weights[s_id] * count;
925 }
926 }
927
928 // Now we have finished for this tick, subtract the scale factor
930 }
931}
932
939static void timer_callback(UNUSED uint timer_count, UNUSED uint unused) {
940 profiler_write_entry_disable_irq_fiq(PROFILER_ENTER | PROFILER_TIMER);
941
942 time++;
943
944 log_debug("Timer tick %u", time);
945
946 // If a fixed number of simulation ticks are specified and these have passed
948 // go into pause and resume state to avoid another tick
950
951 profiler_write_entry_disable_irq_fiq(PROFILER_EXIT | PROFILER_TIMER);
952
953 // Finalise any recordings that are in progress, writing back the final
954 // amounts of samples recorded to SDRAM
955 if (recording_flags > 0) {
957 }
958
960
961 // Subtract 1 from the time so this tick gets done again on the next
962 // run
963 time--;
965 return;
966 }
967
968 // Set the colour for the time step
970
971 // Do any rate changes
972 while (circular_buffer_size(rate_change_buffer) >= 2) {
973 uint32_t id = 0;
974 REAL rate = 0.0k;
975 circular_buffer_get_next(rate_change_buffer, &id);
976 circular_buffer_get_next(rate_change_buffer, (uint32_t *) &rate);
977 set_spike_source_rate(id, rate);
978 }
979
980 // Reset the inputs this timestep if using them
981 if (sdram_inputs->address != 0) {
983 }
984
985 // Loop through spike sources and see if they need updating
986 // NOTE: This full loop needs to happen first with processing in a second
987 // separate loop. This is to ensure that the random generator use matches
988 // between a single run and a split run (as slow sources can produce
989 // multiple spikes in a single time step).
990 for (index_t s_id = 0; s_id < ssp_params.n_spike_sources; s_id++) {
991 spike_source_t *spike_source = &source[s_id];
992
993 // Move to the next tick now if needed
994 if (time >= spike_source->next_ticks) {
995 log_debug("Moving to next rate at time %d", time);
996 read_next_rates(s_id);
997#if LOG_LEVEL >= LOG_DEBUG
998 print_spike_source(s_id);
999#endif
1000 }
1001 }
1002
1003 // Loop through the sources and process them
1004 for (index_t s_id = 0; s_id < ssp_params.n_spike_sources; s_id++) {
1005 spike_source_t *spike_source = &source[s_id];
1006 if (spike_source->is_fast_source) {
1007 process_fast_source(s_id, spike_source);
1008 } else {
1009 process_slow_source(s_id, spike_source);
1010 }
1011 }
1012
1013 profiler_write_entry_disable_irq_fiq(PROFILER_EXIT | PROFILER_TIMER);
1014
1015 // If transferring over SDRAM, transfer now
1016 if (sdram_inputs->address != 0) {
1019 }
1020
1021 // Record output spikes if required
1022 if (recording_flags > 0) {
1024 }
1025}
1026
1031 uint32_t id = key & ssp_params.set_rate_neuron_id_mask;
1032 if ((id < ssp_params.first_source_id) ||
1034 return;
1035 }
1036 // The above condition prevents this from being negative
1037 uint32_t sub_id = (uint32_t) id - ssp_params.first_source_id;
1038 circular_buffer_add(rate_change_buffer, sub_id);
1039 circular_buffer_add(rate_change_buffer, payload);
1040}
1041
1043void c_main(void) {
1044 // Load DTCM data
1045 time = 0;
1046 if (!initialize()) {
1047 log_error("Error in initialisation - exiting!");
1049 }
1050
1051 // Start the time at "-1" so that the first tick will be 0
1052 time = UINT32_MAX;
1053
1054 // Set timer tick (in microseconds)
1055 spin1_set_timer_tick(timer_period);
1056
1057 // Register callback
1061
1063}
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:102
#define EXP(x)
This calculates the exponential (to base e) of the argument.
Definition maths-util.h:133
unsigned accum UREAL
Type used for "unsigned real" numbers.
Definition maths-util.h:92
#define REAL_COMPARE(x, op, y)
Compare two REAL numbers.
Definition maths-util.h:180
#define HALF
A REAL 0.5.
Definition maths-util.h:119
accum REAL
Type used for "real" numbers.
Definition maths-util.h:89
#define UFRACT_CONST(x)
Define a constant of type UFRACT.
Definition maths-util.h:114
unsigned long fract UFRACT
Type used for "unsigned fractional" numbers.
Definition maths-util.h:98
#define ZERO
A REAL 0.0.
Definition maths-util.h:121
#define SQRT(x)
This calculates the square-root of the argument.
Definition maths-util.h:128
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.
REAL sqrt_lambda
sqrt(λ)
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 times_tdma_fell_behind
number of times the tdma fell behind its slot
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
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.
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.
void set_spike_source_rate(uint32_t sub_id, unsigned long accum rate)
Set the spike source rate as required.
static uint32_t n_spikes_poisson_fast(UFRACT exp_minus_lambda)
How many spikes to generate for a fast Poisson source.
REAL slow_rate_per_tick_cutoff
The border rate between slow and fast sources.
static spike_source_t * source
The currently applied rate descriptors.
uint32_t time_to_spike_ticks
Planned time to spike, in ticks.
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 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.
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.
REAL fast_rate_per_tick_cutoff
The border rate between fast and faster sources.
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