all repos — mgba @ e1e627e4960d463a88cb60200b00a03c22ae0a3c

mGBA Game Boy Advance Emulator

src/ds/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 <mgba/ds/core.h>
  7
  8#include <mgba/core/cheats.h>
  9#include <mgba/core/core.h>
 10#include <mgba/core/log.h>
 11#include <mgba/internal/arm/debugger/debugger.h>
 12#include <mgba/internal/ds/ds.h>
 13#include <mgba/internal/ds/extra/cli.h>
 14#include <mgba/internal/ds/gx/software.h>
 15#include <mgba/internal/ds/input.h>
 16#include <mgba/internal/ds/renderers/software.h>
 17#include <mgba-util/memory.h>
 18#include <mgba-util/patch.h>
 19#include <mgba-util/vfs.h>
 20
 21struct DSCore {
 22	struct mCore d;
 23	struct ARMCore* arm7;
 24	struct ARMCore* arm9;
 25	struct DSVideoSoftwareRenderer renderer;
 26	struct DSGXSoftwareRenderer gxRenderer;
 27	int keys;
 28	int cursorX;
 29	int cursorY;
 30	bool touchDown;
 31	struct mCPUComponent* components[CPU_COMPONENT_MAX];
 32	struct mDebuggerPlatform* debuggerPlatform;
 33	struct mCheatDevice* cheatDevice;
 34};
 35
 36static bool _DSCoreInit(struct mCore* core) {
 37	struct DSCore* dscore = (struct DSCore*) core;
 38
 39	struct ARMCore* arm7 = anonymousMemoryMap(sizeof(struct ARMCore));
 40	struct ARMCore* arm9 = anonymousMemoryMap(sizeof(struct ARMCore));
 41	struct DS* ds = anonymousMemoryMap(sizeof(struct DS));
 42	if (!arm7 || !arm9 || !ds) {
 43		free(arm7);
 44		free(arm9);
 45		free(ds);
 46		return false;
 47	}
 48	core->cpu = arm9;
 49	core->board = ds;
 50	core->debugger = NULL;
 51	dscore->arm7 = arm7;
 52	dscore->arm9 = arm9;
 53	dscore->debuggerPlatform = NULL;
 54	dscore->cheatDevice = NULL;
 55
 56	DSCreate(ds);
 57	memset(dscore->components, 0, sizeof(dscore->components));
 58	ARMSetComponents(arm7, &ds->d, CPU_COMPONENT_MAX, dscore->components);
 59	ARMSetComponents(arm9, &ds->d, CPU_COMPONENT_MAX, dscore->components);
 60	ARMInit(arm7);
 61	ARMInit(arm9);
 62
 63	DSVideoSoftwareRendererCreate(&dscore->renderer);
 64	DSGXSoftwareRendererCreate(&dscore->gxRenderer);
 65	dscore->renderer.outputBuffer = NULL;
 66
 67	dscore->keys = 0;
 68	ds->keySource = &dscore->keys;
 69	dscore->cursorX = 0;
 70	ds->cursorSourceX = &dscore->cursorX;
 71	dscore->cursorY = 0;
 72	ds->cursorSourceY = &dscore->cursorY;
 73	dscore->touchDown = false;
 74	ds->touchSource = &dscore->touchDown;
 75
 76#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 77	mDirectorySetInit(&core->dirs);
 78#endif
 79
 80#ifndef MINIMAL_CORE
 81	core->inputInfo = &DSInputInfo; // TODO: GBInputInfo
 82#endif
 83
 84	return true;
 85}
 86
 87static void _DSCoreDeinit(struct mCore* core) {
 88	struct DSCore* dscore = (struct DSCore*) core;
 89	ARMDeinit(dscore->arm7);
 90	ARMDeinit(dscore->arm9);
 91	DSDestroy(core->board);
 92	mappedMemoryFree(dscore->arm7, sizeof(struct ARMCore));
 93	mappedMemoryFree(dscore->arm9, sizeof(struct ARMCore));
 94	mappedMemoryFree(core->board, sizeof(struct DS));
 95#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 96	mDirectorySetDeinit(&core->dirs);
 97#endif
 98
 99	free(dscore->debuggerPlatform);
100	if (dscore->cheatDevice) {
101		mCheatDeviceDestroy(dscore->cheatDevice);
102	}
103	free(dscore->cheatDevice);
104	free(core);
105}
106
107static enum mPlatform _DSCorePlatform(const struct mCore* core) {
108	UNUSED(core);
109	return PLATFORM_DS;
110}
111
112static void _DSCoreSetSync(struct mCore* core, struct mCoreSync* sync) {
113	struct DS* ds = core->board;
114	ds->sync = sync;
115}
116
117static void _DSCoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
118	struct DS* ds = core->board;
119	struct VFile* bios = NULL;
120
121	mCoreConfigCopyValue(&core->config, config, "ds.bios7");
122	mCoreConfigCopyValue(&core->config, config, "ds.bios9");
123	mCoreConfigCopyValue(&core->config, config, "ds.firmware");
124}
125
126static void _DSCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
127	UNUSED(core);
128	*width = DS_VIDEO_HORIZONTAL_PIXELS;
129	*height = DS_VIDEO_VERTICAL_PIXELS * 2;
130}
131
132static void _DSCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
133	struct DSCore* dscore = (struct DSCore*) core;
134	dscore->renderer.outputBuffer = buffer;
135	dscore->renderer.outputBufferStride = stride;
136}
137
138static void _DSCoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) {
139	struct DSCore* dscore = (struct DSCore*) core;
140	dscore->renderer.d.getPixels(&dscore->renderer.d, stride, buffer);
141}
142
143static void _DSCorePutPixels(struct mCore* core, const void* buffer, size_t stride) {
144	struct DSCore* dscore = (struct DSCore*) core;
145	dscore->renderer.d.putPixels(&dscore->renderer.d, stride, buffer);
146}
147
148static struct blip_t* _DSCoreGetAudioChannel(struct mCore* core, int ch) {
149	return NULL;
150}
151
152static void _DSCoreSetAudioBufferSize(struct mCore* core, size_t samples) {
153}
154
155static size_t _DSCoreGetAudioBufferSize(struct mCore* core) {
156	return 2048;
157}
158
159static void _DSCoreAddCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) {
160	struct DS* ds = core->board;
161	*mCoreCallbacksListAppend(&ds->coreCallbacks) = *coreCallbacks;
162}
163
164static void _DSCoreClearCoreCallbacks(struct mCore* core) {
165	struct DS* ds = core->board;
166	mCoreCallbacksListClear(&ds->coreCallbacks);
167}
168
169static void _DSCoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
170	struct DS* ds = core->board;
171	ds->stream = stream;
172	if (stream && stream->videoDimensionsChanged) {
173		stream->videoDimensionsChanged(stream, DS_VIDEO_HORIZONTAL_PIXELS, DS_VIDEO_VERTICAL_PIXELS * 2);
174	}
175}
176
177static bool _DSCoreLoadROM(struct mCore* core, struct VFile* vf) {
178	return DSLoadROM(core->board, vf);
179}
180
181static bool _DSCoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
182	UNUSED(type);
183	return DSLoadBIOS(core->board, vf);
184}
185
186static bool _DSCoreLoadSave(struct mCore* core, struct VFile* vf) {
187	return DSLoadSave(core->board, vf);
188}
189
190static bool _DSCoreLoadPatch(struct mCore* core, struct VFile* vf) {
191	return false;
192}
193
194static void _DSCoreUnloadROM(struct mCore* core) {
195	return DSUnloadROM(core->board);
196}
197
198static void _DSCoreChecksum(const struct mCore* core, void* data, enum mCoreChecksumType type) {
199}
200
201static void _DSCoreReset(struct mCore* core) {
202	struct DSCore* dscore = (struct DSCore*) core;
203	struct DS* ds = (struct DS*) core->board;
204
205	if (dscore->renderer.outputBuffer) {
206		struct DSVideoRenderer* renderer = &dscore->renderer.d;
207		DSVideoAssociateRenderer(&ds->video, renderer);
208
209		struct DSGXRenderer* gxRenderer = &dscore->gxRenderer.d;
210		DSGXAssociateRenderer(&ds->gx, gxRenderer);
211	}
212
213#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
214	struct VFile* bios7 = NULL;
215	struct VFile* bios9 = NULL;
216	struct VFile* firm = NULL;
217	if (core->opts.useBios) {
218		bool found7 = false;
219		bool found9 = false;
220		bool foundFirm = false;
221
222		if (!found7) {
223			const char* configPath = mCoreConfigGetValue(&core->config, "ds.bios7");
224			bios7 = VFileOpen(configPath, O_RDONLY);
225			if (bios7 && DSIsBIOS7(bios7)) {
226				found7 = true;
227			} else if (bios7) {
228				bios7->close(bios7);
229				bios7 = NULL;
230			}
231		}
232
233		if (!found9) {
234			const char* configPath = mCoreConfigGetValue(&core->config, "ds.bios9");
235			bios9 = VFileOpen(configPath, O_RDONLY);
236			if (bios9 && DSIsBIOS9(bios9)) {
237				found9 = true;
238			} else if (bios9) {
239				bios9->close(bios9);
240				bios9 = NULL;
241			}
242		}
243
244		if (!foundFirm) {
245			const char* configPath = mCoreConfigGetValue(&core->config, "ds.firmware");
246			firm = VFileOpen(configPath, O_RDONLY);
247			if (firm && DSIsFirmware(firm)) {
248				foundFirm = true;
249			} else if (firm) {
250				firm->close(firm);
251				firm = NULL;
252			}
253		}
254
255		if (!found7) {
256			char path[PATH_MAX];
257			mCoreConfigDirectory(path, PATH_MAX);
258			strncat(path, PATH_SEP "ds7_bios.bin", PATH_MAX - strlen(path));
259			bios7 = VFileOpen(path, O_RDONLY);
260		}
261
262		if (!found9) {
263			char path[PATH_MAX];
264			mCoreConfigDirectory(path, PATH_MAX);
265			strncat(path, PATH_SEP "ds9_bios.bin", PATH_MAX - strlen(path));
266			bios9 = VFileOpen(path, O_RDONLY);
267		}
268
269		if (!foundFirm) {
270			char path[PATH_MAX];
271			mCoreConfigDirectory(path, PATH_MAX);
272			strncat(path, PATH_SEP "ds_firmware.bin", PATH_MAX - strlen(path));
273			firm = VFileOpen(path, O_RDWR);
274		}
275	}
276	if (bios7) {
277		DSLoadBIOS(ds, bios7);
278	}
279	if (bios9) {
280		DSLoadBIOS(ds, bios9);
281	}
282	if (firm) {
283		DSLoadFirmware(ds, firm);
284	}
285#endif
286
287	ARMReset(ds->ds7.cpu);
288	ARMReset(ds->ds9.cpu);
289}
290
291static void _DSCoreRunFrame(struct mCore* core) {
292	struct DSCore* dscore = (struct DSCore*) core;
293	struct DS* ds = core->board;
294	int32_t frameCounter = ds->video.frameCounter;
295	while (ds->video.frameCounter == frameCounter) {
296		DSRunLoop(core->board);
297	}
298}
299
300static void _DSCoreRunLoop(struct mCore* core) {
301	DSRunLoop(core->board);
302}
303
304static void _DSCoreStep(struct mCore* core) {
305	struct DSCore* dscore = (struct DSCore*) core;
306	if (core->cpu == dscore->arm9) {
307		DS9Step(core->board);
308	} else {
309		DS7Step(core->board);
310	}
311}
312
313static size_t _DSCoreStateSize(struct mCore* core) {
314	UNUSED(core);
315	return 0;
316}
317
318static bool _DSCoreLoadState(struct mCore* core, const void* state) {
319	return false;
320}
321
322static bool _DSCoreSaveState(struct mCore* core, void* state) {
323	return false;
324}
325
326static void _DSCoreSetKeys(struct mCore* core, uint32_t keys) {
327	struct DSCore* dscore = (struct DSCore*) core;
328	dscore->keys = keys;
329}
330
331static void _DSCoreAddKeys(struct mCore* core, uint32_t keys) {
332	struct DSCore* dscore = (struct DSCore*) core;
333	dscore->keys |= keys;
334}
335
336static void _DSCoreClearKeys(struct mCore* core, uint32_t keys) {
337	struct DSCore* dscore = (struct DSCore*) core;
338	dscore->keys &= ~keys;
339}
340
341static void _DSCoreSetCursorLocation(struct mCore* core, int x, int y) {
342	struct DSCore* dscore = (struct DSCore*) core;
343	dscore->cursorX = x;
344	dscore->cursorY = y - DS_VIDEO_VERTICAL_PIXELS;
345	if (dscore->cursorY < 0) {
346		dscore->cursorY = 0;
347	}
348}
349
350static void _DSCoreSetCursorDown(struct mCore* core, bool down) {
351	struct DSCore* dscore = (struct DSCore*) core;
352	dscore->touchDown = down;
353}
354
355static int32_t _DSCoreFrameCounter(const struct mCore* core) {
356	struct DS* ds = core->board;
357	return ds->video.frameCounter;
358}
359
360static int32_t _DSCoreFrameCycles(const struct mCore* core) {
361	UNUSED(core);
362	return DS_VIDEO_TOTAL_LENGTH;
363}
364
365static int32_t _DSCoreFrequency(const struct mCore* core) {
366	UNUSED(core);
367	return DS_ARM946ES_FREQUENCY;
368}
369
370static void _DSCoreGetGameTitle(const struct mCore* core, char* title) {
371	DSGetGameTitle(core->board, title);
372}
373
374static void _DSCoreGetGameCode(const struct mCore* core, char* title) {
375	DSGetGameCode(core->board, title);
376}
377
378static void _DSCoreSetRotation(struct mCore* core, struct mRotationSource* rotation) {
379}
380
381static void _DSCoreSetRumble(struct mCore* core, struct mRumble* rumble) {
382	struct DS* ds = core->board;
383	ds->rumble = rumble;
384}
385
386static uint32_t _DSCoreBusRead8(struct mCore* core, uint32_t address) {
387	struct ARMCore* cpu = core->cpu;
388	return cpu->memory.load8(cpu, address, 0);
389}
390
391static uint32_t _DSCoreBusRead16(struct mCore* core, uint32_t address) {
392	struct ARMCore* cpu = core->cpu;
393	return cpu->memory.load16(cpu, address, 0);
394
395}
396
397static uint32_t _DSCoreBusRead32(struct mCore* core, uint32_t address) {
398	struct ARMCore* cpu = core->cpu;
399	return cpu->memory.load32(cpu, address, 0);
400}
401
402static void _DSCoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
403	struct ARMCore* cpu = core->cpu;
404	cpu->memory.store8(cpu, address, value, 0);
405}
406
407static void _DSCoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
408	struct ARMCore* cpu = core->cpu;
409	cpu->memory.store16(cpu, address, value, 0);
410}
411
412static void _DSCoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
413	struct ARMCore* cpu = core->cpu;
414	cpu->memory.store32(cpu, address, value, 0);
415}
416
417static uint32_t _DSCoreRawRead8(struct mCore* core, uint32_t address, int segment) {
418	// TODO: Raw
419	struct ARMCore* cpu = core->cpu;
420	return cpu->memory.load8(cpu, address, 0);
421}
422
423static uint32_t _DSCoreRawRead16(struct mCore* core, uint32_t address, int segment) {
424	// TODO: Raw
425	struct ARMCore* cpu = core->cpu;
426	return cpu->memory.load16(cpu, address, 0);
427}
428
429static uint32_t _DSCoreRawRead32(struct mCore* core, uint32_t address, int segment) {
430	// TODO: Raw
431	struct ARMCore* cpu = core->cpu;
432	return cpu->memory.load32(cpu, address, 0);
433}
434
435static void _DSCoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) {
436}
437
438static void _DSCoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) {
439}
440
441static void _DSCoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) {
442}
443
444#ifdef USE_DEBUGGERS
445static bool _DSCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
446	UNUSED(core);
447	switch (type) {
448	case DEBUGGER_CLI:
449		return true;
450#ifdef USE_GDB_STUB
451	case DEBUGGER_GDB:
452		return true;
453#endif
454	default:
455		return false;
456	}
457}
458
459static struct mDebuggerPlatform* _DSCoreDebuggerPlatform(struct mCore* core) {
460	struct DSCore* dscore = (struct DSCore*) core;
461	if (!dscore->debuggerPlatform) {
462		dscore->debuggerPlatform = ARMDebuggerPlatformCreate();
463	}
464	return dscore->debuggerPlatform;
465}
466
467static struct CLIDebuggerSystem* _DSCoreCliDebuggerSystem(struct mCore* core) {
468	return &DSCLIDebuggerCreate(core)->d;
469}
470
471static void _DSCoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
472	if (core->debugger) {
473		DSDetachDebugger(core->board);
474	}
475	DSAttachDebugger(core->board, debugger);
476	core->debugger = debugger;
477}
478
479static void _DSCoreDetachDebugger(struct mCore* core) {
480	DSDetachDebugger(core->board);
481	core->debugger = NULL;
482}
483#endif
484
485static struct mCheatDevice* _DSCoreCheatDevice(struct mCore* core) {
486	return NULL;
487}
488
489static size_t _DSCoreSavedataClone(struct mCore* core, void** sram) {
490	return 0;
491}
492
493static bool _DSCoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
494	return false;
495}
496
497struct mCore* DSCoreCreate(void) {
498	struct DSCore* dscore = malloc(sizeof(*dscore));
499	struct mCore* core = &dscore->d;
500	memset(&core->opts, 0, sizeof(core->opts));
501	core->cpu = NULL;
502	core->board = NULL;
503	core->debugger = NULL;
504	core->init = _DSCoreInit;
505	core->deinit = _DSCoreDeinit;
506	core->platform = _DSCorePlatform;
507	core->setSync = _DSCoreSetSync;
508	core->loadConfig = _DSCoreLoadConfig;
509	core->desiredVideoDimensions = _DSCoreDesiredVideoDimensions;
510	core->setVideoBuffer = _DSCoreSetVideoBuffer;
511	core->getPixels = _DSCoreGetPixels;
512	core->putPixels = _DSCorePutPixels;
513	core->getAudioChannel = _DSCoreGetAudioChannel;
514	core->setAudioBufferSize = _DSCoreSetAudioBufferSize;
515	core->getAudioBufferSize = _DSCoreGetAudioBufferSize;
516	core->addCoreCallbacks = _DSCoreAddCoreCallbacks;
517	core->clearCoreCallbacks = _DSCoreClearCoreCallbacks;
518	core->setAVStream = _DSCoreSetAVStream;
519	core->isROM = DSIsROM;
520	core->loadROM = _DSCoreLoadROM;
521	core->loadBIOS = _DSCoreLoadBIOS;
522	core->loadSave = _DSCoreLoadSave;
523	core->loadPatch = _DSCoreLoadPatch;
524	core->unloadROM = _DSCoreUnloadROM;
525	core->checksum = _DSCoreChecksum;
526	core->reset = _DSCoreReset;
527	core->runFrame = _DSCoreRunFrame;
528	core->runLoop = _DSCoreRunLoop;
529	core->step = _DSCoreStep;
530	core->stateSize = _DSCoreStateSize;
531	core->loadState = _DSCoreLoadState;
532	core->saveState = _DSCoreSaveState;
533	core->setKeys = _DSCoreSetKeys;
534	core->addKeys = _DSCoreAddKeys;
535	core->clearKeys = _DSCoreClearKeys;
536	core->setCursorLocation = _DSCoreSetCursorLocation;
537	core->setCursorDown = _DSCoreSetCursorDown;
538	core->frameCounter = _DSCoreFrameCounter;
539	core->frameCycles = _DSCoreFrameCycles;
540	core->frequency = _DSCoreFrequency;
541	core->getGameTitle = _DSCoreGetGameTitle;
542	core->getGameCode = _DSCoreGetGameCode;
543	core->setRotation = _DSCoreSetRotation;
544	core->setRumble = _DSCoreSetRumble;
545	core->busRead8 = _DSCoreBusRead8;
546	core->busRead16 = _DSCoreBusRead16;
547	core->busRead32 = _DSCoreBusRead32;
548	core->busWrite8 = _DSCoreBusWrite8;
549	core->busWrite16 = _DSCoreBusWrite16;
550	core->busWrite32 = _DSCoreBusWrite32;
551	core->rawRead8 = _DSCoreRawRead8;
552	core->rawRead16 = _DSCoreRawRead16;
553	core->rawRead32 = _DSCoreRawRead32;
554	core->rawWrite8 = _DSCoreRawWrite8;
555	core->rawWrite16 = _DSCoreRawWrite16;
556	core->rawWrite32 = _DSCoreRawWrite32;
557#ifdef USE_DEBUGGERS
558	core->supportsDebuggerType = _DSCoreSupportsDebuggerType;
559	core->debuggerPlatform = _DSCoreDebuggerPlatform;
560	core->cliDebuggerSystem = _DSCoreCliDebuggerSystem;
561	core->attachDebugger = _DSCoreAttachDebugger;
562	core->detachDebugger = _DSCoreDetachDebugger;
563#endif
564	core->cheatDevice = _DSCoreCheatDevice;
565	core->savedataClone = _DSCoreSavedataClone;
566	core->savedataRestore = _DSCoreSavedataRestore;
567	return core;
568}