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