sPyNNaker neural_modelling  7.4.2
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 
50 typedef struct spike_source_t {
52  uint32_t start_ticks;
54  uint32_t end_ticks;
56  uint32_t next_ticks;
58  uint32_t is_fast_source;
59 
65  uint32_t mean_isi_ticks;
69 
71 typedef struct timed_out_spikes {
73  uint32_t time;
75  uint32_t n_buffers;
77  uint32_t out_spikes[];
79 
81 typedef enum region {
91 
93 #define NUMBER_OF_REGIONS_TO_RECORD 1
95 #define BYTE_TO_WORD_CONVERTER 4
97 #define ISI_SCALE_FACTOR 1000
98 
100 typedef enum ssp_callback_priorities {
102  MULTICAST = -1,
104  SDP = 0,
106  DMA = 1,
108  TIMER = 2
110 
112 typedef struct {
113  uint32_t x;
114  uint32_t y;
115  uint32_t z;
116  uint32_t c;
117 } rng_seed_t;
118 
120 typedef struct global_parameters {
122  uint32_t has_key;
134  uint32_t first_source_id;
136  uint32_t n_spike_sources;
140  uint32_t n_colour_bits;
144 
147 
149  uint32_t n_saturations;
150 };
151 
152 __attribute__((aligned(4)))
153 typedef struct source_details {
154  unsigned long accum rate;
155  unsigned long accum start;
156  unsigned long accum duration;
157 } source_details;
158 
160 static uint32_t *keys;
161 
163 typedef struct source_info {
165  uint32_t n_rates;
167  uint32_t index;
169  source_details details[];
170 } source_info;
171 
172 typedef struct source_expand_details {
174  uint32_t count;
178 
179 typedef 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 
190 struct 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 
213 static uint32_t recording_flags = 0;
214 
217 static uint32_t time;
218 
220 static uint32_t simulation_ticks = 0;
221 
223 static uint32_t infinite_run;
224 
226 static timed_out_spikes *spikes = NULL;
227 
230 
232 static uint32_t n_spike_buffer_words;
233 
235 static uint32_t spike_buffer_size;
236 
238 static uint32_t timer_period;
239 
241 static struct sdram_config *sdram_inputs;
242 
244 static uint16_t *input_this_timestep;
245 
248 
250 static circular_buffer rate_change_buffer;
251 
253 static uint32_t colour;
254 
256 static uint32_t colour_mask;
257 
260 static uint32_t n_saturations = 0;
261 
265 static inline uint32_t rng(void) {
266  ssp_params.spike_source_seed.x = 314527869 * ssp_params.spike_source_seed.x + 1234567;
270  uint64_t t = 4294584393ULL * ssp_params.spike_source_seed.z + ssp_params.spike_source_seed.c;
271  ssp_params.spike_source_seed.c = t >> 32;
273 
274  return (uint32_t) ssp_params.spike_source_seed.x
276 }
277 
281 static 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 
296 static 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 
323 static inline uint32_t slow_spike_source_get_time_to_spike(
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 
339 static 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 
355 static inline uint32_t faster_spike_source_get_num_spikes(
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 
368 void 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 
411 static 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 
420 static inline uint32_t ms_to_ticks(unsigned long accum ms) {
421  return (uint32_t) ((ms * ssp_params.ticks_per_ms) + 0.5k);
422 }
423 
424 static 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 
456 static inline bit_field_t out_spikes_bitfield(uint32_t n) {
457  return &spikes->out_spikes[n * n_spike_buffer_words];
458 }
459 
461 static 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
472 static void print_spike_source(index_t s) {
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 
486 static void print_spike_sources(void) {
487  for (index_t s = 0; s < ssp_params.n_spike_sources; s++) {
489  }
490 }
491 #endif
492 
497 static 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 
510  colour_mask = (1 << ssp_params.n_colour_bits) - 1;
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 
540 static 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 
552 static 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 
600 static 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 
649 static bool initialise_recording(data_specification_metadata_t *ds_regions) {
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 
662 static 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");
667  rt_error(RTE_SWERR);
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,
680  sark_free(spikes);
681  }
682 
683  spikes = new_spikes;
685 }
686 
691 static bool initialize(void) {
692  log_info("Initialise: started");
693 
694  // Get the address this core's DTCM data starts at from SRAM
695  data_specification_metadata_t *ds_regions =
696  data_specification_get_data_address();
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
704  if (!simulation_initialise(
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 
711  simulation_set_provenance_function(
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
746  profiler_init(
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  }
772  sark_word_set(input_this_timestep, 0, sdram_inputs->size_in_bytes);
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
779  rate_change_buffer = circular_buffer_initialize(
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 
792 static void resume_callback(void) {
793  recording_reset();
794 
795  data_specification_metadata_t *ds_regions =
796  data_specification_get_data_address();
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");
804  rt_error(RTE_SWERR);
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");
817  rt_error(RTE_SWERR);
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 
831 static 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 
847 static inline void record_spikes(uint32_t time) {
848  if ((spikes != NULL) && (spikes->n_buffers > 0)) {
849  spikes->time = time;
850  recording_record(0, spikes, 8 + (spikes->n_buffers * spike_buffer_size));
851  reset_spikes();
852  }
853 }
854 
855 static 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;
861  n_saturations++;
862  }
863  input_this_timestep[sdram_inputs->offset + s_id] = (uint16_t) accumulation;
864 }
865 
869 static void process_fast_source(index_t s_id, spike_source_t *source) {
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
876  if (REAL_COMPARE(source->sqrt_lambda, >, ZERO)) {
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 
915 static void process_slow_source(index_t s_id, spike_source_t *source) {
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 
957 static 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
965  if (simulation_is_finished()) {
966  // go into pause and resume state to avoid another tick
967  simulation_handle_pause_resume(resume_callback);
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) {
974  recording_finalise();
975  }
976 
977  profiler_finalise();
978 
979  // Subtract 1 from the time so this tick gets done again on the next
980  // run
981  time--;
982  simulation_ready_to_read();
983  return;
984  }
985 
986  // Set the colour for the time step
987  colour = time & colour_mask;
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) {
1000  sark_word_set(input_this_timestep, 0, sdram_inputs->size_in_bytes);
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) {
1035  spin1_dma_transfer(0, sdram_inputs->address, input_this_timestep,
1036  DMA_WRITE, sdram_inputs->size_in_bytes);
1037  }
1038 
1039  // Record output spikes if required
1040  if (recording_flags > 0) {
1042  }
1043 }
1044 
1048 static void multicast_packet_callback(uint key, uint payload) {
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 
1061 void c_main(void) {
1062  // Load DTCM data
1063  time = 0;
1064  if (!initialize()) {
1065  log_error("Error in initialisation - exiting!");
1066  rt_error(RTE_SWERR);
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
1076  spin1_callback_on(TIMER_TICK, timer_callback, TIMER);
1077  spin1_callback_on(
1078  MCPL_PACKET_RECEIVED, multicast_packet_callback, MULTICAST);
1079 
1080  simulation_run();
1081 }
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
Definition: profile_tags.h:23
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