all repos — mgba @ ae5547ea51aa7dbb6dc89e21f64a11ed91b9989b

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