SpiNNFrontEndCommon 7.3.1
Common support code for user-facing front end systems.
Loading...
Searching...
No Matches
live_packet_gather.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015 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
25
26#include <common-typedefs.h>
27#include <circular_buffer.h>
28#include <data_specification.h>
29#include <debug.h>
30#include <simulation.h>
31#include <spin1_api.h>
32#include <eieio.h>
33
45
46typedef struct key_translation_entry {
47 // The key to check against after masking
48 uint32_t key;
49 // The mask to apply to the key
50 uint32_t mask;
51 // The atom identifier to add to the computed index
52 uint32_t lo_atom;
54
92
94enum {
95 MC_PACKET = -1,
96 SDP = 0,
97 USER = 1,
98 DMA = 2,
99 TIMER = 3
101
103enum {
105 CONFIGURATION_REGION,
107};
108
111 NO_PAYLOAD_16,
112 PAYLOAD_16,
113 NO_PAYLOAD_32,
114 PAYLOAD_32
115};
116
117// Globals
120
122static uint16_t *sdp_msg_aer_header;
123
126
128static uint16_t *sdp_msg_aer_data;
129
131static uint32_t time;
132
134static uint32_t packets_sent;
135
137static uint32_t buffer_index;
138
140static uint16_t eieio_constant_header;
141
143static uint8_t event_size;
144
147
149static uint32_t simulation_ticks = 0;
150
153static uint32_t infinite_run = FALSE;
154
157
160
162static bool processing_events = false;
163
166
168static struct lpg_config *config;
169
171#define FLAG_IS_SET(flags, bit) (((flags) & (bit)) != 0)
172
174#define CLAMP8(value) ((value) & 0xFF)
175
177#define CLAMP16(value) ((value) & 0xFFFF)
178
180#define HAVE_PAYLOAD(pkt_type) FLAG_IS_SET(pkt_type, 0x1)
181
183#define HAVE_WIDE_LOAD(pkt_type) FLAG_IS_SET(pkt_type, 0x2)
184
186#define BUFFER_CAPACITY 256
187
189static inline bool find_translation_entry(uint32_t key, uint32_t *index) {
190 if (!config->n_translation_entries) {
191 return false;
192 }
193
194 uint32_t imin = 0;
195 uint32_t imax = config->n_translation_entries;
196
197 while (imin < imax) {
198 uint32_t imid = (imax + imin) >> 1;
199 key_translation_entry entry = config->translation_table[imid];
200 if ((key & entry.mask) == entry.key) {
201 *index = imid;
202 return true;
203 } else if (entry.key < key) {
204
205 // Entry must be in upper part of the table
206 imin = imid + 1;
207 } else {
208 // Entry must be in lower part of the table
209 imax = imid;
210 }
211 }
212 return false;
213}
214
215static inline uint32_t translated_key(uint32_t key) {
216 uint32_t index = 0;
217
218 // If there isn't an entry, don't translate
219 if (!find_translation_entry(key, &index)) {
220 return key & config->received_key_mask;
221 }
222
223 key_translation_entry entry = config->translation_table[index];
224
225 // Pre-shift the key as requested
226 uint32_t shifted_key = key & ~entry.mask;
227 if (config->translated_key_right_shift) {
228 shifted_key = shifted_key >> config->translated_key_right_shift;
229 }
230 return shifted_key + entry.lo_atom;
231}
232
239static inline void write_word(void *base, uint32_t index, uint32_t value) {
240 uint16_t *ary = base;
241 uint32_t idx = index * 2;
242 ary[idx++] = CLAMP16(value);
243 ary[idx] = CLAMP16(value >> 16);
244}
245
250static inline void write_short(void *base, uint32_t index, uint32_t value) {
251 uint16_t *ary = base;
252 ary[index] = CLAMP16(value);
253}
254
257static inline uint8_t get_event_count(void) {
258 uint8_t event_count = buffer_index;
259 // If there are payloads, it takes two buffer values to encode them
260 if (HAVE_PAYLOAD(config->packet_type)) {
261 event_count >>= 1;
262 }
263 return event_count;
264}
265
268static void flush_events(void) {
269 // Send the event message only if there is data
270 if ((buffer_index > 0) && (
271 (config->packets_per_timestamp == 0) ||
273 // Get the event count depending on if there is a payload or not
275
276 // insert appropriate header
278
282
283 // Add the timestamp if required
284 if (sdp_msg_aer_payload_prefix && config->payload_timestamp) {
285 if (!HAVE_WIDE_LOAD(config->packet_type)) {
287 } else {
289 }
290 }
291
292 spin1_send_sdp_msg(&g_event_message, 1);
293 packets_sent++;
295 }
296
297 // reset counter
298 buffer_index = 0;
299}
300
306 // Copy provenance data into SDRAM region
307 *sdram = provenance_data;
308}
309
310// Callbacks
319 // flush the spike message and sent it over the Ethernet
320 flush_events();
321
322 // increase time variable to keep track of current timestep
323 time++;
324 log_debug("Timer tick %u", time);
325
326 // Reset the count of packets sent in the current timestep
327 packets_sent = 0;
328
329 // check if the simulation has run to completion
332
334 }
335}
336
341static inline void flush_events_if_full(void) {
343 flush_events();
344 }
345}
346
349static void process_incoming_event(uint key) {
350 log_debug("Processing key %x", key);
351
352 // process the received spike
353 if (!HAVE_WIDE_LOAD(config->packet_type)) {
354 // 16 bit packet
356 key >> config->key_right_shift);
357
358 // if there is a payload to be added
359 if (HAVE_PAYLOAD(config->packet_type) && !config->payload_timestamp) {
361 } else if (HAVE_PAYLOAD(config->packet_type) && config->payload_timestamp) {
363 }
364 } else {
365 // 32 bit packet
367
368 // if there is a payload to be added
369 if (HAVE_PAYLOAD(config->packet_type) && !config->payload_timestamp) {
371 } else if (HAVE_PAYLOAD(config->packet_type) && config->payload_timestamp) {
373 }
374 }
376}
377
381static void process_incoming_event_payload(uint key, uint payload) {
382 log_debug("Processing key %x, payload %x", key, payload);
383
384 // process the received spike
385 if (!HAVE_WIDE_LOAD(config->packet_type)) {
386 //16 bit packet
388 key >> config->key_right_shift);
389
390 //if there is a payload to be added
391 if (HAVE_PAYLOAD(config->packet_type) && !config->payload_timestamp) {
393 payload >> config->payload_right_shift);
394 } else if (HAVE_PAYLOAD(config->packet_type) && config->payload_timestamp) {
396 }
397 } else {
398 //32 bit packet
400
401 //if there is a payload to be added
402 if (HAVE_PAYLOAD(config->packet_type) && !config->payload_timestamp) {
404 } else if (HAVE_PAYLOAD(config->packet_type) && config->payload_timestamp) {
406 }
407 }
409}
410
428 do {
429 uint32_t key, payload;
430
431 if (circular_buffer_get_next(without_payload_buffer, &key)) {
432 key = translated_key(key);
434 } else if (circular_buffer_get_next(with_payload_buffer, &key)
435 && circular_buffer_get_next(with_payload_buffer, &payload)) {
436 key = translated_key(key);
437 process_incoming_event_payload(key, payload);
438 } else {
439 processing_events = false;
440 break;
441 }
442
443 // send packet if enough data is stored
445 } while (processing_events);
446}
447
456 log_debug("Received key %x", key);
457
458 if (circular_buffer_add(without_payload_buffer, key)) {
459 if (!processing_events) {
460 processing_events = true;
462 }
463 } else {
465 }
466}
467
475static void incoming_event_payload_callback(uint key, uint payload) {
476 log_debug("Received key %x, payload %x", key, payload);
477
478 if (circular_buffer_add(with_payload_buffer, key)) {
479 circular_buffer_add(with_payload_buffer, payload);
480 if (!processing_events) {
481 processing_events = true;
483 }
484 } else {
486 }
487}
488
495 uint32_t n_bytes = sizeof(struct lpg_config) +
497 config = spin1_malloc(n_bytes);
498 if (config == NULL) {
499 log_error("Could not allocate space for config!");
500 return false;
501
502 }
504
505 log_info("apply_prefix: %d", config->apply_prefix);
506 log_info("prefix: %08x", config->prefix);
507 log_info("prefix_type: %d", config->prefix_type);
508 log_info("packet_type: %d", config->packet_type);
509 log_info("key_right_shift: %d", config->key_right_shift);
510 log_info("payload_timestamp: %d", config->payload_timestamp);
511 log_info("payload_apply_prefix: %d", config->payload_apply_prefix);
512 log_info("payload_prefix: %08x", config->payload_prefix);
513 log_info("payload_right_shift: %d", config->payload_right_shift);
514 log_info("sdp_tag: %d", config->sdp_tag);
515 log_info("sdp_dest: 0x%04x", config->sdp_dest);
516 log_info("packets_per_timestamp: %d", config->packets_per_timestamp);
517 log_info("n_translation_entries: %d", config->n_translation_entries);
518 for (uint32_t i = 0; i < config->n_translation_entries; i++) {
519 key_translation_entry *entry = &config->translation_table[i];
520 log_info("key = 0x%08x, mask = 0x%08x, lo_atom = 0x%08x",
521 entry->key, entry->mask, entry->lo_atom);
522 }
523
524 return true;
525}
526
531static bool initialize(uint32_t *timer_period) {
532 // Get the address this core's DTCM data starts at from SRAM
535
536 // Read the header
538 return false;
539 }
540
541 // Get the timing details and set up the simulation interface
545 &infinite_run, &time, SDP, DMA)) {
546 return false;
547 }
551
552 // Fix simulation ticks to be one extra timer period to soak up last events
553 if (infinite_run != TRUE) {
555 }
556
557 // Read the parameters
558 return read_parameters(
559 data_specification_get_region(CONFIGURATION_REGION, ds_regions));
560}
561
564static bool configure_sdp_msg(void) {
565 log_debug("configure_sdp_msg");
566
567 switch (config->packet_type) {
568 case NO_PAYLOAD_16:
569 event_size = 2;
570 break;
571 case PAYLOAD_16:
572 event_size = 4;
573 break;
574 case NO_PAYLOAD_32:
575 event_size = 4;
576 break;
577 case PAYLOAD_32:
578 event_size = 8;
579 break;
580 default:
581 log_error("unknown packet type: %d", config->packet_type);
582 return false;
583 }
584
585 // initialise SDP header
586 g_event_message.tag = config->sdp_tag;
587 // No reply required
588 g_event_message.flags = 0x07;
589 // Chip 0,0
590 g_event_message.dest_addr = config->sdp_dest;
591 // Dump through Ethernet
593 // Set up monitoring address and port
596
597 // check incompatible options
598 if (config->payload_timestamp && config->payload_apply_prefix
599 && HAVE_PAYLOAD(config->packet_type)) {
600 log_error("Timestamp can either be included as payload prefix or as"
601 "payload to each key, not both");
602 return false;
603 }
604 if (config->payload_timestamp && !config->payload_apply_prefix
605 && !HAVE_PAYLOAD(config->packet_type)) {
606 log_error("Timestamp can either be included as payload prefix or as"
607 "payload to each key, but current configuration does not"
608 "specify either of these");
609 return false;
610 }
611
612 // initialise AER header
613 // pointer to data space
615
619 eieio_constant_header |= config->payload_apply_prefix << APPLY_PAYLOAD_PREFIX;
620 eieio_constant_header |= config->payload_timestamp << PAYLOAD_IS_TIMESTAMP;
621 eieio_constant_header |= config->packet_type << PACKET_TYPE;
622
623 // pointers for AER packet header, prefix and data
624 // Point to the half-word after main header half-word
626 if (config->apply_prefix) {
627 // pointer to key prefix, so data is one half-word further ahead
630 }
631
632 if (config->payload_apply_prefix) {
633 // pointer to payload prefix
635
636 if (!HAVE_WIDE_LOAD(config->packet_type)) {
637 //16 bit payload prefix; advance data position by one half word
639 if (!config->payload_timestamp) {
640 // add payload prefix as required - not a timestamp
641 write_short(sdp_msg_aer_payload_prefix, 0, config->payload_prefix);
642 }
643 } else {
644 //32 bit payload prefix; advance data position by two half words
645 sdp_msg_aer_data += 2;
646 if (!config->payload_timestamp) {
647 // add payload prefix as required - not a timestamp
648 write_word(sdp_msg_aer_payload_prefix, 0, config->payload_prefix);
649 }
650 }
651 }
652
653 // compute header length in bytes
656
657 log_debug("sdp_msg_aer_header: %08x", sdp_msg_aer_header);
658 log_debug("sdp_msg_aer_payload_prefix: %08x", sdp_msg_aer_payload_prefix);
659 log_debug("sdp_msg_aer_data: %08x", sdp_msg_aer_data);
660 log_debug("sdp_msg_aer_header_len: %d", sdp_msg_aer_header_len);
661
662 packets_sent = 0;
663 buffer_index = 0;
664
665 return true;
666}
667
669void c_main(void) {
670 // Configure system
671 uint32_t timer_period = 0;
672 if (!initialize(&timer_period)) {
673 log_error("Error in initialisation - exiting!");
675 }
676
677 // Configure SDP message
678 if (!configure_sdp_msg()) {
680 }
681
682 // Set up circular buffers for multicast message reception
685
686 // Set timer_callback
687 spin1_set_timer_tick(timer_period);
688
689 // Register callbacks
695
696 // Start the time at "-1" so that the first tick will be 0
699}
static bool initialize(void)
Initialises the program.
circular_buffer circular_buffer_initialize(uint32_t size)
@ PROVENANCE_REGION
Where to record provenance data. (Format: cs_provenance_t)
@ SYSTEM_REGION
Where simulation system information is stored.
Data type definitions for SpiNNaker Neuron-modelling.
uint32_t * address_t
A generic pointer to a word.
Data Specification region access API.
data_specification_metadata_t * data_specification_get_data_address(void)
Gets the location of the data for this core using the user0 entry of the SARK VCPU structure.
bool data_specification_read_header(data_specification_metadata_t *ds_regions)
Reads the header from the address given and checks if the parameters are of the correct values.
static void * data_specification_get_region(uint32_t region, data_specification_metadata_t *ds_regions)
Gets the address of a region.
The central structure that the DSE writes.
SpiNNaker debug header file.
void log_error(const char *message,...)
This function logs errors. Errors usually indicate a serious fault in the program,...
void log_debug(const char *message,...)
This function logs debugging messages. This level of message is normally not printed except when the ...
void log_info(const char *message,...)
This function logs informational messages. This is the lowest level of message normally printed.
EIEIO message header description.
@ PAYLOAD_IS_TIMESTAMP
eieio_header_bitfields::payload_is_timestamp
Definition eieio.h:33
@ PACKET_TYPE
eieio_header_bitfields::packet_type
Definition eieio.h:34
@ APPLY_PAYLOAD_PREFIX
eieio_header_bitfields::apply_payload_prefix
Definition eieio.h:32
@ APPLY_PREFIX
eieio_header_bitfields::apply_prefix
Definition eieio.h:30
@ PREFIX_UPPER
eieio_header_bitfields::prefix_upper
Definition eieio.h:31
static sdp_msg_t g_event_message
The SDP message that we will send.
uint32_t sdp_dest
SDP destination to use when sending.
key_translation_entry translation_table[]
Translation table.
static uint32_t buffer_index
Index into our buffer in sdp_msg_aer_data.
uint32_t n_translation_entries
The number of entries in the translation table.
uint32_t payload_prefix
Payload prefix data (for the receiver)
uint32_t received_key_mask
Mask to apply to non-translated keys.
static uint32_t simulation_ticks
When we will run until.
#define HAVE_WIDE_LOAD(pkt_type)
Does the packet type include a double-width payload?
static uint16_t * sdp_msg_aer_data
Pointer to outbound message data. Might only be half-word aligned!
static uint8_t sdp_msg_aer_header_len
The length of the header, in bytes.
uint32_t payload_apply_prefix
D bit.
#define HAVE_PAYLOAD(pkt_type)
Does the packet type include a payload?
#define CLAMP16(value)
How to use just the low 16 bits of an integer value.
static lpg_provenance_data_t provenance_data
The provenance information that we are collecting.
#define BUFFER_CAPACITY
The size of the circular buffers.
uint32_t key_right_shift
Right payload shift (for the sender)
static bool configure_sdp_msg(void)
Sets up the AER EIEIO data message.
static circular_buffer without_payload_buffer
Circular buffer of incoming multicast packets that lack payloads.
static uint8_t get_event_count(void)
Get how many events there are waiting to be sent.
uint32_t translated_key_right_shift
Shift to apply to received and translated keys.
static void record_provenance_data(address_t provenance_region_address)
Store provenance data elements into SDRAM.
static uint16_t * sdp_msg_aer_payload_prefix
The location of the payload prefix in the message. NULL if no prefix.
static bool processing_events
Whether we are processing events (or discarding them).
packet_types
EIEIO packet types.
static uint16_t * sdp_msg_aer_header
The location of the EIEIO header in the message.
static bool read_parameters(struct lpg_config *sdram_config)
Copies the application configuration from DSG SDRAM to DTCM.
static void flush_events(void)
Send buffered events to host via SDP AER message and clear internal buffers.
static void process_incoming_event(uint key)
Processes an incoming multicast packet without payload.
static uint32_t infinite_run
TRUE if we're running without bound. FALSE if we're only running for a limited period of time.
void c_main(void)
Entry point.
static void timer_callback(uint unused0, uint unused1)
Periodic timer callback.
uint32_t payload_timestamp
T bit.
uint32_t sdp_tag
SDP tag to use when sending.
@ TIMER
Timer interrupt is lowest priority.
@ DMA
DMA complete interrupt is low priority.
@ SDP
SDP interrupt is highest priority.
@ MC_PACKET
Multicast packet interrupt uses FIQ (super high prio)
@ USER
Interrupt for enqueued list of received packets.
static void process_incoming_event_payload(uint key, uint payload)
Processes an incoming multicast packet with payload.
uint32_t payload_right_shift
Right payload shift (for the sender)
static circular_buffer with_payload_buffer
Circular buffer of incoming multicast packets that have payloads.
uint32_t number_of_overflows_no_payload
Count of overflows when no payload was sent.
static void write_short(void *base, uint32_t index, uint32_t value)
Simple mirror of write_word() for true 16 bit values.
static bool find_translation_entry(uint32_t key, uint32_t *index)
find a key translation entry
uint32_t number_of_sent_messages
Number of messages sent to host.
static struct lpg_config * config
The configuration data of the application.
static uint32_t packets_sent
The number of packets sent so far this timestamp.
static void incoming_event_payload_callback(uint key, uint payload)
FIQ handler for incoming packets with payload.
static void flush_events_if_full(void)
Flush events to the outside world if our internal buffers are now full.
uint32_t packet_type
F bit (for the receiver)
uint32_t prefix
Prefix data.
uint32_t number_of_gathered_events
Number of events gathered and recorded.
uint32_t packets_per_timestamp
Maximum number of packets to send per timestep, or 0 for "send them all".
static uint16_t eieio_constant_header
Part of the generic EIEIO header that is constant.
static void write_word(void *base, uint32_t index, uint32_t value)
Because WHY OH WHY would you use aligned memory? At least with this we don't get data aborts.
static uint32_t time
Current simulation time.
uint32_t number_of_overflows_with_payload
Count of overflows when a payload was sent.
static void incoming_event_process_callback(uint unused0, uint unused1)
Handler for processing incoming packets that have been locally queued.
static uint8_t event_size
The size of an individual event.
uint32_t apply_prefix
P bit.
uint32_t prefix_type
Type bits.
static void incoming_event_callback(uint key, uint unused)
FIQ handler for incoming packets without payload.
#define CLAMP8(value)
How to use just the low 8 bits of an integer value.
Definitions of each element in the configuration.
Provenance data store.
uint32_t prefix_type
The type of prefix that is supplied.
uint32_t prefix
The prefix to apply.
uint32_t apply_prefix
Whether to always apply a prefix.
uint32_t mask
The mask used for packet selection.
The configuration parameters for the application.
#define PORT_ETH
uchar dest_port
ushort cmd_rc
uchar srce_port
#define PORT_SHIFT
RTE_SWERR
ushort length
void rt_error(uint code,...)
ushort dest_addr
ushort srce_addr
uchar flags
Simulation Functions Header File.
void simulation_handle_pause_resume(resume_callback_t callback)
cleans up the house keeping, falls into a sync state and handles the resetting up of states as requir...
Definition simulation.c:113
void simulation_set_provenance_function(prov_callback_t provenance_function, address_t provenance_data_address)
Set an additional callback function to store extra provenance data.
Definition simulation.c:418
bool simulation_is_finished(void)
determine if the simulation is finished. Will also pause the simulation for resynchronisation if requ...
Definition simulation.c:444
void simulation_ready_to_read(void)
Indicates that all data has been written and the core is going idle, so any data can now be read.
Definition simulation.c:131
void simulation_run(void)
Starts the simulation running, returning when it is complete,.
Definition simulation.c:108
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)
initialises the simulation interface which involves:
Definition simulation.c:370
MCPL_PACKET_RECEIVED
MC_PACKET_RECEIVED
USER_EVENT
TIMER_TICK
#define NULL
uint spin1_trigger_user_event(uint arg0, uint arg1)
void spin1_memcpy(void *dst, void const *src, uint len)
#define TRUE
#define FALSE
uint spin1_get_chip_id(void)
uint spin1_get_core_id(void)
void spin1_callback_on(uint event_id, callback_t cback, int priority)
unsigned int uint