SpiNNFrontEndCommon  development
Common support code for user-facing front end systems.
simulation.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 
22 #include "simulation.h"
23 
24 #include <stdbool.h>
25 #include <debug.h>
26 #include <spin1_api_params.h>
27 #include <spin1_api.h>
28 #include <wfi.h>
29 
30 // Import things from spin1_api that are not explicitly exposed //
31 
34 extern uint resume_wait(void);
35 
37 static uint32_t *pointer_to_simulation_time;
38 
40 static uint32_t *pointer_to_infinite_run;
41 
43 static uint32_t *pointer_to_current_time;
44 
47 
50 
53 
56 
58 static struct simulation_provenance *prov = NULL;
59 
61 static callback_t sdp_callback[NUM_SDP_PORTS];
62 
65 
67 static bool uses_timer = true;
68 
70 static uint32_t n_sync_steps;
71 
73 static uint32_t next_sync_step;
74 
76 static bool simulation_paused = false;
77 
82  extern diagnostics_t diagnostics;
83 
84  // store the data into the provenance data region
85  prov->transmission_event_overflow = diagnostics.tx_packet_queue_full;
86  prov->callback_queue_overloads = diagnostics.task_queue_full;
87  prov->dma_queue_overloads = diagnostics.dma_queue_full;
88  prov->user_queue_overloads = diagnostics.user_event_queue_full;
89  prov->timer_tic_has_overrun =
90  diagnostics.total_times_tick_tic_callback_overran;
91  prov->max_num_timer_tic_overrun =
92  diagnostics.largest_number_of_concurrent_timer_tic_overruns;
93  return prov->provenance_data_elements;
94 }
95 
97 static void execute_provenance_storage(void) {
98  if (prov != NULL) {
99  log_info("Starting basic provenance gathering");
100  void *address_to_start_with = simulation_store_provenance_data();
101  if (stored_provenance_function != NULL) {
102  log_info("running other provenance gathering");
103  stored_provenance_function(address_to_start_with);
104  }
105  }
106 }
107 
108 void simulation_run(void) {
109  // go into spin1 API start, but paused (no SYNC yet)
110  spin1_start_paused();
111 }
112 
114  // Pause the simulation
115  if (uses_timer) {
116  spin1_pause();
117  }
118 
119  stored_resume_function = callback;
120 
121  // Store provenance data as required
123 }
124 
127 void simulation_exit(void) {
129 }
130 
132  sark_cpu_state(CPU_STATE_WAIT);
133 }
134 
137 static void send_ok_response(sdp_msg_t *msg) {
138  msg->cmd_rc = RC_OK;
139  msg->length = 12;
140  uint dest_port = msg->dest_port;
141  uint dest_addr = msg->dest_addr;
142  msg->dest_port = msg->srce_port;
143  msg->srce_port = dest_port;
144  msg->dest_addr = msg->srce_addr;
145  msg->srce_addr = dest_addr;
146  spin1_send_sdp_msg(msg, 10);
147 }
148 
152 static inline void wait_before_run(bool reset_event) {
153  while (resume_wait()) {
155  }
156  if (reset_event) {
157  event.wait ^= 1;
158  }
159  sark_cpu_state(CPU_STATE_RUN);
160 }
161 
165 static void synchronise_start(uint unused0, uint unused1) {
166  // If we are not using the timer, no-one else resets the event, so do it now
167  // (event comes from sark.h - this is how SARK knows whether to wait for a
168  // SYNC0 or SYNC1 message)
171 }
172 
174 static inline void set_cpu_wait_state() {
175  if (event.wait) {
176  sark_cpu_state(CPU_STATE_SYNC1);
177  } else {
178  sark_cpu_state(CPU_STATE_SYNC0);
179  }
180 }
181 
187 static void simulation_control_scp_callback(uint mailbox, UNUSED uint port) {
188  sdp_msg_t *msg = (sdp_msg_t *) mailbox;
189  uint16_t length = msg->length;
190 
191  switch (msg->cmd_rc) {
192  case CMD_STOP:
193  log_info("Received exit signal. Program complete.");
194 
195  // free the message to stop overload
196  spin1_msg_free(msg);
197 
198  // call any stored exit callbacks
199  if (stored_exit_function != NULL) {
200  log_info("Calling pre-exit function");
202  }
203  log_info("Exiting");
204  spin1_exit(0);
205  break;
206 
207  case CMD_RUNTIME:
208  log_info("Setting the runtime of this model to %d starting at %d",
209  msg->arg1, msg->arg3);
210  log_info("Setting the flag of infinite run for this model to %d",
211  msg->arg2);
212 
213  // resetting the simulation time pointer
214  *pointer_to_simulation_time = msg->arg1;
215  *pointer_to_infinite_run = msg->arg2;
216  // We start at time - 1 because the first thing models do is
217  // increment a time counter
218  *pointer_to_current_time = (msg->arg3 - 1);
219  uint32_t *data = (uint32_t *) msg->data;
220  n_sync_steps = data[0];
221  if (n_sync_steps > 0) {
222  // Add one to make the sync happen *after* n_sync_steps
224  } else {
225  next_sync_step = 0;
226  }
227 
228  if (stored_resume_function != NULL) {
229  log_info("Calling pre-resume function");
231  stored_resume_function = NULL;
232  }
233 
234  if (stored_start_function != NULL) {
235  spin1_schedule_callback(synchronise_start, 0, 0, 1);
236  }
237  if (uses_timer) {
238  log_info("Resuming");
239  spin1_resume(SYNC_WAIT);
240  } else {
242  }
243  send_ok_response(msg);
244 
245  // free the message to stop overload
246  spin1_msg_free(msg);
247  break;
248 
250  log_info("Forced provenance gathering");
251 
252  // force provenance to be executed and then exit
254 
255  // call any stored exit callbacks
256  if (stored_exit_function != NULL) {
257  log_info("Calling pre-exit function");
259  }
260  spin1_msg_free(msg);
261  spin1_exit(1);
262  break;
263 
264  case IOBUF_CLEAR:
265  // run clear iobuf code
266  sark_io_buf_reset();
267 
268  // If we are told to send a response, send it now
269  if (msg->arg3 == 1) {
270  send_ok_response(msg);
271  }
272 
273  // free the message to stop overload
274  spin1_msg_free(msg);
275  break;
276 
277  case CMD_PAUSE:
278  // pause the simulation
279  log_info("Pausing the simulation");
280  simulation_paused = true;
281  send_ok_response(msg);
282  spin1_msg_free(msg);
283  break;
284 
285  case CMD_GET_TIME:
286  // send the current time back
287  msg->cmd_rc = RC_OK;
288  // The length is 12 for the header + 4 for the time (in arg1)
289  msg->length = 16;
290  msg->arg1 = *pointer_to_current_time;
291  uint dest_port = msg->dest_port;
292  uint dest_addr = msg->dest_addr;
293  msg->dest_port = msg->srce_port;
294  msg->srce_port = dest_port;
295  msg->dest_addr = msg->srce_addr;
296  msg->srce_addr = dest_addr;
297  spin1_send_sdp_msg(msg, 10);
298  spin1_msg_free(msg);
299  break;
300 
301  default:
302  // should never get here
303  log_error("received packet with unknown command code %d",
304  msg->cmd_rc);
305  spin1_msg_free(msg);
306  }
307 }
308 
312 static void simulation_sdp_callback_handler(uint mailbox, uint port) {
313  if (sdp_callback[port] != NULL) {
314  // if a callback is associated with the port, process it
315  sdp_callback[port](mailbox, port);
316  } else {
317  // if no callback is associated, dump the received packet
318  sdp_msg_t *msg = (sdp_msg_t *) mailbox;
319  sark_msg_free(msg);
320  }
321 }
322 
323 bool simulation_sdp_callback_on(uint sdp_port, callback_t callback) {
324  if (sdp_callback[sdp_port] != NULL) {
325  log_error("Cannot allocate SDP callback on port %d as its already "
326  "been allocated.", sdp_port);
327  return false;
328  }
329  sdp_callback[sdp_port] = callback;
330  return true;
331 }
332 
333 void simulation_sdp_callback_off(uint sdp_port) {
334  sdp_callback[sdp_port] = NULL;
335 }
336 
340 static void simulation_dma_transfer_done_callback(uint unused, uint tag) {
341  if (tag < MAX_DMA_CALLBACK_TAG && dma_complete_callbacks[tag] != NULL) {
342  dma_complete_callbacks[tag](unused, tag);
343  }
344 }
345 
346 bool simulation_dma_transfer_done_callback_on(uint tag, callback_t callback) {
347  // ensure that tag being allocated is less than max tag
348  if (tag >= MAX_DMA_CALLBACK_TAG) {
349  log_error("Cannot handle tag value above %d, please reduce the tag "
350  "value accordingly.", MAX_DMA_CALLBACK_TAG - 1);
351  return false;
352  }
353 
354  // allocate tag callback if not already allocated
355  if (dma_complete_callbacks[tag] != NULL) {
356  // if allocated already, raise error
357  log_error("Cannot allocate DMA transfer callback on tag %d as its "
358  "already been allocated.", tag);
359  return false;
360  }
361 
362  dma_complete_callbacks[tag] = callback;
363  return true;
364 }
365 
367  dma_complete_callbacks[tag] = NULL;
368 }
369 
371  address_t address, uint32_t expected_app_magic_number,
372  uint32_t* timer_period, uint32_t *simulation_ticks_pointer,
373  uint32_t *infinite_run_pointer, uint32_t *time_pointer,
374  int sdp_packet_callback_priority,
375  int dma_transfer_done_callback_priority) {
376  struct simulation_config *config = (void *) address;
377 
378  // handle the timing reading
379  if (config->application_magic_number != expected_app_magic_number) {
380  log_error("Unexpected magic number 0x%08x instead of 0x%08x at 0x%08x",
381  config->application_magic_number, expected_app_magic_number,
382  &config->application_magic_number);
383  return false;
384  }
385 
386  if (sdp_packet_callback_priority < -1) {
387  log_error("The SDP callback priority should be set to a number greater "
388  "than or equal to -1. It is currently set to %d",
389  sdp_packet_callback_priority);
390  return false;
391  }
392 
393  // transfer data to pointers for end user usage
394  *timer_period = config->timer_period;
395 
396  // handle the SDP callback for the simulation
397  pointer_to_simulation_time = simulation_ticks_pointer;
398  pointer_to_infinite_run = infinite_run_pointer;
399  pointer_to_current_time = time_pointer;
400 
401  spin1_callback_on(SDP_PACKET_RX, simulation_sdp_callback_handler,
402  sdp_packet_callback_priority);
403  simulation_sdp_callback_on(config->control_sdp_port,
405  if (dma_transfer_done_callback_priority >= -1) {
406  spin1_callback_on(DMA_TRANSFER_DONE, simulation_dma_transfer_done_callback,
407  dma_transfer_done_callback_priority);
408  }
409 
410  // if all simulation initialisation complete return true,
411  return true;
412 }
413 
414 void simulation_set_provenance_data_address(address_t provenance_data_address) {
415  prov = (void *) provenance_data_address;
416 }
417 
419  prov_callback_t provenance_function,
420  address_t provenance_data_address) {
421  stored_provenance_function = provenance_function;
422  prov = (void *) provenance_data_address;
423 }
424 
426  stored_exit_function = exit_function;
427 }
428 
430  stored_start_function = start_function;
431 }
432 
433 void simulation_set_uses_timer(bool sim_uses_timer) {
434  uses_timer = sim_uses_timer;
435 }
436 
437 void simulation_set_sync_steps(uint32_t n_steps) {
438  n_sync_steps = n_steps;
439  if (n_steps > 0) {
440  next_sync_step = *pointer_to_current_time + n_steps + 1;
441  }
442 }
443 
445  // If we are manually paused, report yes once, then go back to no
446  if (simulation_paused) {
447  simulation_paused = false;
448  return true;
449  }
450 
451  bool finished = ((*pointer_to_infinite_run != TRUE) &&
453  // If we are finished, or not running synchronized, return finished
454  if (finished || !n_sync_steps) {
455  return finished;
456  }
457  // If we are synchronized, check if this is a sync step (or should have been)
459  log_debug("Sync at %d", next_sync_step);
460 
461  // If using the timer, pause the timer
462  if (uses_timer) {
463  log_debug("Pausing");
464  spin1_pause();
465  }
466 
467  // Wait for synchronisation to happen
468  log_debug("Waiting for sync");
470  wait_before_run(true);
472  log_debug("Sync done, next sync at %d", next_sync_step);
473 
474  // If using the timer, start it again
475  if (uses_timer) {
476  spin1_resume(SYNC_NOWAIT);
477  }
478  }
479  return false;
480 }
uint32_t * address_t
A generic pointer to a word.
static uint32_t data[ITEMS_PER_DATA_PACKET]
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.
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
void simulation_set_provenance_data_address(address_t provenance_data_address)
Set the address of the data region where provenance data is to be stored.
Definition: simulation.c:414
static uint32_t n_sync_steps
The number of steps to run before synchronisation.
Definition: simulation.c:70
static void wait_before_run(bool reset_event)
wait for a signal before running
Definition: simulation.c:152
static callback_t sdp_callback[NUM_SDP_PORTS]
the list of SDP callbacks for ports
Definition: simulation.c:61
static void * simulation_store_provenance_data(void)
Store basic provenance data.
Definition: simulation.c:80
static void simulation_control_scp_callback(uint mailbox, uint port)
Handle the new commands needed to resume the binary with a new runtime counter, as well as switching ...
Definition: simulation.c:187
void simulation_exit(void)
Exit the application.
Definition: simulation.c:127
void simulation_set_start_function(start_callback_t start_function)
Set an additional function to call before starting the binary.
Definition: simulation.c:429
void simulation_set_uses_timer(bool sim_uses_timer)
set whether the simulation uses the timer. By default it will be assumed that simulations use the tim...
Definition: simulation.c:433
static void simulation_sdp_callback_handler(uint mailbox, uint port)
handles the SDP callbacks interface.
Definition: simulation.c:312
static uint32_t * pointer_to_infinite_run
the pointer to the flag for if it is a infinite run
Definition: simulation.c:40
void simulation_set_exit_function(exit_callback_t exit_function)
Set an additional function to call before exiting the binary when running without a fixed duration of...
Definition: simulation.c:425
static void execute_provenance_storage(void)
Run the provenance data storage.
Definition: simulation.c:97
static exit_callback_t stored_exit_function
the function call to run when received a exit command.
Definition: simulation.c:49
static callback_t dma_complete_callbacks[MAX_DMA_CALLBACK_TAG]
the list of DMA callbacks for DMA complete callbacks
Definition: simulation.c:64
bool simulation_is_finished(void)
determine if the simulation is finished. Will also pause the simulation for resynchronisation if requ...
Definition: simulation.c:444
static void set_cpu_wait_state()
Set the CPU state depending on the event wait state.
Definition: simulation.c:174
bool simulation_initialise(address_t address, uint32_t expected_app_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_done_callback_priority)
initialises the simulation interface which involves:
Definition: simulation.c:370
static uint32_t next_sync_step
The number simulation timestep at the next synchronisation.
Definition: simulation.c:73
static void send_ok_response(sdp_msg_t *msg)
Send an OK response to the host when a command message is received.
Definition: simulation.c:137
static uint32_t * pointer_to_current_time
the pointer to the current simulation time
Definition: simulation.c:43
bool simulation_dma_transfer_done_callback_on(uint tag, callback_t callback)
registers a DMA transfer callback to the simulation system
Definition: simulation.c:346
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
static start_callback_t stored_start_function
the function call to run at the start of simulation
Definition: simulation.c:55
static struct simulation_provenance * prov
the region ID for storing provenance data from the chip
Definition: simulation.c:58
static prov_callback_t stored_provenance_function
the function call to run when extracting provenance data from the chip
Definition: simulation.c:46
static bool simulation_paused
Whether the simulation has been manually "paused".
Definition: simulation.c:76
static void simulation_dma_transfer_done_callback(uint unused, uint tag)
handles the DMA transfer done callbacks interface.
Definition: simulation.c:340
void simulation_sdp_callback_off(uint sdp_port)
disables SDP callbacks on the given port
Definition: simulation.c:333
void simulation_set_sync_steps(uint32_t n_steps)
sets the simulation to enter a synchronisation barrier repeatedly during the simulation....
Definition: simulation.c:437
bool simulation_sdp_callback_on(uint sdp_port, callback_t callback)
Registers an additional SDP callback on a given SDP port. This is required when using simulation_regi...
Definition: simulation.c:323
uint resume_wait(void)
Indicate whether the SYNC signal has been received.
static resume_callback_t stored_resume_function
the function call to run just before resuming a simulation
Definition: simulation.c:52
static void synchronise_start(uint unused0, uint unused1)
Callback when starting after synchronise.
Definition: simulation.c:165
static bool uses_timer
Whether the simulation uses the timer or not (default true)
Definition: simulation.c:67
void simulation_dma_transfer_done_callback_off(uint tag)
turns off a registered callback for a given DMA transfer done tag
Definition: simulation.c:366
void simulation_run(void)
Starts the simulation running, returning when it is complete,.
Definition: simulation.c:108
static uint32_t * pointer_to_simulation_time
the pointer to the simulation time used by application models
Definition: simulation.c:37
Simulation Functions Header File.
void(* resume_callback_t)(void)
the definition of the callback used by pause and resume
Definition: simulation.h:78
void(* exit_callback_t)(void)
Definition: simulation.h:82
#define MAX_DMA_CALLBACK_TAG
Definition: simulation.h:35
resume_callback_t start_callback_t
the definition of the callback used to call a function once at start
Definition: simulation.h:85
void(* prov_callback_t)(address_t)
the definition of the callback used by provenance data functions
Definition: simulation.h:75
@ CMD_STOP
Asks the simulation loop to stop as soon as possible.
Definition: simulation.h:60
@ CMD_PAUSE
Definition: simulation.h:69
@ CMD_GET_TIME
Get the current simulation time.
Definition: simulation.h:71
@ PROVENANCE_DATA_GATHERING
Asks the application to gather provenance data.
Definition: simulation.h:64
@ CMD_RUNTIME
Tells the simulation loop how long to run for.
Definition: simulation.h:62
@ IOBUF_CLEAR
Clears the IOBUF.
Definition: simulation.h:66
the position and human readable terms for each element from the region containing the timing details.
Definition: simulation.h:39
elements that are always grabbed for provenance if possible when requested
Definition: simulation.h:47
Wait for interrupt.
static void wait_for_interrupt(void)
Wait for any interrupt to occur.
Definition: wfi.h:32