all repos — mgba @ 2f5fb2265992581712525dad2b47fcad0a5c0372

mGBA Game Boy Advance Emulator

src/core/timing.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/core/timing.h>
  7
  8void mTimingInit(struct mTiming* timing, int32_t* relativeCycles, int32_t* nextEvent) {
  9	timing->root = NULL;
 10	timing->reroot = NULL;
 11	timing->globalCycles = 0;
 12	timing->masterCycles = 0;
 13	timing->relativeCycles = relativeCycles;
 14	timing->nextEvent = nextEvent;
 15}
 16
 17void mTimingDeinit(struct mTiming* timing) {
 18	UNUSED(timing);
 19}
 20
 21void mTimingClear(struct mTiming* timing) {
 22	timing->root = NULL;
 23	timing->reroot = NULL;
 24	timing->globalCycles = 0;
 25	timing->masterCycles = 0;
 26}
 27
 28void mTimingSchedule(struct mTiming* timing, struct mTimingEvent* event, int32_t when) {
 29	int32_t nextEvent = when + *timing->relativeCycles;
 30	event->when = nextEvent + timing->masterCycles;
 31	if (nextEvent < *timing->nextEvent) {
 32		*timing->nextEvent = nextEvent;
 33	}
 34	if (timing->reroot) {
 35		timing->root = timing->reroot;
 36		timing->reroot = NULL;
 37	}
 38	struct mTimingEvent** previous = &timing->root;
 39	struct mTimingEvent* next = timing->root;
 40	unsigned priority = event->priority;
 41	while (next) {
 42		int32_t nextWhen = next->when - timing->masterCycles;
 43		if (nextWhen > nextEvent || (nextWhen == nextEvent && next->priority > priority)) {
 44			break;
 45		}
 46		previous = &next->next;
 47		next = next->next;
 48	}
 49	event->next = next;
 50	*previous = event;
 51}
 52
 53void mTimingScheduleAbsolute(struct mTiming* timing, struct mTimingEvent* event, int32_t when) {
 54	mTimingSchedule(timing, event, when - mTimingCurrentTime(timing));
 55}
 56
 57void mTimingDeschedule(struct mTiming* timing, struct mTimingEvent* event) {
 58	if (timing->reroot) {
 59		timing->root = timing->reroot;
 60		timing->reroot = NULL;
 61	}
 62	struct mTimingEvent** previous = &timing->root;
 63	struct mTimingEvent* next = timing->root;
 64	while (next) {
 65		if (next == event) {
 66			*previous = next->next;
 67			return;
 68		}
 69		previous = &next->next;
 70		next = next->next;
 71	}
 72}
 73
 74bool mTimingIsScheduled(const struct mTiming* timing, const struct mTimingEvent* event) {
 75	const struct mTimingEvent* next = timing->root;
 76	if (!next) {
 77		next = timing->reroot;
 78	}
 79	while (next) {
 80		if (next == event) {
 81			return true;
 82		}
 83		next = next->next;
 84	}
 85	return false;
 86}
 87
 88int32_t mTimingTick(struct mTiming* timing, int32_t cycles) {
 89	timing->masterCycles += cycles;
 90	uint32_t masterCycles = timing->masterCycles;
 91	while (timing->root) {
 92		struct mTimingEvent* next = timing->root;
 93		int32_t nextWhen = next->when - masterCycles;
 94		if (nextWhen > 0) {
 95			return nextWhen;
 96		}
 97		timing->root = next->next;
 98		next->callback(timing, next->context, -nextWhen);
 99	}
100	if (timing->reroot) {
101		timing->root = timing->reroot;
102		timing->reroot = NULL;
103		*timing->nextEvent = mTimingNextEvent(timing); 
104	}
105	return *timing->nextEvent;
106}
107
108int32_t mTimingCurrentTime(const struct mTiming* timing) {
109	return timing->masterCycles + *timing->relativeCycles;
110}
111
112uint64_t mTimingGlobalTime(const struct mTiming* timing) {
113	return timing->globalCycles + *timing->relativeCycles;
114}
115
116int32_t mTimingNextEvent(struct mTiming* timing) {
117	struct mTimingEvent* next = timing->root;
118	if (!next) {
119		return INT_MAX;
120	}
121	return next->when - timing->masterCycles - *timing->relativeCycles;
122}
123
124int32_t mTimingUntil(const struct mTiming* timing, const struct mTimingEvent* event) {
125	return event->when - timing->masterCycles - *timing->relativeCycles;
126}