src/gba/timer.c (view raw)
1/* Copyright (c) 2013-2018 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 <mgba/internal/gba/timer.h>
7
8#include <mgba/internal/gba/gba.h>
9#include <mgba/internal/gba/io.h>
10
11#define TIMER_RELOAD_DELAY 0
12#define TIMER_STARTUP_DELAY 2
13
14#define REG_TMCNT_LO(X) (REG_TM0CNT_LO + ((X) << 2))
15
16static void GBATimerIrq(struct GBA* gba, int timerId, uint32_t cyclesLate) {
17 struct GBATimer* timer = &gba->timers[timerId];
18 if (GBATimerFlagsIsDoIrq(timer->flags)) {
19 GBARaiseIRQ(gba, IRQ_TIMER0 + timerId, cyclesLate);
20 }
21}
22
23void GBATimerUpdate(struct mTiming* timing, struct GBATimer* timer, uint16_t* io, uint32_t cyclesLate) {
24 if (GBATimerFlagsIsCountUp(timer->flags)) {
25 *io = timer->reload;
26 } else {
27 GBATimerUpdateRegisterInternal(timer, timing, io, TIMER_RELOAD_DELAY + cyclesLate);
28 }
29}
30
31static void GBATimerUpdateAudio(struct GBA* gba, int timerId, uint32_t cyclesLate) {
32 if (!gba->audio.enable) {
33 return;
34 }
35 if ((gba->audio.chALeft || gba->audio.chARight) && gba->audio.chATimer == timerId) {
36 GBAAudioSampleFIFO(&gba->audio, 0, cyclesLate);
37 }
38
39 if ((gba->audio.chBLeft || gba->audio.chBRight) && gba->audio.chBTimer == timerId) {
40 GBAAudioSampleFIFO(&gba->audio, 1, cyclesLate);
41 }
42}
43
44bool GBATimerUpdateCountUp(struct mTiming* timing, struct GBATimer* nextTimer, uint16_t* io, uint32_t cyclesLate) {
45 if (GBATimerFlagsIsCountUp(nextTimer->flags)) { // TODO: Does this increment while disabled?
46 ++*io;
47 if (!*io && GBATimerFlagsIsEnable(nextTimer->flags)) {
48 GBATimerUpdate(timing, nextTimer, io, cyclesLate);
49 return true;
50 }
51 }
52 return false;
53}
54
55static void GBATimerUpdate0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
56 struct GBA* gba = context;
57 GBATimerUpdateAudio(gba, 0, cyclesLate);
58 GBATimerUpdate(timing, &gba->timers[0], &gba->memory.io[REG_TM0CNT_LO >> 1], cyclesLate);
59 GBATimerIrq(gba, 0, cyclesLate);
60 if (GBATimerUpdateCountUp(timing, &gba->timers[1], &gba->memory.io[REG_TM1CNT_LO >> 1], cyclesLate)) {
61 GBATimerIrq(gba, 1, cyclesLate);
62 }
63}
64
65static void GBATimerUpdate1(struct mTiming* timing, void* context, uint32_t cyclesLate) {
66 struct GBA* gba = context;
67 GBATimerUpdateAudio(gba, 1, cyclesLate);
68 GBATimerUpdate(timing, &gba->timers[1], &gba->memory.io[REG_TM1CNT_LO >> 1], cyclesLate);
69 GBATimerIrq(gba, 1, cyclesLate);
70 if (GBATimerUpdateCountUp(timing, &gba->timers[2], &gba->memory.io[REG_TM2CNT_LO >> 1], cyclesLate)) {
71 GBATimerIrq(gba, 2, cyclesLate);
72 }
73}
74
75static void GBATimerUpdate2(struct mTiming* timing, void* context, uint32_t cyclesLate) {
76 struct GBA* gba = context;
77 GBATimerUpdate(timing, &gba->timers[2], &gba->memory.io[REG_TM2CNT_LO >> 1], cyclesLate);
78 GBATimerIrq(gba, 2, cyclesLate);
79 if (GBATimerUpdateCountUp(timing, &gba->timers[3], &gba->memory.io[REG_TM3CNT_LO >> 1], cyclesLate)) {
80 GBATimerIrq(gba, 3, cyclesLate);
81 }
82}
83
84static void GBATimerUpdate3(struct mTiming* timing, void* context, uint32_t cyclesLate) {
85 struct GBA* gba = context;
86 GBATimerUpdate(timing, &gba->timers[3], &gba->memory.io[REG_TM3CNT_LO >> 1], cyclesLate);
87 GBATimerIrq(gba, 3, cyclesLate);
88}
89
90void GBATimerInit(struct GBA* gba) {
91 memset(gba->timers, 0, sizeof(gba->timers));
92 gba->timers[0].event.name = "GBA Timer 0";
93 gba->timers[0].event.callback = GBATimerUpdate0;
94 gba->timers[0].event.context = gba;
95 gba->timers[0].event.priority = 0x20;
96 gba->timers[1].event.name = "GBA Timer 1";
97 gba->timers[1].event.callback = GBATimerUpdate1;
98 gba->timers[1].event.context = gba;
99 gba->timers[1].event.priority = 0x21;
100 gba->timers[2].event.name = "GBA Timer 2";
101 gba->timers[2].event.callback = GBATimerUpdate2;
102 gba->timers[2].event.context = gba;
103 gba->timers[2].event.priority = 0x22;
104 gba->timers[3].event.name = "GBA Timer 3";
105 gba->timers[3].event.callback = GBATimerUpdate3;
106 gba->timers[3].event.context = gba;
107 gba->timers[3].event.priority = 0x23;
108}
109
110void GBATimerUpdateRegister(struct GBA* gba, int timer, int32_t cyclesLate) {
111 struct GBATimer* currentTimer = &gba->timers[timer];
112 if (GBATimerFlagsIsEnable(currentTimer->flags) && !GBATimerFlagsIsCountUp(currentTimer->flags)) {
113 int32_t prefetchSkew = cyclesLate;
114 if (gba->memory.lastPrefetchedPc > (uint32_t) gba->cpu->gprs[ARM_PC]) {
115 prefetchSkew += ((gba->memory.lastPrefetchedPc - gba->cpu->gprs[ARM_PC]) * gba->cpu->memory.activeSeqCycles16) / WORD_SIZE_THUMB;
116 }
117 GBATimerUpdateRegisterInternal(currentTimer, &gba->timing, &gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1], prefetchSkew);
118 }
119}
120
121void GBATimerUpdateRegisterInternal(struct GBATimer* timer, struct mTiming* timing, uint16_t* io, int32_t skew) {
122 if (!GBATimerFlagsIsEnable(timer->flags) || GBATimerFlagsIsCountUp(timer->flags)) {
123 return;
124 }
125
126 // Align timer
127 int prescaleBits = GBATimerFlagsGetPrescaleBits(timer->flags);
128 int32_t currentTime = mTimingCurrentTime(timing) - skew;
129 int32_t tickMask = (1 << prescaleBits) - 1;
130 currentTime &= ~tickMask;
131
132 // Update register
133 int32_t tickIncrement = currentTime - timer->lastEvent;
134 timer->lastEvent = currentTime;
135 tickIncrement >>= prescaleBits;
136 tickIncrement += *io;
137 *io = tickIncrement;
138 while (tickIncrement >= 0x10000) {
139 tickIncrement -= 0x10000 - timer->reload;
140 }
141 *io = tickIncrement;
142
143 // Schedule next update
144 tickIncrement = (0x10000 - tickIncrement) << prescaleBits;
145 currentTime += tickIncrement;
146 currentTime &= ~tickMask;
147 currentTime -= mTimingCurrentTime(timing);
148 mTimingDeschedule(timing, &timer->event);
149 mTimingSchedule(timing, &timer->event, currentTime);
150}
151
152void GBATimerWriteTMCNT_LO(struct GBATimer* timer, uint16_t reload) {
153 timer->reload = reload;
154}
155
156void GBATimerWriteTMCNT_HI(struct GBATimer* timer, struct mTiming* timing, uint16_t* io, uint16_t control) {
157 GBATimerUpdateRegisterInternal(timer, timing, io, 0);
158
159 unsigned oldPrescale = GBATimerFlagsGetPrescaleBits(timer->flags);
160 unsigned prescaleBits;
161 switch (control & 0x0003) {
162 case 0x0000:
163 prescaleBits = 0;
164 break;
165 case 0x0001:
166 prescaleBits = 6;
167 break;
168 case 0x0002:
169 prescaleBits = 8;
170 break;
171 case 0x0003:
172 prescaleBits = 10;
173 break;
174 }
175 prescaleBits += timer->forcedPrescale;
176 timer->flags = GBATimerFlagsSetPrescaleBits(timer->flags, prescaleBits);
177 timer->flags = GBATimerFlagsTestFillCountUp(timer->flags, timer > 0 && (control & 0x0004));
178 timer->flags = GBATimerFlagsTestFillDoIrq(timer->flags, control & 0x0040);
179 bool wasEnabled = GBATimerFlagsIsEnable(timer->flags);
180 timer->flags = GBATimerFlagsTestFillEnable(timer->flags, control & 0x0080);
181 if (!wasEnabled && GBATimerFlagsIsEnable(timer->flags)) {
182 mTimingDeschedule(timing, &timer->event);
183 *io = timer->reload;
184 int32_t tickMask = (1 << prescaleBits) - 1;
185 timer->lastEvent = (mTimingCurrentTime(timing) - TIMER_STARTUP_DELAY) & ~tickMask;
186 GBATimerUpdateRegisterInternal(timer, timing, io, TIMER_STARTUP_DELAY);
187 } else if (wasEnabled && !GBATimerFlagsIsEnable(timer->flags)) {
188 mTimingDeschedule(timing, &timer->event);
189 } else if (GBATimerFlagsIsEnable(timer->flags) && GBATimerFlagsGetPrescaleBits(timer->flags) != oldPrescale && !GBATimerFlagsIsCountUp(timer->flags)) {
190 mTimingDeschedule(timing, &timer->event);
191 int32_t tickMask = (1 << prescaleBits) - 1;
192 timer->lastEvent = (mTimingCurrentTime(timing) - TIMER_STARTUP_DELAY) & ~tickMask;
193 GBATimerUpdateRegisterInternal(timer, timing, io, TIMER_STARTUP_DELAY);
194 }
195}