SpiNNFrontEndCommon  7.4.2
Common support code for user-facing front end systems.
data_speed_up_packet_gatherer.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 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 
25 // imports
26 #include <spin1_api.h>
27 #include <common-typedefs.h>
28 #include "common.h"
29 #include <data_specification.h>
30 #include <simulation.h>
31 #include <debug.h>
32 #include <bit_field.h>
33 
34 //-----------------------------------------------------------------------------
35 // MAGIC NUMBERS
36 //-----------------------------------------------------------------------------
37 
39 #define SDP_TIMEOUT 100
40 
43 #define MESSAGE_DELAY_TIME_WHEN_FAIL 1
44 
46 #define FIRST_SEQ_NUM 0
47 
49 #define MAX_CHIP_INDEX 8
50 
53  // received
60  // sent
65 };
66 
71 };
72 
74 #define SDRAM_VS_DTCM_THRESHOLD 40000
75 
77 enum {
80 
83 
86 
88  START_OF_DATA = 2
89 };
90 
92 #define ALL_MISSING_FLAG 0xFFFFFFFE
93 
95 #define ROUTER_TIMEOUT_MASK 0xFF
96 
98 enum {
107 };
108 
110 enum {
120 };
121 
122 //-----------------------------------------------------------------------------
123 // TYPES AND GLOBALS
124 //-----------------------------------------------------------------------------
125 
128  uint command;
131  ushort chip_y;
132  ushort chip_x;
133  uint max_seq_num;
135 
137 typedef struct receive_seq_data_msg_t {
138  uint command;
140  uint seq_num;
141  uint data[];
143 
145 typedef struct sdp_msg_out_payload_t {
147  uint command;
153 
155 static uint32_t new_sequence_key = 0;
156 
158 static uint32_t first_data_key = 0;
159 
161 static uint32_t transaction_id_key = 0;
162 
164 static uint32_t end_flag_key = 0;
165 
167 static uint32_t basic_data_key = 0;
168 
170 static uint32_t seq_num = FIRST_SEQ_NUM;
171 
173 static uint32_t max_seq_num = 0xFFFFFFFF;
174 
176 static uint32_t transaction_id = 0;
177 
179 static uint32_t data_out_transaction_id = 0;
180 
183 static uint32_t data[ITEMS_PER_DATA_PACKET];
184 
186 static uint32_t position_in_store = 0;
187 
190 
192 enum {
199 };
200 
202 typedef struct data_out_config_t {
204  const uint new_seq_key;
206  const uint first_data_key;
208  const uint transaction_id_key;
210  const uint end_flag_key;
212  const uint basic_data_key;
216  const uint tag_id;
218 
220 enum {
221  MC_PACKET = -1,
222  SDP = 0
223 };
224 
232 
234 static uint chip_x = 0xFFFFFFF; // Not a legal chip coordinate
235 
237 static uint chip_y = 0xFFFFFFF; // Not a legal chip coordinate
238 
240 static bit_field_t received_seq_nums_store = NULL;
241 
243 static uint size_of_bitfield = 0;
244 
248 static bool alloc_in_sdram = false;
249 
251 static uint total_received_seq_nums = 0;
252 
254 static uint last_seen_seq_num = 0;
255 
257 static uint start_sdram_address = 0;
258 
261 typedef enum {
268 } key_offsets;
269 
273  uint32_t x_coord;
274  uint32_t y_coord;
275  uint32_t base_key;
276 };
277 
279 typedef struct data_in_config_t {
281  const uint32_t n_extra_monitors;
283  const uint32_t reinjector_base_key;
288  const struct chip_key_data_t chip_to_key[];
290 
292 typedef struct dsupg_provenance_t {
294  uint32_t n_sdp_sent;
296  uint32_t n_sdp_recvd;
298  uint32_t n_in_streams;
300  uint32_t n_out_streams;
302 
305 
308 
309 //-----------------------------------------------------------------------------
310 // FUNCTIONS
311 //-----------------------------------------------------------------------------
312 
316 // Get pointer to 1st virtual processor info struct in SRAM
317  vcpu_t *virtual_processor_table = (vcpu_t*) SV_VCPU;
318 
319  // Get the address this core's DTCM data starts at from the user data
320  // member of the structure associated with this virtual processor
321  virtual_processor_table[spin1_get_core_id()].user1 = transaction_id;
322 }
323 
325 static inline void send_sdp_message(void) {
326  log_debug("sending message of length %u", my_msg.length);
327  while (!spin1_send_sdp_msg((sdp_msg_t *) &my_msg, SDP_TIMEOUT)) {
328  log_debug("failed to send SDP message");
329  spin1_delay_us(MESSAGE_DELAY_TIME_WHEN_FAIL);
330  }
331  prov.n_sdp_sent++;
333 }
334 
338 static inline void send_mc_message(key_offsets command, uint payload) {
339  uint key = data_in_mc_key_map[chip_x][chip_y] + command;
340  while (spin1_send_mc_packet(key, payload, WITH_PAYLOAD) == 0) {
341  spin1_delay_us(MESSAGE_DELAY_TIME_WHEN_FAIL);
342  }
343 }
344 
353 static inline void sanity_check_write(uint write_address, uint n_elements) {
354  // determine size of data to send
355  log_debug("Writing %u elements to 0x%08x", n_elements, write_address);
356 
357  uint end_ptr = write_address + n_elements * sizeof(uint);
358  if (write_address < SDRAM_BASE_BUF || end_ptr >= SDRAM_BASE_UNBUF ||
359  end_ptr < write_address) {
360  log_error("bad write range 0x%08x-0x%08x", write_address, end_ptr);
361  rt_error(RTE_SWERR);
362  }
363 }
364 
375  const uint *data, uint n_elements, bool set_write_address,
376  uint write_address) {
377  // send mc message with SDRAM location to correct chip
378  if (set_write_address) {
379  send_mc_message(WRITE_ADDR_KEY_OFFSET, write_address);
380  }
381 
382  // send mc messages containing rest of sdp data
383  for (uint data_index = 0; data_index < n_elements; data_index++) {
384  log_debug("data is %d", data[data_index]);
385  send_mc_message(DATA_KEY_OFFSET, data[data_index]);
386  }
387 }
388 
394 static void create_sequence_number_bitfield(uint max_seq) {
395  if (received_seq_nums_store != NULL) {
396  log_error("Allocating seq num store when already one exists at 0x%08x",
398  rt_error(RTE_SWERR);
399  }
400  size_of_bitfield = get_bit_field_size(max_seq + 1);
401  if (max_seq_num != max_seq) {
402  max_seq_num = max_seq;
403  alloc_in_sdram = false;
404  if (max_seq_num >= SDRAM_VS_DTCM_THRESHOLD || (NULL ==
405  (received_seq_nums_store = spin1_malloc(
406  size_of_bitfield * sizeof(uint32_t))))) {
407  received_seq_nums_store = sark_xalloc(
408  sv->sdram_heap, size_of_bitfield * sizeof(uint32_t), 0,
409  ALLOC_LOCK | ALLOC_ID | (sark_vec->app_id << 8));
410  if (received_seq_nums_store == NULL) {
411  log_error(
412  "Failed to allocate %u bytes for missing seq num store",
413  size_of_bitfield * sizeof(uint32_t));
414  rt_error(RTE_SWERR);
415  }
416  alloc_in_sdram = true;
417  }
418  }
419  log_debug("clearing bit field");
420  clear_bit_field(received_seq_nums_store, size_of_bitfield);
421 }
422 
424 static inline void free_sequence_number_bitfield(void) {
425  if (received_seq_nums_store == NULL) {
426  log_error("Freeing a non-existent seq num store");
427  rt_error(RTE_SWERR);
428  }
429  if (alloc_in_sdram) {
430  sark_xfree(sv->sdram_heap, received_seq_nums_store,
431  ALLOC_LOCK | ALLOC_ID | (sark_vec->app_id << 8));
432  } else {
433  sark_free(received_seq_nums_store);
434  }
436  max_seq_num = 0xFFFFFFFF;
437 }
438 
443  return (start_sdram_address
444  + (DATA_IN_NORMAL_PACKET_WORDS * seq_num * sizeof(uint)));
445 }
446 
449 static inline void set_message_length(const void *end) {
450  my_msg.length = ((const uint8_t *) end) - &my_msg.flags;
452  log_error("bad message length %u", my_msg.length);
453  }
454 }
455 
460  const receive_data_to_location_msg_t *receive_data_cmd) {
461  // if received when doing a stream. ignore as either clone or oddness
462  if (received_seq_nums_store != NULL) {
463  log_debug(
464  "received location message with transaction id %d when "
465  "already processing stream with transaction id %d",
466  receive_data_cmd->transaction_id, transaction_id);
467  return;
468  }
469 
470  // updater transaction id if it hits the cap
471  if (((transaction_id + 1) & TRANSACTION_CAP) == 0) {
472  transaction_id = 0;
474  }
475 
476  // if transaction id is not as expected. ignore it as its from the past.
477  // and worthless
478  if (receive_data_cmd->transaction_id != transaction_id + 1) {
479  log_debug(
480  "received location message with unexpected "
481  "transaction id %d; mine is %d",
482  receive_data_cmd->transaction_id, transaction_id + 1);
483  return;
484  }
485 
486  //extract transaction id and update
487  transaction_id = receive_data_cmd->transaction_id;
489 
490  // track changes
491  uint prev_x = chip_x, prev_y = chip_y;
492 
493  // update sdram and tracker as now have the sdram and size
494  chip_x = receive_data_cmd->chip_x;
495  chip_y = receive_data_cmd->chip_y;
496 
497  if (prev_x != chip_x || prev_y != chip_y) {
498  log_debug(
499  "Changed stream target chip to %d,%d for transaction id %d",
501  }
502 
503  log_debug("Writing %u packets to 0x%08x for transaction id %d",
504  receive_data_cmd->max_seq_num + 1, receive_data_cmd->address,
506 
507  // store where the sdram started, for out-of-order UDP packets.
508  start_sdram_address = (uint) receive_data_cmd->address;
509 
510  // allocate location for holding the seq numbers
511  create_sequence_number_bitfield(receive_data_cmd->max_seq_num);
513  prov.n_in_streams++;
515 
516  // set start of last seq number
517  last_seen_seq_num = 0;
518 }
519 
521 static void send_finished_response(void) {
522  // send boundary key, so that monitor knows everything in the previous
523  // stream is done
527  my_msg.length = sizeof(sdp_hdr_t) +
528  sizeof(int) * SEND_MISSING_SEQ_HEADER_WORDS;
530  log_debug("Sent end flag");
531 }
532 
537  const sdp_msg_pure_data *msg) {
538  // verify in right state
539  uint this_message_transaction_id = msg->data[TRANSACTION_ID];
540  if (received_seq_nums_store == NULL &&
541  this_message_transaction_id != transaction_id) {
542  log_debug(
543  "received missing seq numbers before a location with a "
544  "transaction id which is stale.");
545  return;
546  }
547  if (received_seq_nums_store == NULL &&
548  this_message_transaction_id == transaction_id) {
549  log_debug("received tell request when already sent finish. resending");
551  return;
552  }
553 
555  payload->transaction_id = transaction_id;
556 
557  // check that missing seq transmission is actually needed, or
558  // have we finished
563  return;
564  }
565 
566  // sending missing seq nums
567  log_debug("Looking for %d missing packets",
568  ((int) max_seq_num + 1) - ((int) total_received_seq_nums));
570  const uint *data_start = payload->data;
571  const uint *end_of_buffer = (uint *) (payload + 1);
572  uint *data_ptr = payload->data;
573 
574  // handle case of all missing
575  if (total_received_seq_nums == 0) {
576  // send response
577  data_ptr = payload->data;
578  *(data_ptr++) = ALL_MISSING_FLAG;
579  set_message_length(data_ptr);
581  return;
582  }
583 
584  // handle a random number of missing seqs
585  for (uint bit = 0; bit <= max_seq_num; bit++) {
586  if (bit_field_test(received_seq_nums_store, bit)) {
587  continue;
588  }
589 
590  *(data_ptr++) = bit;
591  if (data_ptr >= end_of_buffer) {
592  set_message_length(data_ptr);
594  data_ptr = payload->data;
595  }
596  }
597 
598  // send final message if required
599  if (data_ptr > data_start) {
600  set_message_length(data_ptr);
602  }
603 }
604 
609 static inline uint n_elements_in_msg(
610  const sdp_msg_pure_data *msg, const uint *data_start) {
611  // Offset in bytes from the start of the SDP message to where the data is
612  uint offset = ((uint8_t *) data_start) - &msg->flags;
613  return (msg->length - offset) / sizeof(uint);
614 }
615 
620 static inline void copy_data(
621  void *restrict target, const void *source, uint n_words) {
622  uint *to = target;
623  const uint *from = source;
624  while (n_words-- > 0) {
625  *to++ = *from++;
626  }
627 }
628 
632 static inline void receive_seq_data(const sdp_msg_pure_data *msg) {
633  // cast to the receive seq data
634  const receive_seq_data_msg_t *receive_data_cmd =
635  (receive_seq_data_msg_t *) msg->data;
636 
637  // check for bad states
638  if (received_seq_nums_store == NULL) {
639  log_debug("received data before being given a location");
640  return;
641  }
642  if (receive_data_cmd->transaction_id != transaction_id) {
643  log_debug("received data from a different transaction");
644  return;
645  }
646 
647  // all good, process data
648  uint seq = receive_data_cmd->seq_num;
649  log_debug("Sequence data, seq:%u", seq);
650  if (seq > max_seq_num) {
651  log_error("Bad sequence number %u when max is %u!", seq, max_seq_num);
652  return;
653  }
654 
655  uint this_sdram_address = calculate_sdram_address_from_seq_num(seq);
656  bool send_sdram_address = (last_seen_seq_num != seq - 1);
657 
658  if (!bit_field_test(received_seq_nums_store, seq)) {
659  bit_field_set(received_seq_nums_store, seq);
661  }
662  last_seen_seq_num = seq;
663 
664  uint n_elements = n_elements_in_msg(msg, receive_data_cmd->data);
665  log_debug("n elements is %d", n_elements);
666  sanity_check_write(this_sdram_address, n_elements);
667  if (chip_x == 0 && chip_y == 0) {
668  // directly write the data to where it belongs
669  for (uint data_index = 0; data_index < n_elements; data_index++) {
670  log_debug("data is %x", receive_data_cmd->data[data_index]);
671  }
672  copy_data(
673  (address_t) this_sdram_address, receive_data_cmd->data,
674  n_elements);
675  } else {
676  // transmit data to chip; the data lasts to the end of the message
678  receive_data_cmd->data, n_elements,
679  send_sdram_address, this_sdram_address);
680  }
681 }
682 
686  uint command = msg->data[COMMAND_ID];
687  prov.n_sdp_recvd++;
689 
690  // check for separate commands
691  switch (command) {
693  // translate elements to variables
695  break;
697  receive_seq_data(msg);
698  break;
700  log_debug("Checking for missing");
702  break;
703  default:
704  log_error("Failed to recognise command id %u", command);
705  }
706 }
707 
712 static void send_timeout(sdp_msg_t* msg, uint32_t key) {
713  if (msg->arg1 > ROUTER_TIMEOUT_MASK) {
714  msg->cmd_rc = RC_ARG;
715  return;
716  }
717  while (spin1_send_mc_packet(key, msg->arg1, WITH_PAYLOAD) == 0) {
718  spin1_delay_us(MESSAGE_DELAY_TIME_WHEN_FAIL);
719  }
720  msg->cmd_rc = RC_OK;
721 }
722 
726 static void send_clear_message(sdp_msg_t* msg) {
727  while (spin1_send_mc_packet(
728  reinject_clear_mc_key, 0, WITH_PAYLOAD) == 0) {
729  spin1_delay_us(MESSAGE_DELAY_TIME_WHEN_FAIL);
730  }
731  msg->cmd_rc = RC_OK;
732 }
733 
737 static void reinjection_sdp_command(sdp_msg_t *msg) {
738  // handle the key conversion
739  switch (msg->cmd_rc) {
742  log_debug("sent reinjection timeout mc");
743  break;
746  log_debug("sent reinjection emergency timeout mc");
747  break;
748  case CMD_DPRI_CLEAR:
749  send_clear_message(msg);
750  log_debug("sent reinjection clear mc");
751  break;
752  default:
753  // If we are here, the command was not recognised, so fail
754  // (ARG as the command is an argument)
755  log_error(
756  "ignoring message as don't know what to do with it when "
757  "command id is %d", msg->cmd_rc);
758  return;
759  }
760 
761  // set message to correct format
762  msg->length = SDP_REPLY_HEADER_LEN;
763  reflect_sdp_message(msg, 0);
764 
765  while (!spin1_send_sdp_msg(msg, SDP_TIMEOUT)) {
766  log_debug("failed to send SDP message");
767  spin1_delay_us(MESSAGE_DELAY_TIME_WHEN_FAIL);
768  }
769 }
770 
774 static void receive_sdp_message(uint mailbox, uint port) {
775  switch (port) {
776  case REINJECTION_PORT:
777  reinjection_sdp_command((sdp_msg_t *) mailbox);
778  break;
781  break;
782  default:
783  log_info("unexpected port %d\n", port);
784  }
785  // free the message to stop overload
786  spin1_msg_free((sdp_msg_t *) mailbox);
787 }
788 
790 static void send_data(void) {
792  my_msg.length = sizeof(sdp_hdr_t) + position_in_store * sizeof(uint);
793 
794  if (seq_num > max_seq_num) {
795  log_error("Got a funky seq num in sending; max is %d, received %d",
797  }
798 
800 
801  seq_num++;
805 }
806 
811 static void receive_data(uint key, uint payload) {
812  if (key == new_sequence_key) {
814  log_info("sending surplus data from new seq setting");
815  send_data();
816  }
817 
818  log_info("new seq num to set is %d", payload);
819  data[SEQ_NUM_LOC] = payload;
821  seq_num = payload;
823 
824  if (payload > max_seq_num) {
825  log_error("Got a funky seq num; max is %d, received %d",
826  max_seq_num, payload);
827  }
828  } else {
829  data[position_in_store] = payload;
831 
832  if (key == first_data_key) {
833  log_debug("received new stream with max %d", payload);
837  max_seq_num = payload;
838  }
839 
840  if (key == transaction_id_key) {
841  data_out_transaction_id = payload;
846  }
847 
848  if (key == end_flag_key) {
849  // set end flag bit in seq num
850  data[SEQ_NUM_LOC] |= 1 << 31;
851 
852  // adjust size as last payload not counted
854 
855  send_data();
856  log_debug("sent all data");
858  send_data();
859  }
860  }
861 }
862 
864 static void initialise(void) {
865  // Get the address this core's DTCM data starts at from SRAM
866  data_specification_metadata_t *ds_regions =
868 
869  // Read the header
870  if (!data_specification_read_header(ds_regions)) {
871  log_error("Failed to read the data spec header");
872  rt_error(RTE_SWERR);
873  }
874 
875  log_info("Initialising data out");
876 
877  // read keys from sdram
880  new_sequence_key = config->new_seq_key;
881  first_data_key = config->first_data_key;
882  transaction_id_key = config->transaction_id_key;
883  end_flag_key = config->end_flag_key;
884  basic_data_key = config->basic_data_key;
885 
886  log_info("new seq key = %d, first data key = %d, transaction id key = %d, "
887  "end flag key = %d, basic_data_key = %d",
890 
891  log_info("the tag id being used is %d", config->tag_id);
892  my_msg.tag = config->tag_id; // IPTag 1
893  my_msg.dest_port = PORT_ETH; // Ethernet
894  my_msg.dest_addr = sv->eth_addr; // Nearest Ethernet chip
895 
896  // fill in SDP source & flag fields
897  my_msg.flags = 0x07;
898  my_msg.srce_port = 3;
899  my_msg.srce_addr = sv->p2p_addr;
900 
901  // Set up provenance
903 
904  spin1_callback_on(FRPL_PACKET_RECEIVED, receive_data, MC_PACKET);
905 
906  log_info("Initialising data in");
907 
908  // Get the address this core's DTCM data starts at from SRAM
909  data_in_config_t *chip_key_map =
911 
912  // sort out bitfield for reinjection ack tracking
913  uint32_t n_extra_monitors = chip_key_map->n_extra_monitors;
914 
915  // read in the keys for mc packets for data in
916  for (uint i = 0; i < n_extra_monitors; i++) {
917  uint x_coord = chip_key_map->chip_to_key[i].x_coord;
918  uint y_coord = chip_key_map->chip_to_key[i].y_coord;
919  uint base_key = chip_key_map->chip_to_key[i].base_key;
920  data_in_mc_key_map[x_coord][y_coord] = base_key;
921  }
922 
923  // set up the reinjection multicast API
925 
926  // set sdp callback
927  spin1_callback_on(SDP_PACKET_RX, receive_sdp_message, SDP);
928 
929  // load user 1 in case this is a consecutive load
931 }
932 
937 void c_main(void) {
938  log_info("Configuring packet gatherer");
939 
940  // initialise the code
941  initialise();
942 
943  // start execution
944  log_info("Starting");
945 
946  spin1_start(SYNC_NOWAIT);
947 }
Command structure, describing a SpiNNaker multicast packet to be sent at some point.
Data type definitions for SpiNNaker Neuron-modelling.
uint32_t * address_t
A generic pointer to a word.
Common definitions for the non-SCAMP system binaries.
static void initialise_reinjection_mc_api(uint32_t base_mc_key)
sets up the multicast keys for the reinjection multicast API
Definition: common.h:73
static uint reinject_clear_mc_key
the multicast key used for clear reinjector queue to all extra monitors
Definition: common.h:69
@ CMD_DPRI_SET_ROUTER_EMERGENCY_TIMEOUT
Set the router's wait2 timeout.
Definition: common.h:32
@ CMD_DPRI_SET_ROUTER_TIMEOUT
Set the router's wait1 timeout.
Definition: common.h:30
@ CMD_DPRI_CLEAR
Clear the reinjection queue.
Definition: common.h:42
static uint reinject_emergency_timeout_mc_key
the multicast key used for emergency timeouts to all extra monitors
Definition: common.h:66
static uint reinject_timeout_mc_key
the multicast key used for basic timeouts to all extra monitors
Definition: common.h:63
#define SDP_REPLY_HEADER_LEN
Number of bytes in an SDP header.
Definition: common.h:82
#define TRANSACTION_CAP
Flag for cap on transaction id.
Definition: common.h:85
static void reflect_sdp_message(sdp_msg_t *msg, uint body_length)
Updates an SDP message so its content (a response to the message) goes back to where the message came...
Definition: common.h:91
Data Specification region access API.
static void * data_specification_get_region(uint32_t region, data_specification_metadata_t *ds_regions)
Gets the address of a region.
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.
The central structure that the DSE writes.
uint transaction_id
The transaction that the message is taking part in.
@ DATA_IN_NORMAL_PACKET_WORDS
size of data stored in packet with command and seq
@ ITEMS_PER_MISSING_PACKET
size of payload for a packet describing the batch of missing inbound seqs
uint command
The meaning of the message.
static void send_finished_response(void)
sends the finished request
#define SDRAM_VS_DTCM_THRESHOLD
threshold for SDRAM vs DTCM when allocating received_seq_nums_store
static void receive_data(uint key, uint payload)
Handles receipt of a fixed route packet with payload from the SpiNNaker network.
static void send_data(void)
sends data to the host via SDP (using my_msg)
static uint32_t basic_data_key
the key that marks an ordinary word within a data out stream
const uint first_data_key
The key used to indicate the first word of a stream.
ushort chip_y
Board-local y coordinate of chip to do write on.
@ PROVENANCE_REGION
Index of provenance region.
@ CONFIG
Index of general configuration region.
@ CHIP_TO_KEY
Index of chip-to-key mapping table.
uint data[ITEMS_PER_MISSING_PACKET]
The payload data of the message.
static void process_missing_seq_nums_and_request_retransmission(const sdp_msg_pure_data *msg)
searches through received sequence numbers and transmits missing ones back to host for retransmission
const uint transaction_id_key
The key used to indicate a transaction ID.
static void send_sdp_message(void)
sends the SDP message built in the my_msg global
static sdp_msg_pure_data my_msg
SDP message holder for transmissions.
static uint32_t position_in_store
index into data
const uint end_flag_key
The key used to indicate a stream end.
@ WRITE_ADDR_KEY_OFFSET
Payload contains a write address.
@ BOUNDARY_KEY_OFFSET
Write stream complete. Payload irrelevant.
@ DATA_KEY_OFFSET
Payload contains a data word.
const uint new_seq_key
The key used to indicate a new sequence/stream.
#define ALL_MISSING_FLAG
flag when all seq numbers are missing
static uint32_t transaction_id_key
the key that provides a new data out transaction ID
static dsupg_provenance_t prov
The DTCM copy of the provenance.
static void process_address_data(const receive_data_to_location_msg_t *receive_data_cmd)
handles reading the address, chips and max packets from a SDP message (command: SDP_SEND_DATA_TO_LOCA...
const uint32_t reinjector_base_key
The base key for reinjection control messages.
static bit_field_t received_seq_nums_store
Records what sequence numbers we have received from host during Data In.
static void receive_seq_data(const sdp_msg_pure_data *msg)
Handles receipt and parsing of a message full of sequence numbers that need to be retransmitted (comm...
#define SDP_TIMEOUT
timeout used in sending SDP messages
uint command
The meaning of the message.
static void free_sequence_number_bitfield(void)
Frees the allocated sequence number store.
uint32_t n_sdp_recvd
The number of SDP messages received (excluding those for SARK)
uint seq_num
The sequence number of this message.
static void sanity_check_write(uint write_address, uint n_elements)
Sanity checking for writes, ensuring that they're to the buffered SDRAM range.
static uint32_t first_data_key
the key that says this is the first item of data in a data out stream
uint command
The meaning of the message.
static uint32_t data[ITEMS_PER_DATA_PACKET]
uint32_t x_coord
Board local x coordinate of extra monitor.
static uint size_of_bitfield
The size of the bitfield in received_seq_nums_store.
static void create_sequence_number_bitfield(uint max_seq)
creates a store for sequence numbers in a memory store.
static void reinjection_sdp_command(sdp_msg_t *msg)
handles the commands for the reinjector code.
functionality_to_port_num_map
values for port numbers this core will respond to
@ REINJECTION_PORT
Reinjection control messages.
@ DATA_SPEED_UP_IN_PORT
Data Speed Up Inbound messages.
static void data_in_receive_sdp_data(const sdp_msg_pure_data *msg)
processes SDP messages for the Data In protocol
uint transaction_id
The transaction associated with the message.
static bool alloc_in_sdram
Whether received_seq_nums_store was allocated in SDRAM.
uint max_seq_num
Maximum sequence number of data stream.
static void receive_sdp_message(uint mailbox, uint port)
processes SDP messages
static void send_timeout(sdp_msg_t *msg, uint32_t key)
sends the basic timeout command via multicast to the extra monitors
static void copy_data(void *restrict target, const void *source, uint n_words)
because spin1_memcpy() is stupid, especially for access to SDRAM
#define ROUTER_TIMEOUT_MASK
mask needed by router timeout
static uint32_t transaction_id
The Data In transaction ID. Used to distinguish streams of packets.
static void send_mc_message(key_offsets command, uint payload)
sends a multicast (with payload) message to the current target chip
static uint32_t seq_num
default seq num
static dsupg_provenance_t * sdram_prov
The SDRAM copy of the provenance.
address_t address
Where the stream will be writing to in memory.
static uint total_received_seq_nums
Count of received sequence numbers.
void c_main(void)
This function is called at application start-up.
static uint32_t end_flag_key
the key that marks the end of a data out stream
#define MESSAGE_DELAY_TIME_WHEN_FAIL
the time to wait before trying again to send a message (MC, SDP) in microseconds
static uint start_sdram_address
Where the current stream of data started in SDRAM.
static uint data_in_mc_key_map[MAX_CHIP_INDEX][MAX_CHIP_INDEX]
How to find which key to use to talk to which chip on this board.
static uint32_t max_seq_num
maximum sequence number
uint transaction_id
The transaction that the message is taking part in.
uint32_t base_key
Base key to use for talking to that chip.
const uint tag_id
The ID of the IPtag to send the SDP packets out to host on.
@ SDP
SDP receive priority standard (high)
@ MC_PACKET
Multicast packet receive uses FIQ.
static uint32_t data_out_transaction_id
The Data Out transaction ID. Used to distinguish streams of packets.
const struct chip_key_data_t chip_to_key[]
The configuration data for routing messages to specific extra monitors.
@ COMMAND_ID
location of command IDs in SDP message
@ SEQ_NUM_LOC
location of where the seq num is in the packet
@ TRANSACTION_ID
location of the transaction id in the packet
@ START_OF_DATA
location of the start of raw data in the packet
uint32_t y_coord
Board local y coordinate of extra monitor.
ushort chip_x
Board-local x coordinate of chip to do write on.
@ SEND_DATA_LOCATION_HEADER_WORDS
offset with command, transaction id, address in bytes, [x, y], max seq,
@ SEND_SEQ_DATA_HEADER_WORDS
offset with just command transaction id and seq in bytes
@ SEND_MISSING_SEQ_HEADER_WORDS
offset with just command, transaction id
@ ABSOLUTE_MAX_SIZE_OF_SDP_IN_BYTES
absolute maximum size of a SDP message
static void send_clear_message(sdp_msg_t *msg)
sends the clear message to all extra monitors on this board
static uint n_elements_in_msg(const sdp_msg_pure_data *msg, const uint *data_start)
Calculates the number of words of data in an SDP message.
uint data[]
The payload of real data.
static uint calculate_sdram_address_from_seq_num(uint seq_num)
calculates the new sdram location for a given seq num
const uint32_t n_extra_monitors
The number of extra monitors that we can talk to.
static void publish_transaction_id_to_user_1(int transaction_id)
Writes the updated transaction ID to the user1.
sdp_port_commands
SDP port commands relating to the Data In protocol.
@ SDP_SEND_SEQ_DATA_CMD
Data In: Received message contains data to write.
@ SDP_SEND_MISSING_SEQ_DATA_IN_CMD
Data In: Sent message contains missing sequence numbers.
@ SDP_TELL_MISSING_BACK_TO_HOST
Data In: Received message asks for missing sequence numbers.
@ SDP_SEND_FINISHED_DATA_IN_CMD
Data In: Sent message indicates that everything has been received.
@ SDP_SEND_DATA_TO_LOCATION_CMD
Data In: Received message describes where to send data.
static void set_message_length(const void *end)
Sets the length of the outbound SDP message in my_msg.
#define MAX_CHIP_INDEX
max index needed to cover the chips in either direction on a spinn-5 board
const uint basic_data_key
The key used to indicate a general data item in a stream.
static uint32_t new_sequence_key
the key that causes data out sequence number to be processed
#define FIRST_SEQ_NUM
first sequence number to use and reset to
static void initialise(void)
Sets up the application.
static uint last_seen_seq_num
The most recently seen sequence number.
static void process_sdp_message_into_mc_messages(const uint *data, uint n_elements, bool set_write_address, uint write_address)
sends multicast messages accordingly for an SDP message
static uint chip_y
Board-relative y-coordinate of current chip being written to.
static uint chip_x
Board-relative x-coordinate of current chip being written to.
uint32_t n_in_streams
The number of input streams.
uint32_t n_out_streams
The number of output streams (technically, output transactions)
uint32_t n_sdp_sent
The number of SDP messages sent.
The layout of the Data In configuration region.
The layout of the Data Out configuration region.
The structure of the provenance region FIXME.
meaning of payload in first data in SDP packet
meaning of payload in subsequent data in SDP packets
SDP packet payload definition.
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.
The configuration parameters for the application.
uint8_t flags
SDP flag byte; first byte actually sent.
Definition: sdp_no_scp.h:37
uint8_t srce_port
SDP source port/CPU.
Definition: sdp_no_scp.h:40
uint16_t length
Length (measured from flags field start)
Definition: sdp_no_scp.h:33
uint8_t dest_port
SDP destination port/CPU.
Definition: sdp_no_scp.h:39
uint16_t dest_addr
SDP destination address.
Definition: sdp_no_scp.h:41
uint32_t data[ITEMS_PER_DATA_PACKET]
User data (272 bytes when no SCP header)
Definition: sdp_no_scp.h:45
uint8_t tag
SDP IPtag.
Definition: sdp_no_scp.h:38
uint16_t srce_addr
SDP source address.
Definition: sdp_no_scp.h:42
@ ITEMS_PER_DATA_PACKET
How many multicast packets are to be received per SDP packet.
Definition: sdp_no_scp.h:25
An SDP message with purely data, no SCP header.
Definition: sdp_no_scp.h:31
Simulation Functions Header File.