<commit_before>/* Copyright (c) 2013-2018 <NAME>
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/gba/timer.h>

#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/io.h>

#define TIMER_IRQ_DELAY 7
#define TIMER_RELOAD_DELAY 0
#define TIMER_STARTUP_DELAY 2

#define REG_TMCNT_LO(X) (REG_TM0CNT_LO + (X << 2))

static void GBATimerIrq(struct GBA* gba, int timerId) {
	struct GBATimer* timer = &gba->timers[timerId];
	if (GBATimerFlagsIsIrqPending(timer->flags)) {
		timer->flags = GBATimerFlagsClearIrqPending(timer->flags);
		GBARaiseIRQ(gba, IRQ_TIMER0 + timerId);
	}
}

static void GBATimerIrq0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
	UNUSED(timing);
	UNUSED(cyclesLate);
	GBATimerIrq(context, 0);
}

static void GBATimerIrq1(struct mTiming* timing, void* context, uint32_t cyclesLate) {
	UNUSED(timing);
	UNUSED(cyclesLate);
	GBATimerIrq(context, 1);
}

static void GBATimerIrq2(struct mTiming* timing, void* context, uint32_t cyclesLate) {
	UNUSED(timing);
	UNUSED(cyclesLate);
	GBATimerIrq(context, 2);
}

static void GBATimerIrq3(struct mTiming* timing, void* context, uint32_t cyclesLate) {
	UNUSED(timing);
	UNUSED(cyclesLate);
	GBATimerIrq(context, 3);
}

static void GBATimerUpdate(struct GBA* gba, int timerId, uint32_t cyclesLate) {
	struct GBATimer* timer = &gba->timers[timerId];
	GBATimerUpdateRegister(gba, timerId, TIMER_RELOAD_DELAY + cyclesLate);

	if (GBATimerFlagsIsDoIrq(timer->flags)) {
		timer->flags = GBATimerFlagsFillIrqPending(timer->flags);
		if (!mTimingIsScheduled(&gba->timing, &timer->irq)) {
			mTimingSchedule(&gba->timing, &timer->irq, TIMER_IRQ_DELAY - cyclesLate);
		}
	}

	if (gba->audio.enable && timerId < 2) {
		if ((gba->audio.chALeft || gba->audio.chARight) && gba->audio.chATimer == timerId) {
			GBAAudioSampleFIFO(&gba->audio, 0, cyclesLate);
		}

		if ((gba->audio.chBLeft || gba->audio.chBRight) && gba->audio.chBTimer == timerId) {
			GBAAudioSampleFIFO(&gba->audio, 1, cyclesLate);
		}
	}

	if (timerId < 3) {
		struct GBATimer* nextTimer = &gba->timers[timerId + 1];
		if (GBATimerFlagsIsCountUp(nextTimer->flags)) { // TODO: Does this increment while disabled?
			++gba->memory.io[(REG_TM1CNT_LO >> 1) + (timerId << 1)];
			if (!gba->memory.io[(REG_TM1CNT_LO >> 1) + (timerId << 1)] && GBATimerFlagsIsEnable(nextTimer->flags)) {
				GBATimerUpdate(gba, timerId + 1, cyclesLate);
			}
		}
	}
}

static void GBATimerUpdate0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
	UNUSED(timing);
	GBATimerUpdate(context, 0, cyclesLate);
}

static void GBATimerUpdate1(struct mTiming* timing, void* context, uint32_t cyclesLate) {<commit_msg>GBA Timer: Fix count-up timers (fixes #1091)<commit_after>/* Copyright (c) 2013-2018 <NAME>
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/gba/timer.h>

#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/io.h>

#define TIMER_IRQ_DELAY 7
#define TIMER_RELOAD_DELAY 0
#define TIMER_STARTUP_DELAY 2

#define REG_TMCNT_LO(X) (REG_TM0CNT_LO + ((X) << 2))

static void GBATimerIrq(struct GBA* gba, int timerId) {
	struct GBATimer* timer = &gba->timers[timerId];
	if (GBATimerFlagsIsIrqPending(timer->flags)) {
		timer->flags = GBATimerFlagsClearIrqPending(timer->flags);
		GBARaiseIRQ(gba, IRQ_TIMER0 + timerId);
	}
}

static void GBATimerIrq0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
	UNUSED(timing);
	UNUSED(cyclesLate);
	GBATimerIrq(context, 0);
}

static void GBATimerIrq1(struct mTiming* timing, void* context, uint32_t cyclesLate) {
	UNUSED(timing);
	UNUSED(cyclesLate);
	GBATimerIrq(context, 1);
}

static void GBATimerIrq2(struct mTiming* timing, void* context, uint32_t cyclesLate) {
	UNUSED(timing);
	UNUSED(cyclesLate);
	GBATimerIrq(context, 2);
}

static void GBATimerIrq3(struct mTiming* timing, void* context, uint32_t cyclesLate) {
	UNUSED(timing);
	UNUSED(cyclesLate);
	GBATimerIrq(context, 3);
}

static void GBATimerUpdate(struct GBA* gba, int timerId, uint32_t cyclesLate) {
	struct GBATimer* timer = &gba->timers[timerId];
	if (GBATimerFlagsIsCountUp(timer->flags)) {
		gba->memory.io[REG_TMCNT_LO(timerId) >> 1] = timer->reload;
	} else {
		GBATimerUpdateRegister(gba, timerId, TIMER_RELOAD_DELAY + cyclesLate);
	}

	if (GBATimerFlagsIsDoIrq(timer->flags)) {
		timer->flags = GBATimerFlagsFillIrqPending(timer->flags);
		if (!mTimingIsScheduled(&gba->timing, &timer->irq)) {
			mTimingSchedule(&gba->timing, &timer->irq, TIMER_IRQ_DELAY - cyclesLate);
		}
	}

	if (gba->audio.enable && timerId < 2) {
		if ((gba->audio.chALeft || gba->audio.chARight) && gba->audio.chATimer == timerId) {
			GBAAudioSampleFIFO(&gba->audio, 0, cyclesLate);
		}

		if ((gba->audio.chBLeft || gba->audio.chBRight) && gba->audio.chBTimer == timerId) {
			GBAAudioSampleFIFO(&gba->audio, 1, cyclesLate);
		}
	}

	if (timerId < 3) {
		struct GBATimer* nextTimer = &gba->timers[timerId + 1];
		if (GBATimerFlagsIsCountUp(nextTimer->flags)) { // TODO: Does this increment while disabled?
			++gba->memory.io[REG_TMCNT_LO(timerId + 1) >> 1];
			if (!gba->memory.io[REG_TMCNT_LO(timerId + 1) >> 1] && GBATimerFlagsIsEnable(nextTimer->flags)) {
				GBATimerUpdate(gba, timerId + 1, cyclesLate);
			}
		}
	}
}

static void GBATimerUpdate0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
	UNUSED(timing);
	GBATimerUpdate(context, 0, cyclesLate);
}

static void GBATimerUpdate1(struct mTiming* timing, void* context, uint32_t cyclesLate) {
{'fraction_non_alphanumeric': 0.14211438474870017, 'fraction_numerical': 0.019584055459272096, 'mean_word_length': 5.245670995670996, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 76, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6134348', 'n_tokens_mistral': 2410, 'n_tokens_neox': 2239, 'n_words': 468}