all repos — mgba @ 239921966332f0a749ff35f5daa17f06132643ab

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	if (timer->eventDiff + GB_DMG_DIV_PERIOD < timer->nextEvent) {
53		timer->nextEvent = timer->eventDiff + GB_DMG_DIV_PERIOD;
54		if (timer->nextEvent < timer->p->cpu->nextEvent) {
55			timer->p->cpu->nextEvent = timer->nextEvent;
56		}
57	}
58}
59
60uint8_t GBTimerUpdateTAC(struct GBTimer* timer, GBRegisterTAC tac) {
61	if (GBRegisterTACIsRun(tac)) {
62		switch (GBRegisterTACGetClock(tac)) {
63		case 0:
64			timer->timaPeriod = 1024;
65			break;
66		case 1:
67			timer->timaPeriod = 16;
68			break;
69		case 2:
70			timer->timaPeriod = 64;
71			break;
72		case 3:
73			timer->timaPeriod = 256;
74			break;
75		}
76		GBTimerUpdateTIMA(timer);
77	} else {
78		timer->nextTima = INT_MAX;
79	}
80	return tac;
81}
82
83void GBTimerUpdateTIMA(struct GBTimer* timer) {
84	timer->nextTima = timer->eventDiff + timer->p->cpu->cycles + timer->timaPeriod;
85	if (timer->eventDiff + timer->timaPeriod < timer->nextEvent) {
86		timer->nextEvent = timer->eventDiff + timer->timaPeriod;
87		if (timer->nextEvent < timer->p->cpu->nextEvent) {
88			timer->p->cpu->nextEvent = timer->nextEvent;
89		}
90	}
91}