all repos — mgba @ 4d839d03b46918ae0db7cc7f0c7f04e8e6f2c62a

mGBA Game Boy Advance Emulator

src/gba/core.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 "core.h"
  7
  8#include "core/core.h"
  9#include "core/log.h"
 10#include "gba/gba.h"
 11#include "gba/context/overrides.h"
 12#include "gba/renderers/video-software.h"
 13#include "gba/serialize.h"
 14#include "util/memory.h"
 15#include "util/patch.h"
 16#include "util/vfs.h"
 17
 18struct GBACore {
 19	struct mCore d;
 20	struct GBAVideoSoftwareRenderer renderer;
 21	int keys;
 22	struct mCPUComponent* components[GBA_COMPONENT_MAX];
 23	const struct Configuration* overrides;
 24};
 25
 26static bool _GBACoreInit(struct mCore* core) {
 27	struct GBACore* gbacore = (struct GBACore*) core;
 28
 29	struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore));
 30	struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA));
 31	if (!cpu || !gba) {
 32		free(cpu);
 33		free(gba);
 34		return false;
 35	}
 36	core->cpu = cpu;
 37	core->board = gba;
 38	gbacore->overrides = 0;
 39
 40	GBACreate(gba);
 41	// TODO: Restore debugger and cheats
 42	memset(gbacore->components, 0, sizeof(gbacore->components));
 43	ARMSetComponents(cpu, &gba->d, GBA_COMPONENT_MAX, gbacore->components);
 44	ARMInit(cpu);
 45
 46	GBAVideoSoftwareRendererCreate(&gbacore->renderer);
 47	gbacore->renderer.outputBuffer = NULL;
 48
 49	gbacore->keys = 0;
 50	gba->keySource = &gbacore->keys;
 51
 52#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 53	mDirectorySetInit(&core->dirs);
 54#endif
 55	
 56	return true;
 57}
 58
 59static void _GBACoreDeinit(struct mCore* core) {
 60	ARMDeinit(core->cpu);
 61	GBADestroy(core->board);
 62	mappedMemoryFree(core->cpu, sizeof(struct ARMCore));
 63	mappedMemoryFree(core->board, sizeof(struct GBA));
 64#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 65	mDirectorySetDeinit(&core->dirs);
 66#endif
 67	free(core);
 68}
 69
 70static enum mPlatform _GBACorePlatform(struct mCore* core) {
 71	UNUSED(core);
 72	return PLATFORM_GBA;
 73}
 74
 75static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) {
 76	struct GBA* gba = core->board;
 77	gba->sync = sync;
 78}
 79
 80static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
 81	struct GBA* gba = core->board;
 82	if (core->opts.mute) {
 83		gba->audio.masterVolume = 0;
 84	} else {
 85		gba->audio.masterVolume = core->opts.volume;
 86	}
 87	gba->video.frameskip = core->opts.frameskip;
 88
 89#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 90	struct GBACore* gbacore = (struct GBACore*) core;
 91	gbacore->overrides = mCoreConfigGetOverridesConst(config);
 92
 93	struct VFile* bios = 0;
 94	if (core->opts.useBios && core->opts.bios) {
 95		bios = VFileOpen(core->opts.bios, O_RDONLY);
 96	}
 97	if (bios) {
 98		GBALoadBIOS(gba, bios);
 99	}
100#endif
101
102	const char* idleOptimization = mCoreConfigGetValue(config, "idleOptimization");
103	if (idleOptimization) {
104		if (strcasecmp(idleOptimization, "ignore") == 0) {
105			gba->idleOptimization = IDLE_LOOP_IGNORE;
106		} else if (strcasecmp(idleOptimization, "remove") == 0) {
107			gba->idleOptimization = IDLE_LOOP_REMOVE;
108		} else if (strcasecmp(idleOptimization, "detect") == 0) {
109			gba->idleOptimization = IDLE_LOOP_DETECT;
110		}
111	}
112}
113
114static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
115	UNUSED(core);
116	*width = VIDEO_HORIZONTAL_PIXELS;
117	*height = VIDEO_VERTICAL_PIXELS;
118}
119
120static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
121	struct GBACore* gbacore = (struct GBACore*) core;
122	gbacore->renderer.outputBuffer = buffer;
123	gbacore->renderer.outputBufferStride = stride;
124}
125
126static void _GBACoreGetVideoBuffer(struct mCore* core, color_t** buffer, size_t* stride) {
127	struct GBACore* gbacore = (struct GBACore*) core;
128	*buffer = gbacore->renderer.outputBuffer;
129	*stride = gbacore->renderer.outputBufferStride;
130}
131
132static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) {
133	struct GBA* gba = core->board;
134	switch (ch) {
135	case 0:
136		return gba->audio.psg.left;
137	case 1:
138		return gba->audio.psg.right;
139	default:
140		return NULL;
141	}
142}
143
144static void _GBACoreSetAudioBufferSize(struct mCore* core, size_t samples) {
145	struct GBA* gba = core->board;
146	GBAAudioResizeBuffer(&gba->audio, samples);
147}
148
149static size_t _GBACoreGetAudioBufferSize(struct mCore* core) {
150	struct GBA* gba = core->board;
151	return gba->audio.samples;
152}
153
154static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
155	struct GBA* gba = core->board;
156	gba->stream = stream;
157	if (stream && stream->videoDimensionsChanged) {
158		stream->videoDimensionsChanged(stream, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
159	}
160}
161
162static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
163	return GBALoadROM(core->board, vf);
164}
165
166static bool _GBACoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
167	UNUSED(type);
168	if (!GBAIsBIOS(vf)) {
169		return false;
170	}
171	GBALoadBIOS(core->board, vf);
172	return true;
173}
174
175static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) {
176	return GBALoadSave(core->board, vf);
177}
178
179static bool _GBACoreLoadPatch(struct mCore* core, struct VFile* vf) {
180	if (!vf) {
181		return false;
182	}
183	struct Patch patch;
184	if (!loadPatch(vf, &patch)) {
185		return false;
186	}
187	GBAApplyPatch(core->board, &patch);
188	return true;
189}
190
191static void _GBACoreUnloadROM(struct mCore* core) {
192	return GBAUnloadROM(core->board);
193}
194
195static void _GBACoreReset(struct mCore* core) {
196	struct GBACore* gbacore = (struct GBACore*) core;
197	struct GBA* gba = (struct GBA*) core->board;
198	if (gbacore->renderer.outputBuffer) {
199		GBAVideoAssociateRenderer(&gba->video, &gbacore->renderer.d);
200	}
201	ARMReset(core->cpu);
202	if (core->opts.skipBios) {
203		GBASkipBIOS(core->board);
204	}
205
206	struct GBACartridgeOverride override;
207	const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
208	memcpy(override.id, &cart->id, sizeof(override.id));
209	if (GBAOverrideFind(gbacore->overrides, &override)) {
210		GBAOverrideApply(gba, &override);
211	}
212}
213
214static void _GBACoreRunFrame(struct mCore* core) {
215	struct GBA* gba = core->board;
216	int32_t frameCounter = gba->video.frameCounter;
217	while (gba->video.frameCounter == frameCounter) {
218		ARMRunLoop(core->cpu);
219	}
220}
221
222static void _GBACoreRunLoop(struct mCore* core) {
223	ARMRunLoop(core->cpu);
224}
225
226static void _GBACoreStep(struct mCore* core) {
227	ARMRun(core->cpu);
228}
229
230static bool _GBACoreLoadState(struct mCore* core, struct VFile* vf, int flags) {
231	return GBALoadStateNamed(core->board, vf, flags);
232}
233
234static bool _GBACoreSaveState(struct mCore* core, struct VFile* vf, int flags) {
235	return GBASaveStateNamed(core->board, vf, flags);
236}
237
238static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
239	struct GBACore* gbacore = (struct GBACore*) core;
240	gbacore->keys = keys;
241}
242
243static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
244	struct GBACore* gbacore = (struct GBACore*) core;
245	gbacore->keys |= keys;
246}
247
248static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
249	struct GBACore* gbacore = (struct GBACore*) core;
250	gbacore->keys &= ~keys;
251}
252
253static int32_t _GBACoreFrameCounter(struct mCore* core) {
254	struct GBA* gba = core->board;
255	return gba->video.frameCounter;
256}
257
258static int32_t _GBACoreFrameCycles(struct mCore* core) {
259	UNUSED(core);
260	return VIDEO_TOTAL_LENGTH;
261}
262
263static int32_t _GBACoreFrequency(struct mCore* core) {
264	UNUSED(core);
265	return GBA_ARM7TDMI_FREQUENCY;
266}
267
268static void _GBACoreGetGameTitle(struct mCore* core, char* title) {
269	GBAGetGameTitle(core->board, title);
270}
271
272static void _GBACoreGetGameCode(struct mCore* core, char* title) {
273	GBAGetGameCode(core->board, title);
274}
275
276static void _GBACoreSetRTC(struct mCore* core, struct mRTCSource* rtc) {
277	struct GBA* gba = core->board;
278	gba->rtcSource = rtc;
279}
280
281static void _GBACoreSetRotation(struct mCore* core, struct mRotationSource* rotation) {
282	struct GBA* gba = core->board;
283	gba->rotationSource = rotation;
284}
285
286static void _GBACoreSetRumble(struct mCore* core, struct mRumble* rumble) {
287	struct GBA* gba = core->board;
288	gba->rumble = rumble;
289}
290
291struct mCore* GBACoreCreate(void) {
292	struct GBACore* gbacore = malloc(sizeof(*gbacore));
293	struct mCore* core = &gbacore->d;
294	memset(&core->opts, 0, sizeof(core->opts));
295	core->cpu = 0;
296	core->board = 0;
297	core->init = _GBACoreInit;
298	core->deinit = _GBACoreDeinit;
299	core->platform = _GBACorePlatform;
300	core->setSync = _GBACoreSetSync;
301	core->loadConfig = _GBACoreLoadConfig;
302	core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
303	core->setVideoBuffer = _GBACoreSetVideoBuffer;
304	core->getVideoBuffer = _GBACoreGetVideoBuffer;
305	core->getAudioChannel = _GBACoreGetAudioChannel;
306	core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
307	core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
308	core->setAVStream = _GBACoreSetAVStream;
309	core->isROM = GBAIsROM;
310	core->loadROM = _GBACoreLoadROM;
311	core->loadBIOS = _GBACoreLoadBIOS;
312	core->loadSave = _GBACoreLoadSave;
313	core->loadPatch = _GBACoreLoadPatch;
314	core->unloadROM = _GBACoreUnloadROM;
315	core->reset = _GBACoreReset;
316	core->runFrame = _GBACoreRunFrame;
317	core->runLoop = _GBACoreRunLoop;
318	core->step = _GBACoreStep;
319	core->loadState = _GBACoreLoadState;
320	core->saveState = _GBACoreSaveState;
321	core->setKeys = _GBACoreSetKeys;
322	core->addKeys = _GBACoreAddKeys;
323	core->clearKeys = _GBACoreClearKeys;
324	core->frameCounter = _GBACoreFrameCounter;
325	core->frameCycles = _GBACoreFrameCycles;
326	core->frequency = _GBACoreFrequency;
327	core->getGameTitle = _GBACoreGetGameTitle;
328	core->getGameCode = _GBACoreGetGameCode;
329	core->setRTC = _GBACoreSetRTC;
330	core->setRotation = _GBACoreSetRotation;
331	core->setRumble = _GBACoreSetRumble;
332	return core;
333}