all repos — mgba @ d620a8c38c9f49fb4b40a26c0954f0cff2147ab5

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