all repos — mgba @ 2ab7289a059ab3055f00f0677f7c20bfed7591d5

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