summaryrefslogtreecommitdiff
path: root/sys/src/games/gb/ev.c
blob: abbecf34f62901dd4ac934f48eb60e03fea69234 (plain)
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;
}