all repos — mgba @ aaeef69d968f45352a8bfcdb1807da284a76fe89

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