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#include "gb/serialize.h"
11
12void GBTimerReset(struct GBTimer* timer) {
13 timer->nextDiv = GB_DMG_DIV_PERIOD; // TODO: GBC differences
14 timer->nextTima = INT_MAX;
15 timer->nextEvent = GB_DMG_DIV_PERIOD;
16 timer->eventDiff = 0;
17 timer->timaPeriod = 1024;
18}
19
20int32_t GBTimerProcessEvents(struct GBTimer* timer, int32_t cycles) {
21 timer->eventDiff += cycles;
22 timer->nextEvent -= cycles;
23 if (timer->nextEvent <= 0) {
24 timer->nextDiv -= timer->eventDiff;
25 if (timer->nextDiv <= 0) {
26 ++timer->p->memory.io[REG_DIV];
27 timer->nextDiv = GB_DMG_DIV_PERIOD;
28 }
29 timer->nextEvent = timer->nextDiv;
30
31 if (timer->nextTima != INT_MAX) {
32 timer->nextTima -= timer->eventDiff;
33 if (timer->nextTima <= 0) {
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 timer->nextTima = timer->timaPeriod - 4;
39 } else {
40 ++timer->p->memory.io[REG_TIMA];
41 if (!timer->p->memory.io[REG_TIMA]) {
42 timer->nextTima = 4;
43 } else {
44 timer->nextTima = timer->timaPeriod;
45 }
46 }
47 }
48 if (timer->nextTima < timer->nextEvent) {
49 timer->nextEvent = timer->nextTima;
50 }
51 }
52
53 timer->eventDiff = 0;
54 }
55 return timer->nextEvent;
56}
57
58void GBTimerDivReset(struct GBTimer* timer) {
59 timer->p->memory.io[REG_DIV] = 0;
60 timer->nextDiv = timer->eventDiff + timer->p->cpu->cycles + GB_DMG_DIV_PERIOD;
61 if (timer->nextDiv - timer->eventDiff < timer->nextEvent) {
62 timer->nextEvent = timer->nextDiv - timer->eventDiff;
63 if (timer->nextEvent < timer->p->cpu->nextEvent) {
64 timer->p->cpu->nextEvent = timer->nextEvent;
65 }
66 }
67}
68
69uint8_t GBTimerUpdateTAC(struct GBTimer* timer, GBRegisterTAC tac) {
70 if (GBRegisterTACIsRun(tac)) {
71 switch (GBRegisterTACGetClock(tac)) {
72 case 0:
73 timer->timaPeriod = 1024;
74 break;
75 case 1:
76 timer->timaPeriod = 16;
77 break;
78 case 2:
79 timer->timaPeriod = 64;
80 break;
81 case 3:
82 timer->timaPeriod = 256;
83 break;
84 }
85 GBTimerUpdateTIMA(timer);
86 } else {
87 timer->nextTima = INT_MAX;
88 }
89 return tac;
90}
91
92void GBTimerUpdateTIMA(struct GBTimer* timer) {
93 timer->nextTima = timer->eventDiff + timer->p->cpu->cycles + timer->timaPeriod;
94 if (timer->nextTima - timer->eventDiff < timer->nextEvent) {
95 timer->nextEvent = timer->nextTima - timer->eventDiff;
96 if (timer->nextEvent < timer->p->cpu->nextEvent) {
97 timer->p->cpu->nextEvent = timer->nextEvent;
98 }
99 }
100}
101
102void GBTimerSerialize(const struct GBTimer* timer, struct GBSerializedState* state) {
103 STORE_32LE(timer->nextEvent, 0, &state->timer.nextEvent);
104 STORE_32LE(timer->eventDiff, 0, &state->timer.eventDiff);
105 STORE_32LE(timer->nextDiv, 0, &state->timer.nextDiv);
106 STORE_32LE(timer->nextTima, 0, &state->timer.nextTima);
107 STORE_32LE(timer->timaPeriod, 0, &state->timer.timaPeriod);
108}
109
110void GBTimerDeserialize(struct GBTimer* timer, const struct GBSerializedState* state) {
111 LOAD_32LE(timer->nextEvent, 0, &state->timer.nextEvent);
112 LOAD_32LE(timer->eventDiff, 0, &state->timer.eventDiff);
113 LOAD_32LE(timer->nextDiv, 0, &state->timer.nextDiv);
114 LOAD_32LE(timer->nextTima, 0, &state->timer.nextTima);
115 LOAD_32LE(timer->timaPeriod, 0, &state->timer.timaPeriod);
116}