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}