all repos — mgba @ 06e0908642eb0e6c4d151c276f9976d7b1190862

mGBA Game Boy Advance Emulator

src/gb/timer.c (view raw)

 1/* Copyright (c) 2013-2016 Jeffrey Pfau
 2 *
 3 * This Source Code Form is subject to the terms of the Mozilla Public
 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 6#include "timer.h"
 7
 8#include "gb/gb.h"
 9#include "gb/io.h"
10
11void GBTimerReset(struct GBTimer* timer) {
12	timer->nextDiv = GB_DMG_DIV_PERIOD; // TODO: GBC differences
13	timer->nextTima = INT_MAX;
14	timer->nextEvent = INT_MAX;
15}
16
17int32_t GBTimerProcessEvents(struct GBTimer* timer, int32_t cycles) {
18	if (timer->nextEvent == INT_MAX) {
19		return INT_MAX;
20	}
21	timer->eventDiff += cycles;
22	timer->nextEvent -= cycles;
23	if (timer->nextEvent < 0) {
24		timer->nextDiv -= timer->eventDiff;
25		if (timer->nextDiv <= 0) {
26			++timer->p->memory.io[REG_DIV];
27			timer->nextDiv = GB_DMG_DIV_PERIOD;
28		}
29		timer->nextEvent = timer->nextDiv;
30
31		if (timer->nextTima != INT_MAX) {
32			timer->nextTima -= timer->eventDiff;
33			if (timer->nextTima <= 0) {
34				++timer->p->memory.io[REG_TIMA];
35				if (!timer->p->memory.io[REG_TIMA]) {
36					timer->p->memory.io[REG_TIMA] = timer->p->memory.io[REG_TMA];
37					timer->p->memory.io[REG_IF] |= (1 << GB_IRQ_TIMER);
38					GBUpdateIRQs(timer->p);
39				}
40				timer->nextTima = timer->timaPeriod;
41			}
42			if (timer->nextTima < timer->nextEvent) {
43				timer->nextEvent = timer->nextTima;
44			}
45		}
46
47		timer->eventDiff = 0;
48	}
49	return timer->nextEvent;
50}
51
52void GBTimerDivReset(struct GBTimer* timer) {
53	timer->p->memory.io[REG_DIV] = 0;
54	// TODO: Do we need to reset the event?
55}
56
57uint8_t GBTimerUpdateTAC(struct GBTimer* timer, GBRegisterTAC tac) {
58	if (GBRegisterTACIsRun(tac)) {
59		switch (GBRegisterTACGetClock(tac)) {
60		case 0:
61			timer->timaPeriod = 1024;
62			break;
63		case 1:
64			timer->timaPeriod = 16;
65			break;
66		case 2:
67			timer->timaPeriod = 64;
68			break;
69		case 3:
70			timer->timaPeriod = 256;
71			break;
72		}
73		timer->nextTima = timer->eventDiff + timer->timaPeriod;
74		if (timer->nextTima < timer->nextEvent) {
75			timer->nextEvent = timer->nextTima;
76			if (timer->nextEvent < timer->p->cpu->nextEvent) {
77				timer->p->cpu->nextEvent = timer->nextEvent;
78			}
79		}
80	} else {
81		timer->nextTima = INT_MAX;
82	}
83	return tac;
84}