SpiNNFrontEndCommon 7.1.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
333 // Subtract 1 from the time so this tick gets done again on the next
334 // run
335 time--;
336
338 }
339}
340
345static inline void flush_events_if_full(void) {
347 flush_events();
348 }
349}
350
353static void process_incoming_event(uint key) {
354 log_debug("Processing key %x", key);
355
356 // process the received spike
357 if (!HAVE_WIDE_LOAD(config->packet_type)) {
358 // 16 bit packet
360 key >> config->key_right_shift);
361
362 // if there is a payload to be added
363 if (HAVE_PAYLOAD(config->packet_type) && !config->payload_timestamp) {
365 } else if (HAVE_PAYLOAD(config->packet_type) && config->payload_timestamp) {
367 }
368 } else {
369 // 32 bit packet
371
372 // if there is a payload to be added
373 if (HAVE_PAYLOAD(config->packet_type) && !config->payload_timestamp) {
375 } else if (HAVE_PAYLOAD(config->packet_type) && config->payload_timestamp) {
377 }
378 }
380}
381
385static void process_incoming_event_payload(uint key, uint payload) {
386 log_debug("Processing key %x, payload %x", key, payload);
387
388 // process the received spike
389 if (!HAVE_WIDE_LOAD(config->packet_type)) {
390 //16 bit packet
392 key >> config->key_right_shift);
393
394 //if there is a payload to be added
395 if (HAVE_PAYLOAD(config->packet_type) && !config->payload_timestamp) {
397 payload >> config->payload_right_shift);
398 } else if (HAVE_PAYLOAD(config->packet_type) && config->payload_timestamp) {
400 }
401 } else {
402 //32 bit packet
404
405 //if there is a payload to be added
406 if (HAVE_PAYLOAD(config->packet_type) && !config->payload_timestamp) {
408 } else if (HAVE_PAYLOAD(config->packet_type) && config->payload_timestamp) {
410 }
411 }
413}
414
432 do {
433 uint32_t key, payload;
434
435 if (circular_buffer_get_next(without_payload_buffer, &key)) {
436 key = translated_key(key);
438 } else if (circular_buffer_get_next(with_payload_buffer, &key)
439 && circular_buffer_get_next(with_payload_buffer, &payload)) {
440 key = translated_key(key);
441 process_incoming_event_payload(key, payload);
442 } else {
443 processing_events = false;
444 break;
445 }
446
447 // send packet if enough data is stored
449 } while (processing_events);
450}
451
460 log_debug("Received key %x", key);
461
462 if (circular_buffer_add(without_payload_buffer, key)) {
463 if (!processing_events) {
464 processing_events = true;
466 }
467 } else {
469 }
470}
471
479static void incoming_event_payload_callback(uint key, uint payload) {
480 log_debug("Received key %x, payload %x", key, payload);
481
482 if (circular_buffer_add(with_payload_buffer, key)) {
483 circular_buffer_add(with_payload_buffer, payload);
484 if (!processing_events) {
485 processing_events = true;
487 }
488 } else {
490 }
491}
492
499 uint32_t n_bytes = sizeof(struct lpg_config) +
501 config = spin1_malloc(n_bytes);
502 if (config == NULL) {
503 log_error("Could not allocate space for config!");
504 return false;
505
506 }
508
509 log_info("apply_prefix: %d", config->apply_prefix);
510 log_info("prefix: %08x", config->prefix);
511 log_info("prefix_type: %d", config->prefix_type);
512 log_info("packet_type: %d", config->packet_type);
513 log_info("key_right_shift: %d", config->key_right_shift);
514 log_info("payload_timestamp: %d", config->payload_timestamp);
515 log_info("payload_apply_prefix: %d", config->payload_apply_prefix);
516 log_info("payload_prefix: %08x", config->payload_prefix);
517 log_info("payload_right_shift: %d", config->payload_right_shift);
518 log_info("sdp_tag: %d", config->sdp_tag);
519 log_info("sdp_dest: 0x%04x", config->sdp_dest);
520 log_info("packets_per_timestamp: %d", config->packets_per_timestamp);
521 log_info("n_translation_entries: %d", config->n_translation_entries);
522 for (uint32_t i = 0; i < config->n_translation_entries; i++) {
523 key_translation_entry *entry = &config->translation_table[i];
524 log_info("key = 0x%08x, mask = 0x%08x, lo_atom = 0x%08x",
525 entry->key, entry->mask, entry->lo_atom);
526 }
527
528 return true;
529}
530
535static bool initialize(uint32_t *timer_period) {
536 // Get the address this core's DTCM data starts at from SRAM
539
540 // Read the header
542 return false;
543 }
544
545 // Get the timing details and set up the simulation interface
549 &infinite_run, &time, SDP, DMA)) {
550 return false;
551 }
555
556 // Fix simulation ticks to be one extra timer period to soak up last events
557 if (infinite_run != TRUE) {
559 }
560
561 // Read the parameters
562 return read_parameters(
563 data_specification_get_region(CONFIGURATION_REGION, ds_regions));
564}
565
568static bool configure_sdp_msg(void) {
569 log_debug("configure_sdp_msg");
570
571 switch (config->packet_type) {
572 case NO_PAYLOAD_16:
573 event_size = 2;
574 break;
575 case PAYLOAD_16:
576 event_size = 4;
577 break;
578 case NO_PAYLOAD_32:
579 event_size = 4;
580 break;
581 case PAYLOAD_32:
582 event_size = 8;
583 break;
584 default:
585 log_error("unknown packet type: %d", config->packet_type);
586 return false;
587 }
588
589 // initialise SDP header
590 g_event_message.tag = config->sdp_tag;
591 // No reply required
592 g_event_message.flags = 0x07;
593 // Chip 0,0
594 g_event_message.dest_addr = config->sdp_dest;
595 // Dump through Ethernet
597 // Set up monitoring address and port
600
601 // check incompatible options
602 if (config->payload_timestamp && config->payload_apply_prefix
603 && HAVE_PAYLOAD(config->packet_type)) {
604 log_error("Timestamp can either be included as payload prefix or as"
605 "payload to each key, not both");
606 return false;
607 }
608 if (config->payload_timestamp && !config->payload_apply_prefix
609 && !HAVE_PAYLOAD(config->packet_type)) {
610 log_error("Timestamp can either be included as payload prefix or as"
611 "payload to each key, but current configuration does not"
612 "specify either of these");
613 return false;
614 }
615
616 // initialise AER header
617 // pointer to data space
619
623 eieio_constant_header |= config->payload_apply_prefix << APPLY_PAYLOAD_PREFIX;
624 eieio_constant_header |= config->payload_timestamp << PAYLOAD_IS_TIMESTAMP;
625 eieio_constant_header |= config->packet_type << PACKET_TYPE;
626
627 // pointers for AER packet header, prefix and data
628 // Point to the half-word after main header half-word
630 if (config->apply_prefix) {
631 // pointer to key prefix, so data is one half-word further ahead
634 }
635
636 if (config->payload_apply_prefix) {
637 // pointer to payload prefix
639
640 if (!HAVE_WIDE_LOAD(config->packet_type)) {
641 //16 bit payload prefix; advance data position by one half word
643 if (!config->payload_timestamp) {
644 // add payload prefix as required - not a timestamp
645 write_short(sdp_msg_aer_payload_prefix, 0, config->payload_prefix);
646 }
647 } else {
648 //32 bit payload prefix; advance data position by two half words
649 sdp_msg_aer_data += 2;
650 if (!config->payload_timestamp) {
651 // add payload prefix as required - not a timestamp
652 write_word(sdp_msg_aer_payload_prefix, 0, config->payload_prefix);
653 }
654 }
655 }
656
657 // compute header length in bytes
660
661 log_debug("sdp_msg_aer_header: %08x", sdp_msg_aer_header);
662 log_debug("sdp_msg_aer_payload_prefix: %08x", sdp_msg_aer_payload_prefix);
663 log_debug("sdp_msg_aer_data: %08x", sdp_msg_aer_data);
664 log_debug("sdp_msg_aer_header_len: %d", sdp_msg_aer_header_len);
665
666 packets_sent = 0;
667 buffer_index = 0;
668
669 return true;
670}
671
673void c_main(void) {
674 // Configure system
675 uint32_t timer_period = 0;
676 if (!initialize(&timer_period)) {
677 log_error("Error in initialisation - exiting!");
679 }
680
681 // Configure SDP message
682 if (!configure_sdp_msg()) {
684 }
685
686 // Set up circular buffers for multicast message reception
689
690 // Set timer_callback
691 spin1_set_timer_tick(timer_period);
692
693 // Register callbacks
699
700 // Start the time at "-1" so that the first tick will be 0
703}
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:110
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:391
bool simulation_is_finished(void)
determine if the simulation is finished. Will also pause the simulation for resynchronisation if requ...
Definition simulation.c:417
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:128
void simulation_run(void)
Starts the simulation running, returning when it is complete,.
Definition simulation.c:105
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:343
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