all repos — mgba @ 8b04eca8f024debbb10ec942af3e47a172ac09b0

mGBA Game Boy Advance Emulator

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