all repos — mgba @ cf8868d5cb5cfd8244713328f96d8fdd814f1f83

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