]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/gba/ev.c
games/mahjongg: off by one in bmatch(), fix hint() redraw (thanks Kenji)
[plan9front.git] / sys / src / games / gba / ev.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "dat.h"
5 #include "fns.h"
6
7 typedef struct {
8         u16int *cnt;
9         Event;
10         u16int val;
11         int clock;
12         u8int i, sh, snd;
13 } Timer;
14
15 typedef struct fifo fifo;
16 struct fifo {
17         u32int d[8];
18         u8int head, level, headpos;
19 };
20 fifo sndfifo[2];
21
22 Event *elist;
23 Timer timers[4];
24 Event evhblank;
25 extern Event evsamp;
26 Event *events[NEVENT] = {&timers[0].Event, &timers[1].Event, &timers[2].Event, &timers[3].Event, &evhblank, &evsamp};
27
28 Var evvars[] = {
29         VAR(clock),
30         ARR(sndfifo[0].d), VAR(sndfifo[0].head), VAR(sndfifo[0].level), VAR(sndfifo[0].headpos),
31         ARR(sndfifo[1].d), VAR(sndfifo[1].head), VAR(sndfifo[1].level), VAR(sndfifo[1].headpos),
32         VAR(timers[0].val), VAR(timers[0].clock), VAR(timers[0].sh), VAR(timers[0].snd),
33         VAR(timers[1].val), VAR(timers[1].clock), VAR(timers[1].sh), VAR(timers[1].snd),
34         VAR(timers[2].val), VAR(timers[2].clock), VAR(timers[2].sh), VAR(timers[2].snd),
35         VAR(timers[3].val), VAR(timers[3].clock), VAR(timers[3].sh), VAR(timers[3].snd),
36         {nil, 0, 0},
37 };
38
39 void
40 addevent(Event *ev, int time)
41 {
42         Event **p, *e;
43         int t;
44         
45         t = time;
46         for(p = &elist; (e = *p) != nil; p = &e->next){
47                 if(t < e->time){
48                         e->time -= t;
49                         break;
50                 }
51                 t -= e->time;
52         }
53         ev->next = e;
54         ev->time = t;
55         *p = ev;
56 }
57
58 void
59 delevent(Event *ev)
60 {
61         Event **p, *e;
62         
63         for(p = &elist; (e = *p) != nil; p = &e->next)
64                 if(e == ev){
65                         *p = e->next;
66                         if(e->next != nil)
67                                 e->next->time += e->time;
68                         return;
69                 }
70 }
71
72 void
73 popevent(void)
74 {
75         Event *e;
76         int t;
77         
78         do{
79                 e = elist;
80                 t = e->time;
81                 elist = e->next;
82                 e->f(e->aux);
83         }while((elist->time += t) <= 0);
84 }
85
86
87 void
88 fifoput(int i, u32int s)
89 {
90         fifo *f;
91         
92         f = sndfifo + i;
93         if(f->level < 8)
94                 f->d[(f->head + f->level++) & 7] = s;
95 }
96
97 void
98 fifotimer(int b, int n)
99 {
100         fifo *f;
101         int i, j;
102         extern s8int snddma[2];
103         
104         for(i = 0; i < 2; i++){
105                 if((b & 1<<i) == 0)
106                         continue;
107                 f = &sndfifo[i];
108                 for(j = 0; j < n && f->level > 0; j++){
109                         snddma[i] = f->d[f->head] & 0xff;
110                         f->d[f->head] >>= 8;
111                         if(++f->headpos == 4){
112                                 f->head = (f->head + 1) & 7;
113                                 f->level--;
114                                 f->headpos = 0;
115                         }
116                 }
117                 if(f->level <= 4)
118                         dmastart(DMASOUND);
119         }
120 }
121
122 void
123 soundcnth(u16int v)
124 {
125         timers[0].snd = 0;
126         timers[1].snd = 0;
127         if((v & 3<<8) != 0)
128                 timers[(v >> 10) & 1].snd |= 1;
129         if((v & 3<<12) != 0)
130                 timers[(v >> 14) & 1].snd |= 2;
131         if((v & 1<<11) != 0){
132                 sndfifo[0].level = 0;
133                 sndfifo[0].head = 0;
134                 sndfifo[0].headpos = 0;
135         }
136         if((v & 1<<15) != 0){
137                 sndfifo[1].level = 0;
138                 sndfifo[1].head = 0;
139                 sndfifo[1].headpos = 0;
140         }
141 }
142
143 u16int
144 timerget(int i)
145 {
146         Timer *t;
147         
148         t = &timers[i];
149         if((*t->cnt & (COUNTUP|TIMERON)) != TIMERON)
150                 return t->val;
151         return t->val + (clock - t->clock >> t->sh);
152 }
153
154 void
155 timerset(int i, u16int nc)
156 {
157         u32int v;
158         u16int oc;
159         Timer *t;
160         
161         t = &timers[i];
162         oc = *t->cnt;
163         if((oc & (PRESC|COUNTUP|TIMERON)) == (nc & (PRESC|COUNTUP|TIMERON)))
164                 return;
165         if((oc & (COUNTUP|TIMERON)) == TIMERON){
166                 v = t->val + (clock - t->clock >> t->sh);
167                 delevent(t);
168         }else
169                 v = t->val;
170         if((oc & TIMERON) == 0 && (nc & TIMERON) != 0)
171                 v = t->cnt[-1];
172         if((nc & 3) != 0)
173                 t->sh = 4 + (nc & 3) * 2;
174         else
175                 t->sh = 0;
176         t->val = v;
177         t->clock = clock & -(1 << t->sh);
178         if((nc & (COUNTUP|TIMERON)) == TIMERON)
179                 addevent(t, (0x10000 - t->val << t->sh) + (-clock & (1 << t->sh) - 1));
180 }
181
182 void
183 timertick(void *aux)
184 {
185         Timer *t;
186         u32int v;
187         int to;
188         ulong clock0;
189         
190         t = aux;
191         clock0 = clock + t->time;
192         t->clock = clock0 & -(1 << t->sh);
193         t->val = -t->time >> t->sh;
194         do{
195                 to = 0;
196                 do{
197                         t->val = v = t->val + t->cnt[-1];
198                         to++;
199                 }while(v >= 0x10000);
200                 if(t == aux)
201                         addevent(t, (0x10000 - t->val << t->sh) + (-clock0 & (1 << t->sh) - 1));
202                 if((*t->cnt & TIMERIRQ) != 0)
203                         setif(IRQTIM0 << t->i);
204                 if(t->snd)
205                         fifotimer(t->snd, to);
206                 if(++t >= timers + 4 || (*t->cnt & (COUNTUP | TIMERON)) != (COUNTUP|TIMERON))
207                         break;
208                 t->val = v = t->val + to;
209         }while(v >= 0x10000);
210 }
211
212 void
213 eventinit(void)
214 {
215         int i;
216         extern void hblanktick(void *);
217
218         for(i = 0; i < 4; i++){
219                 timers[i].f = timertick;
220                 timers[i].aux = &timers[i];
221                 timers[i].i = i;
222                 timers[i].cnt = &reg[TM0CNTH + i * 2];
223         }
224         evhblank.f = hblanktick;
225         addevent(&evhblank, 240*4);
226 }