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