all repos — mgba @ 3ec4c79e12d24b128bd24a440df8fbc350c65140

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 = GB_DMG_DIV_PERIOD;
15}
16
17int32_t GBTimerProcessEvents(struct GBTimer* timer, int32_t cycles) {
18	timer->eventDiff += cycles;
19	timer->nextEvent -= cycles;
20	if (timer->nextEvent <= 0) {
21		timer->nextDiv -= timer->eventDiff;
22		if (timer->nextDiv <= 0) {
23			++timer->p->memory.io[REG_DIV];
24			timer->nextDiv = GB_DMG_DIV_PERIOD;
25		}
26		timer->nextEvent = timer->nextDiv;
27
28		if (timer->nextTima != INT_MAX) {
29			timer->nextTima -= timer->eventDiff;
30			if (timer->nextTima <= 0) {
31				++timer->p->memory.io[REG_TIMA];
32				if (!timer->p->memory.io[REG_TIMA]) {
33					timer->p->memory.io[REG_TIMA] = timer->p->memory.io[REG_TMA];
34					timer->p->memory.io[REG_IF] |= (1 << GB_IRQ_TIMER);
35					GBUpdateIRQs(timer->p);
36				}
37				timer->nextTima = timer->timaPeriod;
38			}
39			if (timer->nextTima < timer->nextEvent) {
40				timer->nextEvent = timer->nextTima;
41			}
42		}
43
44		timer->eventDiff = 0;
45	}
46	return timer->nextEvent;
47}
48
49void GBTimerDivReset(struct GBTimer* timer) {
50	timer->p->memory.io[REG_DIV] = 0;
51	timer->nextDiv = timer->eventDiff + timer->p->cpu->cycles + GB_DMG_DIV_PERIOD;
52	timer->nextEvent = timer->nextTima;
53	if (timer->nextDiv < timer->nextEvent) {
54		timer->nextEvent = timer->nextDiv;
55	}
56}
57
58uint8_t GBTimerUpdateTAC(struct GBTimer* timer, GBRegisterTAC tac) {
59	if (GBRegisterTACIsRun(tac)) {
60		switch (GBRegisterTACGetClock(tac)) {
61		case 0:
62			timer->timaPeriod = 1024;
63			break;
64		case 1:
65			timer->timaPeriod = 16;
66			break;
67		case 2:
68			timer->timaPeriod = 64;
69			break;
70		case 3:
71			timer->timaPeriod = 256;
72			break;
73		}
74		GBTimerUpdateTIMA(timer);
75	} else {
76		timer->nextTima = INT_MAX;
77	}
78	return tac;
79}
80
81void GBTimerUpdateTIMA(struct GBTimer* timer) {
82	timer->nextTima = timer->eventDiff + timer->p->cpu->cycles + timer->timaPeriod;
83	if (timer->eventDiff + timer->timaPeriod < timer->nextEvent) {
84		timer->nextEvent = timer->eventDiff + timer->timaPeriod;
85		if (timer->nextEvent < timer->p->cpu->nextEvent) {
86			timer->p->cpu->nextEvent = timer->nextEvent;
87		}
88	}
89}