1 /*
2  * Copyright (c) 2017 Oticon A/S
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 /*
8  * TIMER - Timer/counter
9  * https://infocenter.nordicsemi.com/topic/ps_nrf52833/timer.html?cp=5_1_0_5_27
10  * https://infocenter.nordicsemi.com/topic/ps_nrf5340/timer.html?cp=4_0_0_6_34
11  */
12 
13 /**
14  * Notes:
15  *   * The functionality of TASK_SHUTDOWN is a bit of a guess
16  *   * INTENCLR will always read as 0
17  *   * Unlike in real HW, tasks cannot occur simultaneously, they always happen in some sequence
18  *     so task priority is not accounted for
19  *
20  * Implementation notes:
21  *
22  * In Timer mode, the timer is not actually counting all the time, but instead
23  * a HW event timer is programmed on the expected matches' times whenever the
24  * timer is started, stopped, or the compare values are updated.
25  *
26  * In Count mode, the timer count value (Counter[t]) is updated each time the
27  * corresponding TASK_COUNT is triggered.
28  */
29 
30 #include <string.h>
31 #include <stdbool.h>
32 #include <stdint.h>
33 #include "NHW_common_types.h"
34 #include "NHW_config.h"
35 #include "NHW_peri_types.h"
36 #include "NHW_TIMER.h"
37 #include "nsi_hw_scheduler.h"
38 #include "NHW_xPPI.h"
39 #include "irq_ctrl.h"
40 #include "bs_tracing.h"
41 #include "bs_oswrap.h"
42 #include "nsi_tasks.h"
43 #include "nsi_hws_models_if.h"
44 
45 #define N_TIMERS NHW_TIMER_TOTAL_INST
46 #define N_MAX_CC NHW_TIMER_MAX_N_CC
47 
48 struct timer_status {
49   NRF_TIMER_Type *NRF_TIMER_regs;
50 
51   unsigned int n_CCs;  //Number of compare/capture registers in this timer instance
52   int base_freq; //Base frequency (in MHz) of the timer input clock
53 
54   bs_time_t *CC_timers; //[n_CCs] In timer mode: When each compare match is expected to happen
55   bool *oneshot_flag; //[n_CCs] The CC register has been written, and a compare event has not yet been generated
56   bs_time_t start_t; //Time when the timer was started (only for timer mode)
57   uint32_t Counter; //Internal count value. Used in count mode, and in Timer mode during stops.
58   uint32_t INTEN;
59   bool is_running;
60 
61 #if (NHW_HAS_DPPI)
62   uint dppi_map;   //To which DPPI instance are this TIMER subscribe&publish ports connected to
63   //Which of the subscription ports are currently connected, and to which channel:
64   struct nhw_subsc_mem* subscribed_CAPTURE;   //[n_CCs]
65   struct nhw_subsc_mem subscribed_START;
66   struct nhw_subsc_mem subscribed_STOP;
67   struct nhw_subsc_mem subscribed_COUNT;
68   struct nhw_subsc_mem subscribed_CLEAR;
69   struct nhw_subsc_mem subscribed_SHUTDOWN;
70 #endif
71 };
72 
73 static bs_time_t Timer_TIMERs = TIME_NEVER;
74 static struct timer_status nhw_timer_st[NHW_TIMER_TOTAL_INST];
75 NRF_TIMER_Type NRF_TIMER_regs[NHW_TIMER_TOTAL_INST];
76 
77 /**
78  * Initialize the TIMER model
79  */
nhw_timer_init(void)80 static void nhw_timer_init(void) {
81 #if (NHW_HAS_DPPI)
82   /* Mapping of peripheral instance to DPPI instance */
83   uint nhw_timer_dppi_map[NHW_TIMER_TOTAL_INST] = NHW_TIMER_DPPI_MAP;
84 #endif
85   unsigned int Timer_n_CCs[N_TIMERS] = NHW_TIMER_N_CC;
86   int Timer_freqs[N_TIMERS] = NHW_TIMER_FREQ;
87 
88   memset(NRF_TIMER_regs, 0, sizeof(NRF_TIMER_regs));
89 
90   for (int t = 0; t < NHW_TIMER_TOTAL_INST ; t++) {
91     struct timer_status *t_st = &nhw_timer_st[t];
92 
93     t_st->NRF_TIMER_regs = &NRF_TIMER_regs[t];
94 
95     t_st->INTEN = 0;
96     t_st->is_running = false;
97     t_st->start_t = TIME_NEVER;
98     t_st->Counter = 0;
99 
100     t_st->base_freq = Timer_freqs[t];
101     t_st->n_CCs = Timer_n_CCs[t];
102     t_st->CC_timers = (bs_time_t *)bs_malloc(sizeof(bs_time_t)*Timer_n_CCs[t]);
103     t_st->oneshot_flag = (bool *)bs_calloc(Timer_n_CCs[t], sizeof(bool));
104 
105     for (unsigned int cc = 0; cc < t_st->n_CCs ; cc++) {
106       t_st->CC_timers[cc] = TIME_NEVER;
107     }
108 
109 #if (NHW_HAS_DPPI)
110     t_st->dppi_map = nhw_timer_dppi_map[t];
111     t_st->subscribed_CAPTURE = (struct nhw_subsc_mem*)bs_calloc(Timer_n_CCs[t], sizeof(struct nhw_subsc_mem));
112 #endif
113   }
114   Timer_TIMERs = TIME_NEVER;
115 }
116 
117 NSI_TASK(nhw_timer_init, HW_INIT, 100);
118 
119 /*
120  * Free all TIMER instances resources before program exit
121  */
nhw_timer_free(void)122 static void nhw_timer_free(void)
123 {
124   for (int t = 0; t< NHW_TIMER_TOTAL_INST; t++) {
125     struct timer_status *t_st = &nhw_timer_st[t];
126 
127     free(t_st->CC_timers);
128     t_st->CC_timers = NULL;
129 
130     free(t_st->oneshot_flag);
131     t_st->oneshot_flag = NULL;
132 
133 #if (NHW_HAS_DPPI)
134     free(t_st->subscribed_CAPTURE);
135     t_st->subscribed_CAPTURE = NULL;
136 #endif /* (NHW_HAS_DPPI) */
137   }
138 }
139 
140 NSI_TASK(nhw_timer_free, ON_EXIT_PRE, 100);
141 
142 /**
143  * Convert a time delta in us to the equivalent count accounting for the PRESCALER
144  * and the timer clock frequency
145  */
time_to_counter(bs_time_t delta,int t)146 static uint32_t time_to_counter(bs_time_t delta, int t){
147   uint64_t ticks;
148   ticks = (delta * nhw_timer_st[t].base_freq) >> NRF_TIMER_regs[t].PRESCALER;
149   return ticks;
150 }
151 
152 /**
153  * Convert a counter delta to us accounting for the PRESCALER
154  * and the timer clock frequency
155  */
counter_to_time(uint64_t counter,int t)156 static bs_time_t counter_to_time(uint64_t counter, int t){
157   bs_time_t Elapsed;
158   Elapsed = (counter << NRF_TIMER_regs[t].PRESCALER) / nhw_timer_st[t].base_freq;
159   return Elapsed;
160 }
161 
162 /**
163  * Return the counter mask (due to BITMODE) for this TIMER<t>
164  */
mask_from_bitmode(int t)165 static uint32_t mask_from_bitmode(int t){
166   switch (NRF_TIMER_regs[t].BITMODE){
167   case 0:
168     return 0xFFFF;
169     break;
170   case 1:
171     return 0xFF;
172     break;
173   case 2:
174     return 0xFFFFFF;
175     break;
176   default:
177     return 0xFFFFFFFF;
178     break;
179   }
180 }
181 
182 /**
183  * Return the time in us it takes for the COUNTER to do 1 wrap
184  * given BITMODE
185  */
time_of_1_counter_wrap(int t)186 static uint64_t time_of_1_counter_wrap(int t){
187   return counter_to_time((uint64_t)mask_from_bitmode(t) + 1, t);
188 }
189 
190 /**
191  * Find the CC register timer (CC_timers[][]) which will trigger earliest (if any)
192  */
update_master_timer(void)193 static void update_master_timer(void) {
194   Timer_TIMERs = TIME_NEVER;
195 
196   for ( int t = 0 ; t < N_TIMERS ; t++){
197     struct timer_status *t_st = &nhw_timer_st[t];
198 
199     if ((t_st->is_running == true) && (NRF_TIMER_regs[t].MODE == 0)) {
200       for (unsigned int cc = 0 ; cc < t_st->n_CCs ; cc++) {
201         if (t_st->CC_timers[cc] < Timer_TIMERs) {
202           Timer_TIMERs = t_st->CC_timers[cc];
203         }
204       }
205     }
206   }
207   nsi_hws_find_next_event();
208 }
209 
210 /**
211  * Save in CC_timers[t][cc] the next time when this timer will match the CC[cc]
212  * register
213  */
update_cc_timer(int t,int cc)214 static void update_cc_timer(int t, int cc) {
215   struct timer_status *this = &nhw_timer_st[t];
216 
217   if ((this->is_running == true) && (NRF_TIMER_regs[t].MODE == 0)) {
218     bs_time_t next_match = this->start_t
219                            + counter_to_time(NRF_TIMER_regs[t].CC[cc], t);
220     while (next_match <= nsi_hws_get_time()) {
221       next_match += time_of_1_counter_wrap(t);
222     }
223     this->CC_timers[cc] = next_match;
224   } else {
225     this->CC_timers[cc] = TIME_NEVER;
226   }
227 }
228 
update_all_cc_timers(int t)229 static void update_all_cc_timers(int t) {
230   for (unsigned int cc = 0 ; cc < nhw_timer_st[t].n_CCs; cc++) {
231     update_cc_timer(t, cc);
232   }
233 }
234 
nhw_timer_eval_interrupts(int t)235 static void nhw_timer_eval_interrupts(int t) {
236   /* Mapping of peripheral instance to {int controller instance, int number} */
237   static struct nhw_irq_mapping nhw_timer_irq_map[NHW_TIMER_TOTAL_INST] = NHW_TIMER_INT_MAP;
238   static bool TIMER_int_line[N_TIMERS]; /* Is the TIMER currently driving its interrupt line high */
239 
240   struct timer_status *this = &nhw_timer_st[t];
241   bool new_int_line = false;
242 
243   for (unsigned int cc = 0; cc < this->n_CCs; cc++) {
244     int mask = this->INTEN & (TIMER_INTENSET_COMPARE0_Msk << cc);
245     if (NRF_TIMER_regs[t].EVENTS_COMPARE[cc] && mask) {
246       new_int_line = true;
247       break; /* No need to check more */
248     }
249   }
250 
251   if (TIMER_int_line[t] == false && new_int_line == true) {
252     TIMER_int_line[t] = true;
253     hw_irq_ctrl_raise_level_irq_line(nhw_timer_irq_map[t].cntl_inst,
254                                      nhw_timer_irq_map[t].int_nbr);
255   } else if (TIMER_int_line[t] == true && new_int_line == false) {
256     TIMER_int_line[t] = false;
257 
258     hw_irq_ctrl_lower_level_irq_line(nhw_timer_irq_map[t].cntl_inst,
259                                      nhw_timer_irq_map[t].int_nbr);
260   }
261 }
262 
nhw_timer_TASK_START(int t)263 void nhw_timer_TASK_START(int t){
264   struct timer_status *this = &nhw_timer_st[t];
265 
266   //Note: STATUS is missing in NRF_TIMER_Type
267   if (this->is_running == false) {
268     this->is_running = true;
269     if (NRF_TIMER_regs[t].MODE == 0) { //Timer mode
270       this->start_t = nsi_hws_get_time() - counter_to_time(this->Counter, t); //If the counter is not zero at start, is like if the counter was started earlier
271       update_all_cc_timers(t);
272       update_master_timer();
273     }
274   }
275 }
276 
nhw_timer_TASK_STOP(int t)277 void nhw_timer_TASK_STOP(int t) {
278   struct timer_status *this = &nhw_timer_st[t];
279 
280   //Note: STATUS is missing in NRF_TIMER_Type
281   if (this->is_running == true) {
282     this->is_running = false;
283     if (NRF_TIMER_regs[t].MODE == 0) { //Timer mode
284       this->Counter = time_to_counter(nsi_hws_get_time() - this->start_t, t); //we save the value when the counter was stoped in case it is started again without clearing it
285     }
286     for (unsigned int cc = 0 ; cc < this->n_CCs ; cc++) {
287       this->CC_timers[cc] = TIME_NEVER;
288     }
289     update_master_timer();
290   }
291 }
292 
nhw_timer_TASK_SHUTDOWN(int t)293 void nhw_timer_TASK_SHUTDOWN(int t) {
294 #if defined(TIMER_TASKS_SHUTDOWN_TASKS_SHUTDOWN_Msk)
295   struct timer_status *this = &nhw_timer_st[t];
296 
297   /*
298    * TASK_SHUTDOWN is not documented in newer SOCs
299    * In older ones it indicates it STOPS + it reduces power consumption
300    * but that it cannot be resumed after from where it was
301    * The assumption is that the internal count is lost/reset to 0
302    * Effectively making a SHUTDOWN logically equivalent to a STOP + CLEAR
303    */
304   //Note: STATUS is missing in NRF_TIMER_Type
305   this->is_running = false;
306   this->Counter = 0;
307   this->start_t = TIME_NEVER;
308   for (uint cc = 0 ; cc < this->n_CCs ; cc++){
309     this->CC_timers[cc] = TIME_NEVER;
310   }
311   update_master_timer();
312 #else
313   (void) t;
314 #endif
315 }
316 
nhw_timer_TASK_CAPTURE(int t,unsigned int cc_n)317 void nhw_timer_TASK_CAPTURE(int t, unsigned int cc_n) {
318   struct timer_status *this = &nhw_timer_st[t];
319 
320   if (cc_n >= this->n_CCs) {
321     bs_trace_error_line_time("%s: Attempted to access non existing task"
322                              "TIMER%i.TASK_CAPTURE[%i] (>= %i)\n",
323                               t, cc_n, this->n_CCs);
324   }
325   if ((NRF_TIMER_regs[t].MODE != 0 /* Count mode */) || (this->is_running == false)) {
326     NRF_TIMER_regs[t].CC[cc_n] = this->Counter & mask_from_bitmode(t);
327   } else { //Timer mode (and running):
328     bs_time_t Elapsed = nsi_hws_get_time() - this->start_t;
329     NRF_TIMER_regs[t].CC[cc_n] = time_to_counter(Elapsed,t) & mask_from_bitmode(t);
330 
331     //The new CC causes a new possible CC match time:
332     update_cc_timer(t, cc_n);
333     update_master_timer();
334   }
335 }
336 
nhw_timer_TASK_CLEAR(uint t)337 void nhw_timer_TASK_CLEAR(uint t) {
338   struct timer_status *this = &nhw_timer_st[t];
339 
340   this->Counter = 0;
341   if (NRF_TIMER_regs[t].MODE == 0) {
342     //Timer mode:
343     this->start_t = nsi_hws_get_time();
344     update_all_cc_timers(t);
345     update_master_timer();
346   }
347 }
348 
nhw_timer_signal_COMPARE(uint t,uint cc)349 static void nhw_timer_signal_COMPARE(uint t, uint cc) {
350   struct timer_status *this = &nhw_timer_st[t];
351   NRF_TIMER_Type *TIMER_regs = this->NRF_TIMER_regs;
352 
353   if (TIMER_regs->SHORTS & (TIMER_SHORTS_COMPARE0_CLEAR_Msk << cc)) {
354     nhw_timer_TASK_CLEAR(t);
355   }
356   if (TIMER_regs->SHORTS & (TIMER_SHORTS_COMPARE0_STOP_Msk << cc)) {
357     nhw_timer_TASK_STOP(t);
358   }
359 
360   TIMER_regs->EVENTS_COMPARE[cc] = 1;
361 
362   nhw_timer_eval_interrupts(t);
363 
364 #if (NHW_HAS_PPI)
365   ppi_event_types_t event_cc;
366   switch (t) {
367   case 0:
368     event_cc = TIMER0_EVENTS_COMPARE_0;
369     break;
370   case 1:
371     event_cc = TIMER1_EVENTS_COMPARE_0;
372     break;
373   case 2:
374     event_cc = TIMER2_EVENTS_COMPARE_0;
375     break;
376   case 3:
377     event_cc = TIMER3_EVENTS_COMPARE_0;
378     break;
379   case 4:
380   default: /* This default is just to silence a -Werror=maybe-uninitialized warning */
381     event_cc = TIMER4_EVENTS_COMPARE_0;
382     break;
383   }
384   nrf_ppi_event(event_cc + cc);
385 #elif (NHW_HAS_DPPI)
386   nhw_dppi_event_signal_if(this->dppi_map,
387                            TIMER_regs->PUBLISH_COMPARE[cc]);
388 #endif
389 }
390 
nhw_timer_signal_COMPARE_if(uint t,uint cc_n)391 static void nhw_timer_signal_COMPARE_if(uint t, uint cc_n) {
392   struct timer_status *this = &nhw_timer_st[t];
393 #if (NHW_TIMER_HAS_ONE_SHOT)
394   if ((this->oneshot_flag[cc_n] == false) && this->NRF_TIMER_regs->ONESHOTEN[cc_n]) {
395     return;
396   }
397 #endif
398   this->oneshot_flag[cc_n] = false;
399   nhw_timer_signal_COMPARE(t, cc_n);
400 }
401 
nhw_timer_TASK_COUNT(uint t)402 void nhw_timer_TASK_COUNT(uint t) {
403   struct timer_status *this = &nhw_timer_st[t];
404 
405   if ((NRF_TIMER_regs[t].MODE != 0 /* Count mode */) && (this->is_running == true)) {
406     this->Counter = (this->Counter + 1) & mask_from_bitmode(t);
407 
408     for (unsigned int cc_n = 0; cc_n < this->n_CCs; cc_n++) {
409       if (this->Counter == (NRF_TIMER_regs[t].CC[cc_n] & mask_from_bitmode(t))){
410         nhw_timer_signal_COMPARE_if(t, cc_n);
411       }
412     }
413   } //Otherwise ignored
414 }
415 
nhw_timer_regw_sideeffects_TASKS_START(uint t)416 void nhw_timer_regw_sideeffects_TASKS_START(uint t) {
417   if ( NRF_TIMER_regs[t].TASKS_START ){
418     NRF_TIMER_regs[t].TASKS_START = 0;
419     nhw_timer_TASK_START(t);
420   }
421 }
422 
nhw_timer_regw_sideeffects_TASKS_STOP(uint t)423 void nhw_timer_regw_sideeffects_TASKS_STOP(uint t) {
424   if (NRF_TIMER_regs[t].TASKS_STOP) {
425     NRF_TIMER_regs[t].TASKS_STOP = 0;
426     nhw_timer_TASK_STOP(t);
427   }
428 }
429 
nhw_timer_regw_sideeffects_TASKS_SHUTDOWN(uint t)430 void nhw_timer_regw_sideeffects_TASKS_SHUTDOWN(uint t) {
431 #if defined(TIMER_TASKS_SHUTDOWN_TASKS_SHUTDOWN_Msk)
432   if (NRF_TIMER_regs[t].TASKS_SHUTDOWN) {
433     NRF_TIMER_regs[t].TASKS_SHUTDOWN = 0;
434     nhw_timer_TASK_SHUTDOWN(t);
435   }
436 #else
437   (void) t;
438 #endif
439 }
440 
nhw_timer_regw_sideeffects_TASKS_CAPTURE(uint t,uint cc_n)441 void nhw_timer_regw_sideeffects_TASKS_CAPTURE(uint t, uint cc_n){
442   if ( NRF_TIMER_regs[t].TASKS_CAPTURE[cc_n] ){
443     NRF_TIMER_regs[t].TASKS_CAPTURE[cc_n] = 0;
444     nhw_timer_TASK_CAPTURE(t,cc_n);
445   }
446 }
447 
nhw_timer_regw_sideeffects_TASKS_CLEAR(uint t)448 void nhw_timer_regw_sideeffects_TASKS_CLEAR(uint t) {
449   if (NRF_TIMER_regs[t].TASKS_CLEAR) {
450     NRF_TIMER_regs[t].TASKS_CLEAR = 0;
451     nhw_timer_TASK_CLEAR(t);
452   }
453 }
454 
nhw_timer_regw_sideeffects_TASKS_COUNT(uint t)455 void nhw_timer_regw_sideeffects_TASKS_COUNT(uint t) {
456   if ( NRF_TIMER_regs[t].TASKS_COUNT ){
457     NRF_TIMER_regs[t].TASKS_COUNT = 0;
458     nhw_timer_TASK_COUNT(t);
459   }
460 }
461 
462 #if (NHW_HAS_DPPI)
463 
nhw_timer_taskcapture_wrap(void * param)464 static void nhw_timer_taskcapture_wrap(void* param) {
465   unsigned int inst = (uintptr_t)param >> 16;
466   uint cc_n = (uintptr_t)param & 0xFFFF;
467   nhw_timer_TASK_CAPTURE(inst, cc_n);
468 }
469 
nhw_timer_regw_sideeffects_SUBSCRIBE_CAPTURE(uint inst,uint cc_n)470 void nhw_timer_regw_sideeffects_SUBSCRIBE_CAPTURE(uint inst, uint cc_n) {
471   struct timer_status *this = &nhw_timer_st[inst];
472 
473   nhw_dppi_common_subscribe_sideeffect(this->dppi_map,
474                                        this->NRF_TIMER_regs->SUBSCRIBE_CAPTURE[cc_n],
475                                        &this->subscribed_CAPTURE[cc_n],
476                                        nhw_timer_taskcapture_wrap,
477                                        (void*)((inst << 16) + cc_n));
478 }
479 
480 #define NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N)                                 \
481   static void nhw_timer_task##TASK_N##_wrap(void* param)                            \
482   {                                                                                 \
483     nhw_timer_TASK_##TASK_N((int) param);                                           \
484   }                                                                                 \
485                                                                                     \
486   void nhw_timer_regw_sideeffects_SUBSCRIBE_##TASK_N(uint inst)                     \
487   {                                                                                 \
488      struct timer_status *this = &nhw_timer_st[inst];                               \
489                                                                                     \
490      nhw_dppi_common_subscribe_sideeffect(this->dppi_map,                           \
491                                           this->NRF_TIMER_regs->SUBSCRIBE_##TASK_N, \
492                                           &this->subscribed_##TASK_N,               \
493                                           nhw_timer_task##TASK_N##_wrap,            \
494                                           (void*) inst);                            \
495   }
496 
497 NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(START)
NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(STOP)498 NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(STOP)
499 NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(COUNT)
500 NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(CLEAR)
501 #if defined(TIMER_TASKS_SHUTDOWN_TASKS_SHUTDOWN_Msk)
502 NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(SHUTDOWN)
503 #endif
504 
505 #endif /* NHW_HAS_DPPI */
506 
507 
508 void nhw_timer_regw_sideeffects_EVENTS_all(uint t) {
509   nhw_timer_eval_interrupts(t);
510 }
511 
nhw_timer_regw_sideeffects_INTENSET(uint t)512 void nhw_timer_regw_sideeffects_INTENSET(uint t) {
513   struct timer_status *this = &nhw_timer_st[t];
514 
515   if ( NRF_TIMER_regs[t].INTENSET ){
516     this->INTEN |= NRF_TIMER_regs[t].INTENSET;
517     NRF_TIMER_regs[t].INTENSET = this->INTEN;
518     nhw_timer_eval_interrupts(t);
519   }
520 }
521 
nhw_timer_regw_sideeffects_INTENCLR(uint t)522 void nhw_timer_regw_sideeffects_INTENCLR(uint t) {
523   struct timer_status *this = &nhw_timer_st[t];
524 
525   if ( NRF_TIMER_regs[t].INTENCLR ){
526     this->INTEN  &= ~NRF_TIMER_regs[t].INTENCLR;
527     NRF_TIMER_regs[t].INTENSET = this->INTEN;
528     NRF_TIMER_regs[t].INTENCLR = 0;
529     nhw_timer_eval_interrupts(t);
530   }
531 }
532 
nhw_timer_regw_sideeffects_CC(uint t,uint cc_n)533 void nhw_timer_regw_sideeffects_CC(uint t, uint cc_n) {
534   struct timer_status *this = &nhw_timer_st[t];
535 
536   if (cc_n >= this->n_CCs) {
537     bs_trace_error_line_time("%s: Attempted to access non existing register "
538                              "TIMER%i.CC[%i] (>= %i)\n",
539                               __func__, t, cc_n, this->n_CCs);
540   }
541 
542   this->oneshot_flag[cc_n] = true;
543 
544   if ( (this->is_running == true) && ( NRF_TIMER_regs[t].MODE == 0 ) ) {
545     update_cc_timer(t, cc_n);
546     update_master_timer();
547   }
548 }
549 
nhw_hw_model_timer_timer_triggered(void)550 static void nhw_hw_model_timer_timer_triggered(void) {
551   unsigned int t, cc;
552   struct {
553     unsigned int t[N_TIMERS*N_MAX_CC];
554     unsigned int cc[N_TIMERS*N_MAX_CC];
555     unsigned int cnt;
556   } match;
557 
558   match.cnt = 0;
559 
560   for (t = 0 ; t < N_TIMERS ; t++) {
561     struct timer_status *t_st = &nhw_timer_st[t];
562 
563     if ( !((t_st->is_running == true) && (NRF_TIMER_regs[t].MODE == 0)) ) {
564       continue;
565     }
566     for (cc = 0 ; cc < t_st->n_CCs ; cc++) {
567       if (t_st->CC_timers[cc] == Timer_TIMERs) {
568         match.t[match.cnt] = t;
569         match.cc[match.cnt] = cc;
570         match.cnt++;
571       }
572     }
573   }
574   while (match.cnt > 0) {
575     match.cnt--;
576     t = match.t[match.cnt];
577     cc = match.cc[match.cnt];
578     update_cc_timer(t,cc); //Next time it will match
579     nhw_timer_signal_COMPARE_if(t,cc);
580   }
581   update_master_timer();
582 }
583 
584 NSI_HW_EVENT(Timer_TIMERs, nhw_hw_model_timer_timer_triggered, 50);
585 
586 #if (NHW_HAS_PPI)
nhw_timer0_TASK_START(void)587 void nhw_timer0_TASK_START(void) { nhw_timer_TASK_START(0); }
nhw_timer1_TASK_START(void)588 void nhw_timer1_TASK_START(void) { nhw_timer_TASK_START(1); }
nhw_timer2_TASK_START(void)589 void nhw_timer2_TASK_START(void) { nhw_timer_TASK_START(2); }
nhw_timer3_TASK_START(void)590 void nhw_timer3_TASK_START(void) { nhw_timer_TASK_START(3); }
nhw_timer4_TASK_START(void)591 void nhw_timer4_TASK_START(void) { nhw_timer_TASK_START(4); }
592 
nhw_timer0_TASK_STOP(void)593 void nhw_timer0_TASK_STOP(void) { nhw_timer_TASK_STOP(0); }
nhw_timer1_TASK_STOP(void)594 void nhw_timer1_TASK_STOP(void) { nhw_timer_TASK_STOP(1); }
nhw_timer2_TASK_STOP(void)595 void nhw_timer2_TASK_STOP(void) { nhw_timer_TASK_STOP(2); }
nhw_timer3_TASK_STOP(void)596 void nhw_timer3_TASK_STOP(void) { nhw_timer_TASK_STOP(3); }
nhw_timer4_TASK_STOP(void)597 void nhw_timer4_TASK_STOP(void) { nhw_timer_TASK_STOP(4); }
598 
nhw_timer0_TASK_CAPTURE_0(void)599 void nhw_timer0_TASK_CAPTURE_0(void) { nhw_timer_TASK_CAPTURE(0,0); }
nhw_timer0_TASK_CAPTURE_1(void)600 void nhw_timer0_TASK_CAPTURE_1(void) { nhw_timer_TASK_CAPTURE(0,1); }
nhw_timer0_TASK_CAPTURE_2(void)601 void nhw_timer0_TASK_CAPTURE_2(void) { nhw_timer_TASK_CAPTURE(0,2); }
nhw_timer0_TASK_CAPTURE_3(void)602 void nhw_timer0_TASK_CAPTURE_3(void) { nhw_timer_TASK_CAPTURE(0,3); }
603 
nhw_timer1_TASK_CAPTURE_0(void)604 void nhw_timer1_TASK_CAPTURE_0(void) { nhw_timer_TASK_CAPTURE(1,0); }
nhw_timer1_TASK_CAPTURE_1(void)605 void nhw_timer1_TASK_CAPTURE_1(void) { nhw_timer_TASK_CAPTURE(1,1); }
nhw_timer1_TASK_CAPTURE_2(void)606 void nhw_timer1_TASK_CAPTURE_2(void) { nhw_timer_TASK_CAPTURE(1,2); }
nhw_timer1_TASK_CAPTURE_3(void)607 void nhw_timer1_TASK_CAPTURE_3(void) { nhw_timer_TASK_CAPTURE(1,3); }
608 
nhw_timer2_TASK_CAPTURE_0(void)609 void nhw_timer2_TASK_CAPTURE_0(void) { nhw_timer_TASK_CAPTURE(2,0); }
nhw_timer2_TASK_CAPTURE_1(void)610 void nhw_timer2_TASK_CAPTURE_1(void) { nhw_timer_TASK_CAPTURE(2,1); }
nhw_timer2_TASK_CAPTURE_2(void)611 void nhw_timer2_TASK_CAPTURE_2(void) { nhw_timer_TASK_CAPTURE(2,2); }
nhw_timer2_TASK_CAPTURE_3(void)612 void nhw_timer2_TASK_CAPTURE_3(void) { nhw_timer_TASK_CAPTURE(2,3); }
613 
nhw_timer3_TASK_CAPTURE_0(void)614 void nhw_timer3_TASK_CAPTURE_0(void) { nhw_timer_TASK_CAPTURE(3,0); }
nhw_timer3_TASK_CAPTURE_1(void)615 void nhw_timer3_TASK_CAPTURE_1(void) { nhw_timer_TASK_CAPTURE(3,1); }
nhw_timer3_TASK_CAPTURE_2(void)616 void nhw_timer3_TASK_CAPTURE_2(void) { nhw_timer_TASK_CAPTURE(3,2); }
nhw_timer3_TASK_CAPTURE_3(void)617 void nhw_timer3_TASK_CAPTURE_3(void) { nhw_timer_TASK_CAPTURE(3,3); }
nhw_timer3_TASK_CAPTURE_4(void)618 void nhw_timer3_TASK_CAPTURE_4(void) { nhw_timer_TASK_CAPTURE(3,4); }
nhw_timer3_TASK_CAPTURE_5(void)619 void nhw_timer3_TASK_CAPTURE_5(void) { nhw_timer_TASK_CAPTURE(3,5); }
620 
nhw_timer4_TASK_CAPTURE_0(void)621 void nhw_timer4_TASK_CAPTURE_0(void) { nhw_timer_TASK_CAPTURE(4,0); }
nhw_timer4_TASK_CAPTURE_1(void)622 void nhw_timer4_TASK_CAPTURE_1(void) { nhw_timer_TASK_CAPTURE(4,1); }
nhw_timer4_TASK_CAPTURE_2(void)623 void nhw_timer4_TASK_CAPTURE_2(void) { nhw_timer_TASK_CAPTURE(4,2); }
nhw_timer4_TASK_CAPTURE_3(void)624 void nhw_timer4_TASK_CAPTURE_3(void) { nhw_timer_TASK_CAPTURE(4,3); }
nhw_timer4_TASK_CAPTURE_4(void)625 void nhw_timer4_TASK_CAPTURE_4(void) { nhw_timer_TASK_CAPTURE(4,4); }
nhw_timer4_TASK_CAPTURE_5(void)626 void nhw_timer4_TASK_CAPTURE_5(void) { nhw_timer_TASK_CAPTURE(4,5); }
627 
nhw_timer0_TASK_CLEAR(void)628 void nhw_timer0_TASK_CLEAR(void) { nhw_timer_TASK_CLEAR(0); }
nhw_timer1_TASK_CLEAR(void)629 void nhw_timer1_TASK_CLEAR(void) { nhw_timer_TASK_CLEAR(1); }
nhw_timer2_TASK_CLEAR(void)630 void nhw_timer2_TASK_CLEAR(void) { nhw_timer_TASK_CLEAR(2); }
nhw_timer3_TASK_CLEAR(void)631 void nhw_timer3_TASK_CLEAR(void) { nhw_timer_TASK_CLEAR(3); }
nhw_timer4_TASK_CLEAR(void)632 void nhw_timer4_TASK_CLEAR(void) { nhw_timer_TASK_CLEAR(4); }
633 
nhw_timer0_TASK_COUNT(void)634 void nhw_timer0_TASK_COUNT(void) { nhw_timer_TASK_COUNT(0); }
nhw_timer1_TASK_COUNT(void)635 void nhw_timer1_TASK_COUNT(void) { nhw_timer_TASK_COUNT(1); }
nhw_timer2_TASK_COUNT(void)636 void nhw_timer2_TASK_COUNT(void) { nhw_timer_TASK_COUNT(2); }
nhw_timer3_TASK_COUNT(void)637 void nhw_timer3_TASK_COUNT(void) { nhw_timer_TASK_COUNT(3); }
nhw_timer4_TASK_COUNT(void)638 void nhw_timer4_TASK_COUNT(void) { nhw_timer_TASK_COUNT(4); }
639 #endif /* (NHW_HAS_PPI) */
640