all repos — mgba @ b0a1a2e2b722f034d6955dbe0b9d981915654215

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 "gba/supervisor/cli.h"
 15#include "util/memory.h"
 16#include "util/patch.h"
 17#include "util/vfs.h"
 18
 19struct GBACore {
 20	struct mCore d;
 21	struct GBAVideoSoftwareRenderer renderer;
 22	int keys;
 23	struct mCPUComponent* components[CPU_COMPONENT_MAX];
 24	const struct Configuration* overrides;
 25	struct mDebuggerPlatform* debuggerPlatform;
 26};
 27
 28static bool _GBACoreInit(struct mCore* core) {
 29	struct GBACore* gbacore = (struct GBACore*) core;
 30
 31	struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore));
 32	struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA));
 33	if (!cpu || !gba) {
 34		free(cpu);
 35		free(gba);
 36		return false;
 37	}
 38	core->cpu = cpu;
 39	core->board = gba;
 40	core->debugger = NULL;
 41	gbacore->debuggerPlatform = NULL;
 42	gbacore->overrides = 0;
 43
 44	GBACreate(gba);
 45	// TODO: Restore cheats
 46	memset(gbacore->components, 0, sizeof(gbacore->components));
 47	ARMSetComponents(cpu, &gba->d, CPU_COMPONENT_MAX, gbacore->components);
 48	ARMInit(cpu);
 49
 50	GBAVideoSoftwareRendererCreate(&gbacore->renderer);
 51	gbacore->renderer.outputBuffer = NULL;
 52
 53	gbacore->keys = 0;
 54	gba->keySource = &gbacore->keys;
 55
 56#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 57	mDirectorySetInit(&core->dirs);
 58#endif
 59	
 60	return true;
 61}
 62
 63static void _GBACoreDeinit(struct mCore* core) {
 64	ARMDeinit(core->cpu);
 65	GBADestroy(core->board);
 66	mappedMemoryFree(core->cpu, sizeof(struct ARMCore));
 67	mappedMemoryFree(core->board, sizeof(struct GBA));
 68#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 69	mDirectorySetDeinit(&core->dirs);
 70#endif
 71	free(core);
 72}
 73
 74static enum mPlatform _GBACorePlatform(struct mCore* core) {
 75	UNUSED(core);
 76	return PLATFORM_GBA;
 77}
 78
 79static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) {
 80	struct GBA* gba = core->board;
 81	gba->sync = sync;
 82}
 83
 84static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
 85	struct GBA* gba = core->board;
 86	if (core->opts.mute) {
 87		gba->audio.masterVolume = 0;
 88	} else {
 89		gba->audio.masterVolume = core->opts.volume;
 90	}
 91	gba->video.frameskip = core->opts.frameskip;
 92
 93#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 94	struct GBACore* gbacore = (struct GBACore*) core;
 95	gbacore->overrides = mCoreConfigGetOverridesConst(config);
 96
 97	struct VFile* bios = 0;
 98	if (core->opts.useBios && core->opts.bios) {
 99		bios = VFileOpen(core->opts.bios, O_RDONLY);
100	}
101	if (bios) {
102		GBALoadBIOS(gba, bios);
103	}
104#endif
105
106	const char* idleOptimization = mCoreConfigGetValue(config, "idleOptimization");
107	if (idleOptimization) {
108		if (strcasecmp(idleOptimization, "ignore") == 0) {
109			gba->idleOptimization = IDLE_LOOP_IGNORE;
110		} else if (strcasecmp(idleOptimization, "remove") == 0) {
111			gba->idleOptimization = IDLE_LOOP_REMOVE;
112		} else if (strcasecmp(idleOptimization, "detect") == 0) {
113			gba->idleOptimization = IDLE_LOOP_DETECT;
114		}
115	}
116}
117
118static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
119	UNUSED(core);
120	*width = VIDEO_HORIZONTAL_PIXELS;
121	*height = VIDEO_VERTICAL_PIXELS;
122}
123
124static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
125	struct GBACore* gbacore = (struct GBACore*) core;
126	gbacore->renderer.outputBuffer = buffer;
127	gbacore->renderer.outputBufferStride = stride;
128}
129
130static void _GBACoreGetVideoBuffer(struct mCore* core, color_t** buffer, size_t* stride) {
131	struct GBACore* gbacore = (struct GBACore*) core;
132	*buffer = gbacore->renderer.outputBuffer;
133	*stride = gbacore->renderer.outputBufferStride;
134}
135
136static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) {
137	struct GBA* gba = core->board;
138	switch (ch) {
139	case 0:
140		return gba->audio.psg.left;
141	case 1:
142		return gba->audio.psg.right;
143	default:
144		return NULL;
145	}
146}
147
148static void _GBACoreSetAudioBufferSize(struct mCore* core, size_t samples) {
149	struct GBA* gba = core->board;
150	GBAAudioResizeBuffer(&gba->audio, samples);
151}
152
153static size_t _GBACoreGetAudioBufferSize(struct mCore* core) {
154	struct GBA* gba = core->board;
155	return gba->audio.samples;
156}
157
158static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
159	struct GBA* gba = core->board;
160	gba->stream = stream;
161	if (stream && stream->videoDimensionsChanged) {
162		stream->videoDimensionsChanged(stream, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
163	}
164}
165
166static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
167	return GBALoadROM(core->board, vf);
168}
169
170static bool _GBACoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
171	UNUSED(type);
172	if (!GBAIsBIOS(vf)) {
173		return false;
174	}
175	GBALoadBIOS(core->board, vf);
176	return true;
177}
178
179static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) {
180	return GBALoadSave(core->board, vf);
181}
182
183static bool _GBACoreLoadPatch(struct mCore* core, struct VFile* vf) {
184	if (!vf) {
185		return false;
186	}
187	struct Patch patch;
188	if (!loadPatch(vf, &patch)) {
189		return false;
190	}
191	GBAApplyPatch(core->board, &patch);
192	return true;
193}
194
195static void _GBACoreUnloadROM(struct mCore* core) {
196	return GBAUnloadROM(core->board);
197}
198
199static void _GBACoreReset(struct mCore* core) {
200	struct GBACore* gbacore = (struct GBACore*) core;
201	struct GBA* gba = (struct GBA*) core->board;
202	if (gbacore->renderer.outputBuffer) {
203		GBAVideoAssociateRenderer(&gba->video, &gbacore->renderer.d);
204	}
205	ARMReset(core->cpu);
206	if (core->opts.skipBios) {
207		GBASkipBIOS(core->board);
208	}
209
210	struct GBACartridgeOverride override;
211	const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
212	memcpy(override.id, &cart->id, sizeof(override.id));
213	if (GBAOverrideFind(gbacore->overrides, &override)) {
214		GBAOverrideApply(gba, &override);
215	}
216}
217
218static void _GBACoreRunFrame(struct mCore* core) {
219	struct GBA* gba = core->board;
220	int32_t frameCounter = gba->video.frameCounter;
221	while (gba->video.frameCounter == frameCounter) {
222		ARMRunLoop(core->cpu);
223	}
224}
225
226static void _GBACoreRunLoop(struct mCore* core) {
227	ARMRunLoop(core->cpu);
228}
229
230static void _GBACoreStep(struct mCore* core) {
231	ARMRun(core->cpu);
232}
233
234static bool _GBACoreLoadState(struct mCore* core, struct VFile* vf, int flags) {
235	return GBALoadStateNamed(core->board, vf, flags);
236}
237
238static bool _GBACoreSaveState(struct mCore* core, struct VFile* vf, int flags) {
239	return GBASaveStateNamed(core->board, vf, flags);
240}
241
242static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
243	struct GBACore* gbacore = (struct GBACore*) core;
244	gbacore->keys = keys;
245}
246
247static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
248	struct GBACore* gbacore = (struct GBACore*) core;
249	gbacore->keys |= keys;
250}
251
252static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
253	struct GBACore* gbacore = (struct GBACore*) core;
254	gbacore->keys &= ~keys;
255}
256
257static int32_t _GBACoreFrameCounter(struct mCore* core) {
258	struct GBA* gba = core->board;
259	return gba->video.frameCounter;
260}
261
262static int32_t _GBACoreFrameCycles(struct mCore* core) {
263	UNUSED(core);
264	return VIDEO_TOTAL_LENGTH;
265}
266
267static int32_t _GBACoreFrequency(struct mCore* core) {
268	UNUSED(core);
269	return GBA_ARM7TDMI_FREQUENCY;
270}
271
272static void _GBACoreGetGameTitle(struct mCore* core, char* title) {
273	GBAGetGameTitle(core->board, title);
274}
275
276static void _GBACoreGetGameCode(struct mCore* core, char* title) {
277	GBAGetGameCode(core->board, title);
278}
279
280static void _GBACoreSetRTC(struct mCore* core, struct mRTCSource* rtc) {
281	struct GBA* gba = core->board;
282	gba->rtcSource = rtc;
283}
284
285static void _GBACoreSetRotation(struct mCore* core, struct mRotationSource* rotation) {
286	struct GBA* gba = core->board;
287	gba->rotationSource = rotation;
288}
289
290static void _GBACoreSetRumble(struct mCore* core, struct mRumble* rumble) {
291	struct GBA* gba = core->board;
292	gba->rumble = rumble;
293}
294
295static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) {
296	struct ARMCore* cpu = core->cpu;
297	return cpu->memory.load8(cpu, address, 0);
298}
299
300static uint32_t _GBACoreBusRead16(struct mCore* core, uint32_t address) {
301	struct ARMCore* cpu = core->cpu;
302	return cpu->memory.load8(cpu, address, 0);
303
304}
305
306static uint32_t _GBACoreBusRead32(struct mCore* core, uint32_t address) {
307	struct ARMCore* cpu = core->cpu;
308	return cpu->memory.load32(cpu, address, 0);
309}
310
311static void _GBACoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
312	struct ARMCore* cpu = core->cpu;
313	cpu->memory.store8(cpu, address, value, 0);
314}
315
316static void _GBACoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
317	struct ARMCore* cpu = core->cpu;
318	cpu->memory.store16(cpu, address, value, 0);
319}
320
321static void _GBACoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
322	struct ARMCore* cpu = core->cpu;
323	cpu->memory.store32(cpu, address, value, 0);
324}
325
326static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
327	UNUSED(core);
328	switch (type) {
329#ifdef USE_CLI_DEBUGGER
330	case DEBUGGER_CLI:
331		return true;
332#endif
333#ifdef USE_GDB_STUB
334	case DEBUGGER_GDB:
335		return true;
336#endif
337	default:
338		return false;
339	}
340}
341
342static struct mDebuggerPlatform* _GBACoreDebuggerPlatform(struct mCore* core) {
343	struct GBACore* gbacore = (struct GBACore*) core;
344	if (!gbacore->debuggerPlatform) {
345		gbacore->debuggerPlatform = ARMDebuggerPlatformCreate();
346	}
347	return gbacore->debuggerPlatform;
348}
349
350static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) {
351#ifdef USE_CLI_DEBUGGER
352	return &GBACLIDebuggerCreate(core)->d;
353#else
354	UNUSED(core);
355	return NULL;
356#endif
357}
358
359static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
360	if (core->debugger) {
361		GBADetachDebugger(core->board);
362	}
363	GBAAttachDebugger(core->board, debugger);
364	core->debugger = debugger;
365}
366
367static void _GBACoreDetachDebugger(struct mCore* core) {
368	GBADetachDebugger(core->board);
369	core->debugger = NULL;
370}
371
372struct mCore* GBACoreCreate(void) {
373	struct GBACore* gbacore = malloc(sizeof(*gbacore));
374	struct mCore* core = &gbacore->d;
375	memset(&core->opts, 0, sizeof(core->opts));
376	core->cpu = NULL;
377	core->board = NULL;
378	core->debugger = NULL;
379	core->init = _GBACoreInit;
380	core->deinit = _GBACoreDeinit;
381	core->platform = _GBACorePlatform;
382	core->setSync = _GBACoreSetSync;
383	core->loadConfig = _GBACoreLoadConfig;
384	core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
385	core->setVideoBuffer = _GBACoreSetVideoBuffer;
386	core->getVideoBuffer = _GBACoreGetVideoBuffer;
387	core->getAudioChannel = _GBACoreGetAudioChannel;
388	core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
389	core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
390	core->setAVStream = _GBACoreSetAVStream;
391	core->isROM = GBAIsROM;
392	core->loadROM = _GBACoreLoadROM;
393	core->loadBIOS = _GBACoreLoadBIOS;
394	core->loadSave = _GBACoreLoadSave;
395	core->loadPatch = _GBACoreLoadPatch;
396	core->unloadROM = _GBACoreUnloadROM;
397	core->reset = _GBACoreReset;
398	core->runFrame = _GBACoreRunFrame;
399	core->runLoop = _GBACoreRunLoop;
400	core->step = _GBACoreStep;
401	core->loadState = _GBACoreLoadState;
402	core->saveState = _GBACoreSaveState;
403	core->setKeys = _GBACoreSetKeys;
404	core->addKeys = _GBACoreAddKeys;
405	core->clearKeys = _GBACoreClearKeys;
406	core->frameCounter = _GBACoreFrameCounter;
407	core->frameCycles = _GBACoreFrameCycles;
408	core->frequency = _GBACoreFrequency;
409	core->getGameTitle = _GBACoreGetGameTitle;
410	core->getGameCode = _GBACoreGetGameCode;
411	core->setRTC = _GBACoreSetRTC;
412	core->setRotation = _GBACoreSetRotation;
413	core->setRumble = _GBACoreSetRumble;
414	core->busRead8 = _GBACoreBusRead8;
415	core->busRead16 = _GBACoreBusRead16;
416	core->busRead32 = _GBACoreBusRead32;
417	core->busWrite8 = _GBACoreBusWrite8;
418	core->busWrite16 = _GBACoreBusWrite16;
419	core->busWrite32 = _GBACoreBusWrite32;
420	core->supportsDebuggerType = _GBACoreSupportsDebuggerType;
421	core->debuggerPlatform = _GBACoreDebuggerPlatform;
422	core->cliDebuggerSystem = _GBACoreCliDebuggerSystem;
423	core->attachDebugger = _GBACoreAttachDebugger;
424	core->detachDebugger = _GBACoreDetachDebugger;
425	return core;
426}