all repos — mgba @ 8071a5250546e5975eb98fa7c47de88021765964

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