Merge git://gitorious.org/~luki/simavr/lukis-simavr into dev-home
[simavr] / simavr / sim / sim_cycle_timers.c
1 /*
2         sim_cycle_timers.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <strings.h>
25 #include "sim_cycle_timers.h"
26
27 void avr_cycle_timer_register(avr_t * avr, avr_cycle_count_t when, avr_cycle_timer_t timer, void * param)
28 {
29         avr_cycle_timer_cancel(avr, timer, param);
30
31         if (avr->cycle_timer_map == 0xffffffff) {
32                 fprintf(stderr, "avr_cycle_timer_register is full!\n");
33                 return;
34         }
35         when += avr->cycle;
36         if (when < avr->next_cycle_timer)
37                 avr->next_cycle_timer = when;
38         for (int i = 0; i < 32; i++)
39                 if (!(avr->cycle_timer_map & (1 << i))) {
40                         avr->cycle_timer[i].timer = timer;
41                         avr->cycle_timer[i].param = param;
42                         avr->cycle_timer[i].when = when;
43                         avr->cycle_timer_map |= (1 << i);
44                         return;
45                 }
46 }
47
48 void avr_cycle_timer_register_usec(avr_t * avr, uint32_t when, avr_cycle_timer_t timer, void * param)
49 {
50         avr_cycle_timer_register(avr, avr_usec_to_cycles(avr, when), timer, param);
51 }
52
53 void avr_cycle_timer_cancel(avr_t * avr, avr_cycle_timer_t timer, void * param)
54 {
55         if (!avr->cycle_timer_map)
56                 return;
57         for (int i = 0; i < 32; i++)
58                 if ((avr->cycle_timer_map & (1 << i)) &&
59                                 avr->cycle_timer[i].timer == timer &&
60                                 avr->cycle_timer[i].param == param) {
61                         avr->cycle_timer[i].timer = NULL;
62                         avr->cycle_timer[i].param = NULL;
63                         avr->cycle_timer[i].when = 0;
64                         avr->cycle_timer_map &= ~(1 << i);
65                         // no need to reset next_cycle_timer; having too small
66                         // a value there only causes some harmless extra
67                         // computation.
68                         return;
69                 }
70 }
71
72 /*
73  * Check to see if a timer is present, if so, return the number (+1) of
74  * cycles left for it to fire, and if not present, return zero
75  */
76 avr_cycle_count_t
77 avr_cycle_timer_status(avr_t * avr, avr_cycle_timer_t timer, void * param)
78 {
79         uint32_t map = avr->cycle_timer_map;
80
81         while (map) {
82                 int bit = ffs(map)-1;
83                 if (avr->cycle_timer[bit].timer == timer &&
84                     avr->cycle_timer[bit].param == param) {
85                         return 1 + (avr->cycle_timer[bit].when - avr->cycle);
86                 }
87                 map &= ~(1 << bit);
88         }
89
90         return 0;
91 }
92
93 /*
94  * run thru all the timers, call the ones that needs it,
95  * clear the ones that wants it, and calculate the next
96  * potential cycle we could sleep for...
97  */
98 avr_cycle_count_t avr_cycle_timer_process(avr_t * avr)
99 {
100         // If we have previously determined that we don't need to fire
101         // cycle timers yet, we can do an early exit
102         if (avr->next_cycle_timer > avr->cycle)
103                 return avr->next_cycle_timer - avr->cycle;
104
105         if (!avr->cycle_timer_map) {
106                 avr->next_cycle_timer = (avr_cycle_count_t)-1;
107                 return (avr_cycle_count_t)-1;
108         }
109
110         avr_cycle_count_t min = (avr_cycle_count_t)-1;
111         uint32_t map = avr->cycle_timer_map;
112
113         while (map) {
114                 int bit = ffs(map)-1;
115                 // do it several times, in case we're late
116                 while (avr->cycle_timer[bit].when && avr->cycle_timer[bit].when <= avr->cycle) {
117                         // call it
118                         avr->cycle_timer[bit].when =
119                                         avr->cycle_timer[bit].timer(avr,
120                                                         avr->cycle_timer[bit].when,
121                                                         avr->cycle_timer[bit].param);
122                         if (avr->cycle_timer[bit].when == 0) {
123                                 // clear it
124                                 avr->cycle_timer[bit].timer = NULL;
125                                 avr->cycle_timer[bit].param = NULL;
126                                 avr->cycle_timer[bit].when = 0;
127                                 avr->cycle_timer_map &= ~(1 << bit);
128                                 break;
129                         }
130                 }
131                 if (avr->cycle_timer[bit].when && avr->cycle_timer[bit].when < min)
132                         min = avr->cycle_timer[bit].when;
133                 map &= ~(1 << bit);             
134         }
135         avr->next_cycle_timer = min;
136         return min - avr->cycle;
137 }