1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
#include <u.h>
#include <libc.h>
#include <thread.h>
#include "dat.h"
#include "fns.h"
Event evhblank, evtimer, evenv;
extern Event evsamp, chev[4];
extern Event evse;
Event *events[NEVENT] = {&evhblank, &evtimer, &evenv, &evsamp, &chev[0], &chev[1], &chev[2], &chev[3], &evse};
Event *elist;
static int timshtab[4] = {10, 4, 6, 8}, timsh;
ulong timclock;
Var evvars[] = {VAR(timsh), VAR(timclock), {nil, 0, 0}};
void
addevent(Event *ev, int time)
{
Event **p, *e;
int t;
assert(time >= 0);
t = time;
for(p = &elist; (e = *p) != nil; p = &e->next){
if(t < e->time){
e->time -= t;
break;
}
t -= e->time;
}
ev->next = e;
ev->time = t;
*p = ev;
}
void
delevent(Event *ev)
{
Event **p, *e;
for(p = &elist; (e = *p) != nil; p = &e->next)
if(e == ev){
*p = e->next;
if(e->next != nil)
e->next->time += e->time;
return;
}
}
void
popevent(void)
{
Event *e;
int t;
do{
e = elist;
t = e->time;
elist = e->next;
e->f(e->aux);
}while((elist->time += t) <= 0);
}
void
timerset(void)
{
timclock = clock & -(1<<timsh);
if((reg[TAC] & 4) != 0){
delevent(&evtimer);
addevent(&evtimer, 0x100 - reg[TIMA] << timsh);// | -clock & (1<<timsh)-1);
}
}
void
timertac(u8int n, int t)
{
if((reg[TAC] & 7) == (n & 7) && !t)
return;
if((reg[TAC] & 4) != 0){
delevent(&evtimer);
reg[TIMA] += clock - timclock >> timsh;
}
timclock = clock & -(1<<timsh);
timsh = timshtab[n & 3];
if((mode & TURBO) == 0)
timsh++;
if((n & 4) != 0)
addevent(&evtimer, 0x100 - reg[TIMA] << timsh | -clock & (1<<timsh)-1);
}
u8int
timread(void)
{
if((reg[TAC] & 4) == 0)
return reg[TIMA];
return reg[TIMA] + (clock - timclock >> timsh);
}
void
timertick(void *)
{
reg[TIMA] = reg[TMA];
addevent(&evtimer, 0x100 - reg[TIMA] << timsh);
reg[IF] |= IRQTIM;
}
void
eventinit(void)
{
extern void hblanktick(void *);
extern void envtick(void *);
extern void wavetick(void *);
extern void chantick(void *);
evhblank.f = hblanktick;
addevent(&evhblank, 240*4);
evtimer.f = timertick;
evenv.f = envtick;
addevent(&evenv, FREQ / 512);
chev[0].f = chantick;
chev[1].f = chantick;
chev[2].f = chantick;
chev[3].f = chantick;
}
|