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