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