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