all repos — mgba @ 5e4e00938cc930167bf2bb3108ab19d0a62e7608

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 "arm/debugger/debugger.h"
 11#include "gba/cheats.h"
 12#include "gba/gba.h"
 13#include "gba/extra/cli.h"
 14#include "gba/overrides.h"
 15#include "gba/renderers/video-software.h"
 16#include "gba/savedata.h"
 17#include "gba/serialize.h"
 18#include "util/memory.h"
 19#include "util/patch.h"
 20#include "util/vfs.h"
 21
 22struct GBACore {
 23	struct mCore d;
 24	struct GBAVideoSoftwareRenderer renderer;
 25	int keys;
 26	struct mCPUComponent* components[CPU_COMPONENT_MAX];
 27	const struct Configuration* overrides;
 28	struct mDebuggerPlatform* debuggerPlatform;
 29	struct mCheatDevice* cheatDevice;
 30};
 31
 32static bool _GBACoreInit(struct mCore* core) {
 33	struct GBACore* gbacore = (struct GBACore*) core;
 34
 35	struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore));
 36	struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA));
 37	if (!cpu || !gba) {
 38		free(cpu);
 39		free(gba);
 40		return false;
 41	}
 42	core->cpu = cpu;
 43	core->board = gba;
 44	core->debugger = NULL;
 45	gbacore->overrides = NULL;
 46	gbacore->debuggerPlatform = NULL;
 47	gbacore->cheatDevice = NULL;
 48
 49	GBACreate(gba);
 50	// TODO: Restore cheats
 51	memset(gbacore->components, 0, sizeof(gbacore->components));
 52	ARMSetComponents(cpu, &gba->d, CPU_COMPONENT_MAX, gbacore->components);
 53	ARMInit(cpu);
 54
 55	GBAVideoSoftwareRendererCreate(&gbacore->renderer);
 56	gbacore->renderer.outputBuffer = NULL;
 57
 58	gbacore->keys = 0;
 59	gba->keySource = &gbacore->keys;
 60
 61#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 62	mDirectorySetInit(&core->dirs);
 63#endif
 64	
 65	return true;
 66}
 67
 68static void _GBACoreDeinit(struct mCore* core) {
 69	ARMDeinit(core->cpu);
 70	GBADestroy(core->board);
 71	mappedMemoryFree(core->cpu, sizeof(struct ARMCore));
 72	mappedMemoryFree(core->board, sizeof(struct GBA));
 73#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 74	mDirectorySetDeinit(&core->dirs);
 75#endif
 76
 77	struct GBACore* gbacore = (struct GBACore*) core;
 78	free(gbacore->debuggerPlatform);
 79	if (gbacore->cheatDevice) {
 80		mCheatDeviceDestroy(gbacore->cheatDevice);
 81	}
 82	free(gbacore->cheatDevice);
 83	free(core);
 84}
 85
 86static enum mPlatform _GBACorePlatform(struct mCore* core) {
 87	UNUSED(core);
 88	return PLATFORM_GBA;
 89}
 90
 91static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) {
 92	struct GBA* gba = core->board;
 93	gba->sync = sync;
 94}
 95
 96static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
 97	struct GBA* gba = core->board;
 98	if (core->opts.mute) {
 99		gba->audio.masterVolume = 0;
100	} else {
101		gba->audio.masterVolume = core->opts.volume;
102	}
103	gba->video.frameskip = core->opts.frameskip;
104
105#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
106	struct GBACore* gbacore = (struct GBACore*) core;
107	gbacore->overrides = mCoreConfigGetOverridesConst(config);
108
109	struct VFile* bios = 0;
110	if (core->opts.useBios && core->opts.bios) {
111		bios = VFileOpen(core->opts.bios, O_RDONLY);
112	}
113	if (bios) {
114		GBALoadBIOS(gba, bios);
115	}
116#endif
117
118	const char* idleOptimization = mCoreConfigGetValue(config, "idleOptimization");
119	if (idleOptimization) {
120		if (strcasecmp(idleOptimization, "ignore") == 0) {
121			gba->idleOptimization = IDLE_LOOP_IGNORE;
122		} else if (strcasecmp(idleOptimization, "remove") == 0) {
123			gba->idleOptimization = IDLE_LOOP_REMOVE;
124		} else if (strcasecmp(idleOptimization, "detect") == 0) {
125			gba->idleOptimization = IDLE_LOOP_DETECT;
126		}
127	}
128}
129
130static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
131	UNUSED(core);
132	*width = VIDEO_HORIZONTAL_PIXELS;
133	*height = VIDEO_VERTICAL_PIXELS;
134}
135
136static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
137	struct GBACore* gbacore = (struct GBACore*) core;
138	gbacore->renderer.outputBuffer = buffer;
139	gbacore->renderer.outputBufferStride = stride;
140}
141
142static void _GBACoreGetVideoBuffer(struct mCore* core, color_t** buffer, size_t* stride) {
143	struct GBACore* gbacore = (struct GBACore*) core;
144	*buffer = gbacore->renderer.outputBuffer;
145	*stride = gbacore->renderer.outputBufferStride;
146}
147
148static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) {
149	struct GBA* gba = core->board;
150	switch (ch) {
151	case 0:
152		return gba->audio.psg.left;
153	case 1:
154		return gba->audio.psg.right;
155	default:
156		return NULL;
157	}
158}
159
160static void _GBACoreSetAudioBufferSize(struct mCore* core, size_t samples) {
161	struct GBA* gba = core->board;
162	GBAAudioResizeBuffer(&gba->audio, samples);
163}
164
165static size_t _GBACoreGetAudioBufferSize(struct mCore* core) {
166	struct GBA* gba = core->board;
167	return gba->audio.samples;
168}
169
170static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
171	struct GBA* gba = core->board;
172	gba->stream = stream;
173	if (stream && stream->videoDimensionsChanged) {
174		stream->videoDimensionsChanged(stream, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
175	}
176}
177
178static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
179	return GBALoadROM(core->board, vf);
180}
181
182static bool _GBACoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
183	UNUSED(type);
184	if (!GBAIsBIOS(vf)) {
185		return false;
186	}
187	GBALoadBIOS(core->board, vf);
188	return true;
189}
190
191static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) {
192	return GBALoadSave(core->board, vf);
193}
194
195static bool _GBACoreLoadTemporarySave(struct mCore* core, struct VFile* vf) {
196	GBASavedataMask(core->board, vf);
197	return true; // TODO: Return a real value
198}
199
200static bool _GBACoreLoadPatch(struct mCore* core, struct VFile* vf) {
201	if (!vf) {
202		return false;
203	}
204	struct Patch patch;
205	if (!loadPatch(vf, &patch)) {
206		return false;
207	}
208	GBAApplyPatch(core->board, &patch);
209	return true;
210}
211
212static void _GBACoreUnloadROM(struct mCore* core) {
213	return GBAUnloadROM(core->board);
214}
215
216static void _GBACoreReset(struct mCore* core) {
217	struct GBACore* gbacore = (struct GBACore*) core;
218	struct GBA* gba = (struct GBA*) core->board;
219	if (gbacore->renderer.outputBuffer) {
220		GBAVideoAssociateRenderer(&gba->video, &gbacore->renderer.d);
221	}
222	ARMReset(core->cpu);
223	if (core->opts.skipBios) {
224		GBASkipBIOS(core->board);
225	}
226
227	struct GBACartridgeOverride override;
228	const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
229	if (cart) {
230		memcpy(override.id, &cart->id, sizeof(override.id));
231		if (GBAOverrideFind(gbacore->overrides, &override)) {
232			GBAOverrideApply(gba, &override);
233		}
234	}
235}
236
237static void _GBACoreRunFrame(struct mCore* core) {
238	struct GBA* gba = core->board;
239	int32_t frameCounter = gba->video.frameCounter;
240	while (gba->video.frameCounter == frameCounter) {
241		ARMRunLoop(core->cpu);
242	}
243}
244
245static void _GBACoreRunLoop(struct mCore* core) {
246	ARMRunLoop(core->cpu);
247}
248
249static void _GBACoreStep(struct mCore* core) {
250	ARMRun(core->cpu);
251}
252
253static size_t _GBACoreStateSize(struct mCore* core) {
254	UNUSED(core);
255	return sizeof(struct GBASerializedState);
256}
257
258static bool _GBACoreLoadState(struct mCore* core, const void* state) {
259	return GBADeserialize(core->board, state);
260}
261
262static bool _GBACoreSaveState(struct mCore* core, void* state) {
263	GBASerialize(core->board, state);
264	return true;
265}
266
267static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
268	struct GBACore* gbacore = (struct GBACore*) core;
269	gbacore->keys = keys;
270}
271
272static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
273	struct GBACore* gbacore = (struct GBACore*) core;
274	gbacore->keys |= keys;
275}
276
277static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
278	struct GBACore* gbacore = (struct GBACore*) core;
279	gbacore->keys &= ~keys;
280}
281
282static int32_t _GBACoreFrameCounter(struct mCore* core) {
283	struct GBA* gba = core->board;
284	return gba->video.frameCounter;
285}
286
287static int32_t _GBACoreFrameCycles(struct mCore* core) {
288	UNUSED(core);
289	return VIDEO_TOTAL_LENGTH;
290}
291
292static int32_t _GBACoreFrequency(struct mCore* core) {
293	UNUSED(core);
294	return GBA_ARM7TDMI_FREQUENCY;
295}
296
297static void _GBACoreGetGameTitle(struct mCore* core, char* title) {
298	GBAGetGameTitle(core->board, title);
299}
300
301static void _GBACoreGetGameCode(struct mCore* core, char* title) {
302	GBAGetGameCode(core->board, title);
303}
304
305static void _GBACoreSetRTC(struct mCore* core, struct mRTCSource* rtc) {
306	struct GBA* gba = core->board;
307	gba->rtcSource = rtc;
308}
309
310static void _GBACoreSetRotation(struct mCore* core, struct mRotationSource* rotation) {
311	struct GBA* gba = core->board;
312	gba->rotationSource = rotation;
313}
314
315static void _GBACoreSetRumble(struct mCore* core, struct mRumble* rumble) {
316	struct GBA* gba = core->board;
317	gba->rumble = rumble;
318}
319
320static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) {
321	struct ARMCore* cpu = core->cpu;
322	return cpu->memory.load8(cpu, address, 0);
323}
324
325static uint32_t _GBACoreBusRead16(struct mCore* core, uint32_t address) {
326	struct ARMCore* cpu = core->cpu;
327	return cpu->memory.load16(cpu, address, 0);
328
329}
330
331static uint32_t _GBACoreBusRead32(struct mCore* core, uint32_t address) {
332	struct ARMCore* cpu = core->cpu;
333	return cpu->memory.load32(cpu, address, 0);
334}
335
336static void _GBACoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
337	struct ARMCore* cpu = core->cpu;
338	cpu->memory.store8(cpu, address, value, 0);
339}
340
341static void _GBACoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
342	struct ARMCore* cpu = core->cpu;
343	cpu->memory.store16(cpu, address, value, 0);
344}
345
346static void _GBACoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
347	struct ARMCore* cpu = core->cpu;
348	cpu->memory.store32(cpu, address, value, 0);
349}
350
351static uint32_t _GBACoreRawRead8(struct mCore* core, uint32_t address) {
352	struct ARMCore* cpu = core->cpu;
353	return GBAView8(cpu, address);
354}
355
356static uint32_t _GBACoreRawRead16(struct mCore* core, uint32_t address) {
357	struct ARMCore* cpu = core->cpu;
358	return GBAView16(cpu, address);
359}
360
361static uint32_t _GBACoreRawRead32(struct mCore* core, uint32_t address) {
362	struct ARMCore* cpu = core->cpu;
363	return GBAView32(cpu, address);
364}
365
366static void _GBACoreRawWrite8(struct mCore* core, uint32_t address, uint8_t value) {
367	struct ARMCore* cpu = core->cpu;
368	GBAPatch8(cpu, address, value, NULL);
369}
370
371static void _GBACoreRawWrite16(struct mCore* core, uint32_t address, uint16_t value) {
372	struct ARMCore* cpu = core->cpu;
373	GBAPatch16(cpu, address, value, NULL);
374}
375
376static void _GBACoreRawWrite32(struct mCore* core, uint32_t address, uint32_t value) {
377	struct ARMCore* cpu = core->cpu;
378	GBAPatch32(cpu, address, value, NULL);
379}
380
381static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
382	UNUSED(core);
383	switch (type) {
384#ifdef USE_CLI_DEBUGGER
385	case DEBUGGER_CLI:
386		return true;
387#endif
388#ifdef USE_GDB_STUB
389	case DEBUGGER_GDB:
390		return true;
391#endif
392	default:
393		return false;
394	}
395}
396
397static struct mDebuggerPlatform* _GBACoreDebuggerPlatform(struct mCore* core) {
398	struct GBACore* gbacore = (struct GBACore*) core;
399	if (!gbacore->debuggerPlatform) {
400		gbacore->debuggerPlatform = ARMDebuggerPlatformCreate();
401	}
402	return gbacore->debuggerPlatform;
403}
404
405static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) {
406#ifdef USE_CLI_DEBUGGER
407	return &GBACLIDebuggerCreate(core)->d;
408#else
409	UNUSED(core);
410	return NULL;
411#endif
412}
413
414static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
415	if (core->debugger) {
416		GBADetachDebugger(core->board);
417	}
418	GBAAttachDebugger(core->board, debugger);
419	core->debugger = debugger;
420}
421
422static void _GBACoreDetachDebugger(struct mCore* core) {
423	GBADetachDebugger(core->board);
424	core->debugger = NULL;
425}
426
427static struct mCheatDevice* _GBACoreCheatDevice(struct mCore* core) {
428	struct GBACore* gbacore = (struct GBACore*) core;
429	if (!gbacore->cheatDevice) {
430		gbacore->cheatDevice = GBACheatDeviceCreate();
431		((struct ARMCore*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbacore->cheatDevice->d;
432		ARMHotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE);
433		gbacore->cheatDevice->p = core;
434	}
435	return gbacore->cheatDevice;
436}
437
438static size_t _GBACoreSavedataClone(struct mCore* core, void** sram) {
439	struct GBA* gba = core->board;
440	size_t size = GBASavedataSize(&gba->memory.savedata);
441	if (!size) {
442		*sram = NULL;
443		return 0;
444	}
445	*sram = malloc(size);
446	struct VFile* vf = VFileFromMemory(*sram, size);
447	if (!vf) {
448		free(*sram);
449		*sram = NULL;
450		return 0;
451	}
452	bool success = GBASavedataClone(&gba->memory.savedata, vf);
453	vf->close(vf);
454	if (!success) {
455		free(*sram);
456		*sram = NULL;
457		return 0;
458	}
459	return size;
460}
461
462static bool _GBACoreSavedataLoad(struct mCore* core, const void* sram, size_t size) {
463	struct VFile* vf = VFileFromConstMemory(sram, size);
464	if (!vf) {
465		return false;
466	}
467	struct GBA* gba = core->board;
468	bool success = GBASavedataLoad(&gba->memory.savedata, vf);
469	vf->close(vf);
470	return success;
471}
472
473struct mCore* GBACoreCreate(void) {
474	struct GBACore* gbacore = malloc(sizeof(*gbacore));
475	struct mCore* core = &gbacore->d;
476	memset(&core->opts, 0, sizeof(core->opts));
477	core->cpu = NULL;
478	core->board = NULL;
479	core->debugger = NULL;
480	core->init = _GBACoreInit;
481	core->deinit = _GBACoreDeinit;
482	core->platform = _GBACorePlatform;
483	core->setSync = _GBACoreSetSync;
484	core->loadConfig = _GBACoreLoadConfig;
485	core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
486	core->setVideoBuffer = _GBACoreSetVideoBuffer;
487	core->getVideoBuffer = _GBACoreGetVideoBuffer;
488	core->getAudioChannel = _GBACoreGetAudioChannel;
489	core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
490	core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
491	core->setAVStream = _GBACoreSetAVStream;
492	core->isROM = GBAIsROM;
493	core->loadROM = _GBACoreLoadROM;
494	core->loadBIOS = _GBACoreLoadBIOS;
495	core->loadSave = _GBACoreLoadSave;
496	core->loadTemporarySave = _GBACoreLoadTemporarySave;
497	core->loadPatch = _GBACoreLoadPatch;
498	core->unloadROM = _GBACoreUnloadROM;
499	core->reset = _GBACoreReset;
500	core->runFrame = _GBACoreRunFrame;
501	core->runLoop = _GBACoreRunLoop;
502	core->step = _GBACoreStep;
503	core->stateSize = _GBACoreStateSize;
504	core->loadState = _GBACoreLoadState;
505	core->saveState = _GBACoreSaveState;
506	core->setKeys = _GBACoreSetKeys;
507	core->addKeys = _GBACoreAddKeys;
508	core->clearKeys = _GBACoreClearKeys;
509	core->frameCounter = _GBACoreFrameCounter;
510	core->frameCycles = _GBACoreFrameCycles;
511	core->frequency = _GBACoreFrequency;
512	core->getGameTitle = _GBACoreGetGameTitle;
513	core->getGameCode = _GBACoreGetGameCode;
514	core->setRTC = _GBACoreSetRTC;
515	core->setRotation = _GBACoreSetRotation;
516	core->setRumble = _GBACoreSetRumble;
517	core->busRead8 = _GBACoreBusRead8;
518	core->busRead16 = _GBACoreBusRead16;
519	core->busRead32 = _GBACoreBusRead32;
520	core->busWrite8 = _GBACoreBusWrite8;
521	core->busWrite16 = _GBACoreBusWrite16;
522	core->busWrite32 = _GBACoreBusWrite32;
523	core->rawRead8 = _GBACoreRawRead8;
524	core->rawRead16 = _GBACoreRawRead16;
525	core->rawRead32 = _GBACoreRawRead32;
526	core->rawWrite8 = _GBACoreRawWrite8;
527	core->rawWrite16 = _GBACoreRawWrite16;
528	core->rawWrite32 = _GBACoreRawWrite32;
529	core->supportsDebuggerType = _GBACoreSupportsDebuggerType;
530	core->debuggerPlatform = _GBACoreDebuggerPlatform;
531	core->cliDebuggerSystem = _GBACoreCliDebuggerSystem;
532	core->attachDebugger = _GBACoreAttachDebugger;
533	core->detachDebugger = _GBACoreDetachDebugger;
534	core->cheatDevice = _GBACoreCheatDevice;
535	core->savedataClone = _GBACoreSavedataClone;
536	core->savedataLoad = _GBACoreSavedataLoad;
537	return core;
538}