misc: Fixed a couple of typos in comments
[simavr] / simavr / sim / sim_cycle_timers.c
1 /*
2         sim_cycle_timers.c
3
4         Copyright 2008-2012 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 <string.h>
25 #include "sim_avr.h"
26 #include "sim_time.h"
27 #include "sim_cycle_timers.h"
28
29 #if 0
30 #define DEBUG(__w) __w
31 #define DUMP(_pool,_w) { \
32         printf("%s:%d %s ",__func__,__LINE__, _w);\
33         for (int _i=0;_i<_pool->count;_i++) \
34                 printf("[%2d:%7d] ",_i,(int)_pool->timer[_i].when);\
35         printf("\n");\
36 }
37 #else
38 #define DEBUG(__w)
39 #define DUMP(_pool,_w)
40 #endif
41
42 void
43 avr_cycle_timer_reset(
44                 struct avr_t * avr)
45 {
46         avr_cycle_timer_pool_t * pool = &avr->cycle_timers;
47         memset(pool, 0, sizeof(*pool));
48 }
49
50 // no sanity checks checking here, on purpose
51 static void
52 avr_cycle_timer_insert(
53                 avr_t * avr,
54                 avr_cycle_count_t when,
55                 avr_cycle_timer_t timer,
56                 void * param)
57 {
58         avr_cycle_timer_pool_t * pool = &avr->cycle_timers;
59
60         when += avr->cycle;
61
62         // find its place in the list
63         int inserti = 0;
64         while (inserti < pool->count && pool->timer[inserti].when > when)
65                 inserti++;
66         // make a hole
67         int cnt = pool->count - inserti;
68         if (cnt)
69                 memmove(&pool->timer[inserti + 1], &pool->timer[inserti],
70                                 cnt * sizeof(avr_cycle_timer_slot_t));
71
72         pool->timer[inserti].timer = timer;
73         pool->timer[inserti].param = param;
74         pool->timer[inserti].when = when;
75         pool->count++;
76         DEBUG(printf("%s %2d/%2d when %7d %p/%p\n", __func__, inserti, pool->count, (int)(when - avr->cycle), timer, param);)
77         DUMP(pool, "after");
78 }
79
80 void
81 avr_cycle_timer_register(
82                 avr_t * avr,
83                 avr_cycle_count_t when,
84                 avr_cycle_timer_t timer,
85                 void * param)
86 {
87         avr_cycle_timer_pool_t * pool = &avr->cycle_timers;
88
89         // remove it if it was already scheduled
90         avr_cycle_timer_cancel(avr, timer, param);
91
92         if (pool->count == MAX_CYCLE_TIMERS) {
93                 fprintf(stderr, "%s: pool is full (%d)!\n", __func__, MAX_CYCLE_TIMERS);
94                 return;
95         }
96         avr_cycle_timer_insert(avr, when, timer, param);
97 }
98
99 void
100 avr_cycle_timer_register_usec(
101                 avr_t * avr,
102                 uint32_t when,
103                 avr_cycle_timer_t timer,
104                 void * param)
105 {
106         avr_cycle_timer_register(avr, avr_usec_to_cycles(avr, when), timer, param);
107 }
108
109 void
110 avr_cycle_timer_cancel(
111                 avr_t * avr,
112                 avr_cycle_timer_t timer,
113                 void * param)
114 {
115         avr_cycle_timer_pool_t * pool = &avr->cycle_timers;
116
117         for (int i = 0; i < pool->count; i++)
118                 if (pool->timer[i].timer == timer && pool->timer[i].param == param) {
119                         int cnt = pool->count - i - 1;
120                         DEBUG(printf("%s %2d when %7d %p/%p\n", __func__, i, (int)(pool->timer[i].when - avr->cycle), timer, param);)
121                         if (cnt)
122                                 memmove(&pool->timer[i], &pool->timer[i+1],
123                                                 cnt * sizeof(avr_cycle_timer_slot_t));
124                         pool->count--;
125                         DUMP(pool, "after");
126                         return;
127                 }
128 }
129
130 /*
131  * Check to see if a timer is present, if so, return the number (+1) of
132  * cycles left for it to fire, and if not present, return zero
133  */
134 avr_cycle_count_t
135 avr_cycle_timer_status(
136                 avr_t * avr,
137                 avr_cycle_timer_t timer,
138                 void * param)
139 {
140         avr_cycle_timer_pool_t * pool = &avr->cycle_timers;
141
142         for (int i = 0; i < pool->count; i++)
143                 if (pool->timer[i].timer == timer && pool->timer[i].param == param) {
144                         return 1 + (pool->timer[i].when - avr->cycle);
145                 }
146
147         return 0;
148 }
149
150 /*
151  * run through all the timers, call the ones that needs it,
152  * clear the ones that wants it, and calculate the next
153  * potential cycle we could sleep for...
154  */
155 avr_cycle_count_t
156 avr_cycle_timer_process(
157                 avr_t * avr)
158 {
159         avr_cycle_timer_pool_t * pool = &avr->cycle_timers;
160
161         if (!pool->count)
162                 return (avr_cycle_count_t)1000;
163
164         do {
165                 // copy it, since the array is volatile
166                 avr_cycle_timer_slot_t  timer = pool->timer[pool->count-1];
167                 avr_cycle_count_t when = timer.when;
168                 if (when > avr->cycle)
169                         return when - avr->cycle;
170                 pool->count--; // remove the top element now
171                 do {
172                         DEBUG(printf("%s %2d when %7d %p/%p\n", __func__, pool->count, (int)(when), timer.timer, timer.param););
173                         when = timer.timer(avr, when, timer.param);
174                 } while (when && when <= avr->cycle);
175                 if (when) {
176                         DEBUG(printf("%s %2d reschedule when %7d %p/%p\n", __func__, pool->count, (int)(when), timer.timer, timer.param);)
177                         avr_cycle_timer_insert(avr, when - avr->cycle, timer.timer, timer.param);
178                 }
179         } while (pool->count);
180
181         return (avr_cycle_count_t)1000;
182 }