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}