all repos — mgba @ 1a0e44c014ad34bea30d237d27015d82d02cda4b

mGBA Game Boy Advance Emulator

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}