all repos — mgba @ e75cb6f7b4cdea9ee94c9af590172acb33a02ae6

mGBA Game Boy Advance Emulator

DS: Start DS core
Jeffrey Pfau jeffrey@endrift.com
Wed, 01 Jun 2016 01:29:11 -0700
commit

e75cb6f7b4cdea9ee94c9af590172acb33a02ae6

parent

4ac4733cfd4c4524c6a56d0406ba138d173fad61

M CMakeLists.txtCMakeLists.txt

@@ -17,6 +17,7 @@ set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable LIBZIP support")

set(USE_MAGICK ON CACHE BOOL "Whether or not to enable ImageMagick support") set(M_CORE_GBA ON CACHE BOOL "Build Game Boy Advance core") set(M_CORE_GB ON CACHE BOOL "Build Game Boy core") +set(M_CORE_DS ON CACHE BOOL "Build DS core") set(USE_LZMA ON CACHE BOOL "Whether or not to enable 7-Zip support") set(BUILD_QT ON CACHE BOOL "Build Qt frontend") set(BUILD_SDL ON CACHE BOOL "Build SDL frontend")

@@ -43,6 +44,7 @@ file(GLOB GBA_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/*.c)

file(GLOB GBA_TEST_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/test/*.c) file(GLOB GB_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/*.c) file(GLOB GB_TEST_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/test/*.c) +file(GLOB DS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/ds/*.c) file(GLOB GBA_CHEATS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/cheats/*.c) file(GLOB GBA_RR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/rr/*.c) file(GLOB CORE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/core/*.c)

@@ -62,6 +64,7 @@ source_group("LR35902 core" FILES ${LR35902_SRC})

source_group("GBA board" FILES ${GBA_SRC} ${GBA_RENDERER_SRC} ${SIO_SRC}) source_group("GBA extra" FILES ${GBA_CHEATS_SRC} ${GBA_RR_SRC}) source_group("GB board" FILES ${GB_SRC}) +source_group("DS board" FILES ${DS_SRC}) source_group("Utilities" FILES ${UTIL_SRC}) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/src)

@@ -373,6 +376,19 @@ endif()

if(USE_EDITLINE) list(APPEND FEATURES EDITLINE) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/debugger/cli-debugger.c) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/debugger/parser.c) + if(M_CORE_GBA) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/arm/debugger/cli-debugger.c) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/extra/cli.c) + endif() + if(M_CORE_GB) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/cli-debugger.c) + endif() + if(M_CORE_DS) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/arm/debugger/cli-debugger.c) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/ds/extra/cli.c) + endif() include_directories(AFTER ${LIBEDIT_INCLUDE_DIRS}) link_directories(${LIBEDIT_LIBRARY_DIRS}) set(DEBUGGER_LIB ${LIBEDIT_LIBRARIES})

@@ -584,6 +600,15 @@ set(FEATURE_DEFINES)

foreach(FEATURE IN LISTS FEATURES) list(APPEND FEATURE_DEFINES "USE_${FEATURE}") endforeach() + +if(M_CORE_DS) + add_definitions(-DM_CORE_DS) + list(APPEND CORE_SRC + ${ARM_SRC} + ${CMAKE_CURRENT_SOURCE_DIR}/src/arm/debugger/debugger.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/arm/debugger/memory-debugger.c + ${DS_SRC}) +endif() source_group("Virtual files" FILES ${CORE_VFS_SRC} ${VFS_SRC}) source_group("Extra features" FILES ${FEATURE_SRC})
M src/core/core.csrc/core/core.c

@@ -17,6 +17,10 @@ #ifdef M_CORE_GBA

#include "gba/core.h" #include "gba/gba.h" #endif +#ifdef M_CORE_DS +#include "ds/core.h" +#include "ds/ds.h" +#endif static struct mCoreFilter { bool (*filter)(struct VFile*);

@@ -28,6 +32,9 @@ { GBAIsROM, GBACoreCreate, PLATFORM_GBA },

#endif #ifdef M_CORE_GB { GBIsROM, GBCoreCreate, PLATFORM_GB }, +#endif +#ifdef M_CORE_DS + { DSIsROM, DSCoreCreate, PLATFORM_DS }, #endif { 0, 0, PLATFORM_NONE } };
M src/core/core.hsrc/core/core.h

@@ -28,6 +28,9 @@ #endif

#ifdef M_CORE_GB PLATFORM_GB, #endif +#ifdef M_CORE_DS + PLATFORM_DS, +#endif }; struct mRTCSource;
A src/ds/core.c

@@ -0,0 +1,403 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "core.h" + +#include "core/cheats.h" +#include "core/core.h" +#include "core/log.h" +#include "arm/debugger/debugger.h" +#include "ds/ds.h" +#include "ds/extra/cli.h" +#include "util/memory.h" +#include "util/patch.h" +#include "util/vfs.h" + +struct DSCore { + struct mCore d; + struct ARMCore* arm7; + int keys; + struct mCPUComponent* components[CPU_COMPONENT_MAX]; + struct mDebuggerPlatform* debuggerPlatform; + struct mCheatDevice* cheatDevice; +}; + +static bool _DSCoreInit(struct mCore* core) { + struct DSCore* dscore = (struct DSCore*) core; + + struct ARMCore* arm7 = anonymousMemoryMap(sizeof(struct ARMCore)); + struct ARMCore* arm9 = anonymousMemoryMap(sizeof(struct ARMCore)); + struct DS* ds = anonymousMemoryMap(sizeof(struct DS)); + if (!arm7 || !arm9 || !ds) { + free(arm7); + free(arm9); + free(ds); + return false; + } + core->cpu = arm9; + core->board = ds; + core->debugger = NULL; + dscore->arm7 = arm7; + dscore->debuggerPlatform = NULL; + dscore->cheatDevice = NULL; + + DSCreate(ds); + memset(dscore->components, 0, sizeof(dscore->components)); + ARMSetComponents(arm7, &ds->d, CPU_COMPONENT_MAX, dscore->components); + ARMSetComponents(arm9, &ds->d, CPU_COMPONENT_MAX, dscore->components); + ARMInit(arm7); + ARMInit(arm9); + + dscore->keys = 0; + ds->keySource = &dscore->keys; + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 + mDirectorySetInit(&core->dirs); +#endif + + return true; +} + +static void _DSCoreDeinit(struct mCore* core) { + struct DSCore* dscore = (struct DSCore*) core; + ARMDeinit(core->cpu); + ARMDeinit(dscore->arm7); + DSDestroy(core->board); + mappedMemoryFree(core->cpu, sizeof(struct ARMCore)); + mappedMemoryFree(dscore->arm7, sizeof(struct ARMCore)); + mappedMemoryFree(core->board, sizeof(struct DS)); +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 + mDirectorySetDeinit(&core->dirs); +#endif + + free(dscore->debuggerPlatform); + if (dscore->cheatDevice) { + mCheatDeviceDestroy(dscore->cheatDevice); + } + free(dscore->cheatDevice); + free(core); +} + +static enum mPlatform _DSCorePlatform(struct mCore* core) { + UNUSED(core); + return PLATFORM_DS; +} + +static void _DSCoreSetSync(struct mCore* core, struct mCoreSync* sync) { + struct DS* ds = core->board; + ds->sync = sync; +} + +static void _DSCoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) { +} + +static void _DSCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) { + UNUSED(core); + *width = DS_VIDEO_HORIZONTAL_PIXELS; + *height = DS_VIDEO_VERTICAL_PIXELS; +} + +static void _DSCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) { +} + +static void _DSCoreGetVideoBuffer(struct mCore* core, color_t** buffer, size_t* stride) { +} + +static struct blip_t* _DSCoreGetAudioChannel(struct mCore* core, int ch) { + return NULL; +} + +static void _DSCoreSetAudioBufferSize(struct mCore* core, size_t samples) { +} + +static size_t _DSCoreGetAudioBufferSize(struct mCore* core) { + return 2048; +} + +static void _DSCoreSetAVStream(struct mCore* core, struct mAVStream* stream) { +} + +static bool _DSCoreLoadROM(struct mCore* core, struct VFile* vf) { + return DSLoadROM(core->board, vf); +} + +static bool _DSCoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) { + return false; +} + +static bool _DSCoreLoadSave(struct mCore* core, struct VFile* vf) { + return false; +} + +static bool _DSCoreLoadPatch(struct mCore* core, struct VFile* vf) { + return false; +} + +static void _DSCoreUnloadROM(struct mCore* core) { + return DSUnloadROM(core->board); +} + +static void _DSCoreReset(struct mCore* core) { + struct DSCore* dscore = (struct DSCore*) core; + struct DS* ds = (struct DS*) core->board; + ARMReset(ds->arm7); + ARMReset(ds->arm9); +} + +static void _DSCoreRunFrame(struct mCore* core) { + struct DS* ds = core->board; + int32_t frameCounter = ds->video.frameCounter; + while (ds->video.frameCounter == frameCounter) { + ARMRunLoop(core->cpu); + } +} + +static void _DSCoreRunLoop(struct mCore* core) { + ARMRunLoop(core->cpu); +} + +static void _DSCoreStep(struct mCore* core) { + ARMRun(core->cpu); +} + +static size_t _DSCoreStateSize(struct mCore* core) { + UNUSED(core); + return 0; +} + +static bool _DSCoreLoadState(struct mCore* core, const void* state) { + return false; +} + +static bool _DSCoreSaveState(struct mCore* core, void* state) { + return false; +} + +static void _DSCoreSetKeys(struct mCore* core, uint32_t keys) { + struct DSCore* dscore = (struct DSCore*) core; + dscore->keys = keys; +} + +static void _DSCoreAddKeys(struct mCore* core, uint32_t keys) { + struct DSCore* dscore = (struct DSCore*) core; + dscore->keys |= keys; +} + +static void _DSCoreClearKeys(struct mCore* core, uint32_t keys) { + struct DSCore* dscore = (struct DSCore*) core; + dscore->keys &= ~keys; +} + +static int32_t _DSCoreFrameCounter(struct mCore* core) { + struct DS* ds = core->board; + return ds->video.frameCounter; +} + +static int32_t _DSCoreFrameCycles(struct mCore* core) { + UNUSED(core); + return DS_VIDEO_TOTAL_LENGTH; +} + +static int32_t _DSCoreFrequency(struct mCore* core) { + UNUSED(core); + return DS_ARM946ES_FREQUENCY; +} + +static void _DSCoreGetGameTitle(struct mCore* core, char* title) { + DSGetGameTitle(core->board, title); +} + +static void _DSCoreGetGameCode(struct mCore* core, char* title) { + DSGetGameCode(core->board, title); +} + +static void _DSCoreSetRTC(struct mCore* core, struct mRTCSource* rtc) { + struct DS* ds = core->board; + ds->rtcSource = rtc; +} + +static void _DSCoreSetRotation(struct mCore* core, struct mRotationSource* rotation) { +} + +static void _DSCoreSetRumble(struct mCore* core, struct mRumble* rumble) { + struct DS* ds = core->board; + ds->rumble = rumble; +} + +static uint32_t _DSCoreBusRead8(struct mCore* core, uint32_t address) { + struct ARMCore* cpu = core->cpu; + return cpu->memory.load8(cpu, address, 0); +} + +static uint32_t _DSCoreBusRead16(struct mCore* core, uint32_t address) { + struct ARMCore* cpu = core->cpu; + return cpu->memory.load16(cpu, address, 0); + +} + +static uint32_t _DSCoreBusRead32(struct mCore* core, uint32_t address) { + struct ARMCore* cpu = core->cpu; + return cpu->memory.load32(cpu, address, 0); +} + +static void _DSCoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) { + struct ARMCore* cpu = core->cpu; + cpu->memory.store8(cpu, address, value, 0); +} + +static void _DSCoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) { + struct ARMCore* cpu = core->cpu; + cpu->memory.store16(cpu, address, value, 0); +} + +static void _DSCoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) { + struct ARMCore* cpu = core->cpu; + cpu->memory.store32(cpu, address, value, 0); +} + +static uint32_t _DSCoreRawRead8(struct mCore* core, uint32_t address) { + return 0; +} + +static uint32_t _DSCoreRawRead16(struct mCore* core, uint32_t address) { + return 0; +} + +static uint32_t _DSCoreRawRead32(struct mCore* core, uint32_t address) { + return 0; +} + +static void _DSCoreRawWrite8(struct mCore* core, uint32_t address, uint8_t value) { +} + +static void _DSCoreRawWrite16(struct mCore* core, uint32_t address, uint16_t value) { +} + +static void _DSCoreRawWrite32(struct mCore* core, uint32_t address, uint32_t value) { +} + +static bool _DSCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) { + UNUSED(core); + switch (type) { +#ifdef USE_CLI_DEBUGGER + case DEBUGGER_CLI: + return true; +#endif +#ifdef USE_GDB_STUB + case DEBUGGER_GDB: + return true; +#endif + default: + return false; + } +} + +static struct mDebuggerPlatform* _DSCoreDebuggerPlatform(struct mCore* core) { + struct DSCore* dscore = (struct DSCore*) core; + if (!dscore->debuggerPlatform) { + dscore->debuggerPlatform = ARMDebuggerPlatformCreate(); + } + return dscore->debuggerPlatform; +} + +static struct CLIDebuggerSystem* _DSCoreCliDebuggerSystem(struct mCore* core) { +#ifdef USE_CLI_DEBUGGER + return &DSCLIDebuggerCreate(core)->d; +#else + UNUSED(core); + return NULL; +#endif +} + +static void _DSCoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) { + if (core->debugger) { + DSDetachDebugger(core->board); + } + DSAttachDebugger(core->board, debugger); + core->debugger = debugger; +} + +static void _DSCoreDetachDebugger(struct mCore* core) { + DSDetachDebugger(core->board); + core->debugger = NULL; +} + +static struct mCheatDevice* _DSCoreCheatDevice(struct mCore* core) { + return NULL; +} + +static size_t _DSCoreSavedataClone(struct mCore* core, void** sram) { + return 0; +} + +static bool _DSCoreSavedataLoad(struct mCore* core, const void* sram, size_t size) { + return false; +} + +struct mCore* DSCoreCreate(void) { + struct DSCore* dscore = malloc(sizeof(*dscore)); + struct mCore* core = &dscore->d; + memset(&core->opts, 0, sizeof(core->opts)); + core->cpu = NULL; + core->board = NULL; + core->debugger = NULL; + core->init = _DSCoreInit; + core->deinit = _DSCoreDeinit; + core->platform = _DSCorePlatform; + core->setSync = _DSCoreSetSync; + core->loadConfig = _DSCoreLoadConfig; + core->desiredVideoDimensions = _DSCoreDesiredVideoDimensions; + core->setVideoBuffer = _DSCoreSetVideoBuffer; + core->getVideoBuffer = _DSCoreGetVideoBuffer; + core->getAudioChannel = _DSCoreGetAudioChannel; + core->setAudioBufferSize = _DSCoreSetAudioBufferSize; + core->getAudioBufferSize = _DSCoreGetAudioBufferSize; + core->setAVStream = _DSCoreSetAVStream; + core->isROM = DSIsROM; + core->loadROM = _DSCoreLoadROM; + core->loadBIOS = _DSCoreLoadBIOS; + core->loadSave = _DSCoreLoadSave; + core->loadPatch = _DSCoreLoadPatch; + core->unloadROM = _DSCoreUnloadROM; + core->reset = _DSCoreReset; + core->runFrame = _DSCoreRunFrame; + core->runLoop = _DSCoreRunLoop; + core->step = _DSCoreStep; + core->stateSize = _DSCoreStateSize; + core->loadState = _DSCoreLoadState; + core->saveState = _DSCoreSaveState; + core->setKeys = _DSCoreSetKeys; + core->addKeys = _DSCoreAddKeys; + core->clearKeys = _DSCoreClearKeys; + core->frameCounter = _DSCoreFrameCounter; + core->frameCycles = _DSCoreFrameCycles; + core->frequency = _DSCoreFrequency; + core->getGameTitle = _DSCoreGetGameTitle; + core->getGameCode = _DSCoreGetGameCode; + core->setRTC = _DSCoreSetRTC; + core->setRotation = _DSCoreSetRotation; + core->setRumble = _DSCoreSetRumble; + core->busRead8 = _DSCoreBusRead8; + core->busRead16 = _DSCoreBusRead16; + core->busRead32 = _DSCoreBusRead32; + core->busWrite8 = _DSCoreBusWrite8; + core->busWrite16 = _DSCoreBusWrite16; + core->busWrite32 = _DSCoreBusWrite32; + core->rawRead8 = _DSCoreRawRead8; + core->rawRead16 = _DSCoreRawRead16; + core->rawRead32 = _DSCoreRawRead32; + core->rawWrite8 = _DSCoreRawWrite8; + core->rawWrite16 = _DSCoreRawWrite16; + core->rawWrite32 = _DSCoreRawWrite32; + core->supportsDebuggerType = _DSCoreSupportsDebuggerType; + core->debuggerPlatform = _DSCoreDebuggerPlatform; + core->cliDebuggerSystem = _DSCoreCliDebuggerSystem; + core->attachDebugger = _DSCoreAttachDebugger; + core->detachDebugger = _DSCoreDetachDebugger; + core->cheatDevice = _DSCoreCheatDevice; + core->savedataClone = _DSCoreSavedataClone; + core->savedataLoad = _DSCoreSavedataLoad; + return core; +}
A src/ds/core.h

@@ -0,0 +1,12 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef DS_CORE_H +#define DS_CORE_H + +struct mCore; +struct mCore* DSCoreCreate(void); + +#endif
A src/ds/ds.c

@@ -0,0 +1,267 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "ds.h" + +#include "arm/decoder.h" +#include "arm/debugger/debugger.h" +#include "arm/isa-inlines.h" + +#include "util/crc32.h" +#include "util/memory.h" +#include "util/math.h" +#include "util/patch.h" +#include "util/vfs.h" + +mLOG_DEFINE_CATEGORY(DS, "DS"); + +const uint32_t DS_ARM946ES_FREQUENCY = 0x1FF61FE; +const uint32_t DS_ARM7TDMI_FREQUENCY = 0xFFB0FF; +const uint32_t DS_COMPONENT_MAGIC = 0x1FF61FE; + +static const size_t DS_ROM_MAGIC_OFFSET = 0x15C; +static const uint8_t DS_ROM_MAGIC[] = { 0x56, 0xCF }; + +enum { + DS7_SP_BASE = 0x380FD80, + DS7_SP_BASE_IRQ = 0x380FF80, + DS7_SP_BASE_SVC = 0x380FFC0, + + DS9_SP_BASE = 0x3002F7C, + DS9_SP_BASE_IRQ = 0x3003F80, + DS9_SP_BASE_SVC = 0x3003FC0, +}; + +static void DSInit(void* cpu, struct mCPUComponent* component); + +static void DS7Reset(struct ARMCore* cpu); +static void DS7InterruptHandlerInit(struct ARMInterruptHandler* irqh); + +static void DS9Reset(struct ARMCore* cpu); +static void DS9InterruptHandlerInit(struct ARMInterruptHandler* irqh); + +static void DSProcessEvents(struct ARMCore* cpu); +static void DSHitStub(struct ARMCore* cpu, uint32_t opcode); +static void DSIllegal(struct ARMCore* cpu, uint32_t opcode); +static void DSBreakpoint(struct ARMCore* cpu, int immediate); + +void DSCreate(struct DS* ds) { + ds->d.id = DS_COMPONENT_MAGIC; + ds->d.init = DSInit; + ds->d.deinit = NULL; + ds->arm7 = NULL; + ds->arm9 = NULL; +} + +static void DSInit(void* cpu, struct mCPUComponent* component) { + struct DS* ds = (struct DS*) component; + struct ARMCore* core = cpu; + if (!ds->arm7) { + // The ARM7 must get initialized first + ds->arm7 = core; + ds->debugger = 0; + ds->sync = 0; + return; + } + ds->arm9 = cpu; + + DS7InterruptHandlerInit(&ds->arm7->irqh); + DS9InterruptHandlerInit(&ds->arm9->irqh); + + ds->video.p = ds; + + ds->springIRQ7 = 0; + ds->springIRQ9 = 0; + ds->keySource = NULL; + ds->rtcSource = NULL; + ds->rumble = NULL; + + ds->romVf = NULL; + + ds->keyCallback = NULL; +} + +void DSUnloadROM(struct DS* ds) { + if (ds->romVf) { + ds->romVf->close(ds->romVf); + ds->romVf = NULL; + } +} + +void DSDestroy(struct DS* ds) { + DSUnloadROM(ds); +} + +void DS7InterruptHandlerInit(struct ARMInterruptHandler* irqh) { + irqh->reset = DS7Reset; + irqh->processEvents = DSProcessEvents; + irqh->swi16 = NULL; + irqh->swi32 = NULL; + irqh->hitIllegal = DSIllegal; + irqh->readCPSR = NULL; + irqh->hitStub = DSHitStub; + irqh->bkpt16 = DSBreakpoint; + irqh->bkpt32 = DSBreakpoint; +} + +void DS9InterruptHandlerInit(struct ARMInterruptHandler* irqh) { + irqh->reset = DS9Reset; + irqh->processEvents = DSProcessEvents; + irqh->swi16 = NULL; + irqh->swi32 = NULL; + irqh->hitIllegal = DSIllegal; + irqh->readCPSR = NULL; + irqh->hitStub = DSHitStub; + irqh->bkpt16 = DSBreakpoint; + irqh->bkpt32 = DSBreakpoint; +} + +void DS7Reset(struct ARMCore* cpu) { + ARMSetPrivilegeMode(cpu, MODE_IRQ); + cpu->gprs[ARM_SP] = DS7_SP_BASE_IRQ; + ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR); + cpu->gprs[ARM_SP] = DS7_SP_BASE_SVC; + ARMSetPrivilegeMode(cpu, MODE_SYSTEM); + cpu->gprs[ARM_SP] = DS7_SP_BASE; +} + +void DS9Reset(struct ARMCore* cpu) { + ARMSetPrivilegeMode(cpu, MODE_IRQ); + cpu->gprs[ARM_SP] = DS9_SP_BASE_IRQ; + ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR); + cpu->gprs[ARM_SP] = DS9_SP_BASE_SVC; + ARMSetPrivilegeMode(cpu, MODE_SYSTEM); + cpu->gprs[ARM_SP] = DS9_SP_BASE; +} + +static void DSProcessEvents(struct ARMCore* cpu) { + struct DS* ds = (struct DS*) cpu->master; + + if (ds->springIRQ7) { + ARMRaiseIRQ(cpu); + ds->springIRQ7 = 0; + } + + do { + int32_t cycles = cpu->nextEvent; + int32_t nextEvent = INT_MAX; +#ifndef NDEBUG + if (cycles < 0) { + mLOG(DS, FATAL, "Negative cycles passed: %i", cycles); + } +#endif + + cpu->cycles -= cycles; + cpu->nextEvent = nextEvent; + + if (cpu->halted) { + cpu->cycles = cpu->nextEvent; + } + } while (cpu->cycles >= cpu->nextEvent); +} + +void DSAttachDebugger(struct DS* ds, struct mDebugger* debugger) { + ds->debugger = (struct ARMDebugger*) debugger->platform; + ds->arm7->components[CPU_COMPONENT_DEBUGGER] = &debugger->d; + ds->arm9->components[CPU_COMPONENT_DEBUGGER] = &debugger->d; + ARMHotplugAttach(ds->arm7, CPU_COMPONENT_DEBUGGER); + ARMHotplugAttach(ds->arm9, CPU_COMPONENT_DEBUGGER); +} + + +void DSDetachDebugger(struct DS* ds) { + ds->debugger = NULL; + ARMHotplugDetach(ds->arm7, CPU_COMPONENT_DEBUGGER); + ARMHotplugDetach(ds->arm9, CPU_COMPONENT_DEBUGGER); + ds->arm7->components[CPU_COMPONENT_DEBUGGER] = NULL; + ds->arm9->components[CPU_COMPONENT_DEBUGGER] = NULL; +} + +bool DSLoadROM(struct DS* ds, struct VFile* vf) { + DSUnloadROM(ds); + ds->romVf = vf; + // TODO: Checksum? + // TODO: error check + return true; +} + +bool DSIsROM(struct VFile* vf) { + if (vf->seek(vf, DS_ROM_MAGIC_OFFSET, SEEK_SET) < 0) { + return false; + } + uint8_t signature[sizeof(DS_ROM_MAGIC)]; + if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) { + return false; + } + return memcmp(signature, DS_ROM_MAGIC, sizeof(signature)) == 0; +} + +void DSGetGameCode(struct DS* ds, char* out) { + memset(out, 0, 8); + if (!ds->romVf) { + return; + } + + struct DSCartridge* cart = ds->romVf->map(ds->romVf, sizeof(*cart), MAP_READ); + memcpy(out, "NTR-", 4); + memcpy(&out[4], &cart->id, 4); + ds->romVf->unmap(ds->romVf, cart, sizeof(*cart)); +} + +void DSGetGameTitle(struct DS* ds, char* out) { + memset(out, 0, 12); + if (!ds->romVf) { + return; + } + + struct DSCartridge* cart = ds->romVf->map(ds->romVf, sizeof(*cart), MAP_READ); + memcpy(out, &cart->title, 4); + ds->romVf->unmap(ds->romVf, cart, sizeof(*cart)); +} + +void DSHitStub(struct ARMCore* cpu, uint32_t opcode) { + struct DS* ds = (struct DS*) cpu->master; + if (ds->debugger) { + struct mDebuggerEntryInfo info = { + .address = _ARMPCAddress(cpu), + .opcode = opcode + }; + mDebuggerEnter(ds->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info); + } + // TODO: More sensible category? + mLOG(DS, ERROR, "Stub opcode: %08x", opcode); +} + +void DSIllegal(struct ARMCore* cpu, uint32_t opcode) { + struct DS* ds = (struct DS*) cpu->master; + if (ds->debugger) { + struct mDebuggerEntryInfo info = { + .address = _ARMPCAddress(cpu), + .opcode = opcode + }; + mDebuggerEnter(ds->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info); + } else { + ARMRaiseUndefined(cpu); + } +} + +void DSBreakpoint(struct ARMCore* cpu, int immediate) { + struct DS* ds = (struct DS*) cpu->master; + if (immediate >= CPU_COMPONENT_MAX) { + return; + } + switch (immediate) { + case CPU_COMPONENT_DEBUGGER: + if (ds->debugger) { + struct mDebuggerEntryInfo info = { + .address = _ARMPCAddress(cpu) + }; + mDebuggerEnter(ds->debugger->d.p, DEBUGGER_ENTER_BREAKPOINT, &info); + } + break; + default: + break; + } +}
A src/ds/ds.h

@@ -0,0 +1,128 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef DS_H +#define DS_H + +#include "util/common.h" + +#include "arm/arm.h" +#include "core/log.h" + +#include "ds/video.h" + +extern const uint32_t DS_ARM946ES_FREQUENCY; +extern const uint32_t DS_ARM7TDMI_FREQUENCY; + +enum DSIRQ { + DS_IRQ_VBLANK = 0x0, + DS_IRQ_HBLANK = 0x1, + DS_IRQ_VCOUNTER = 0x2, + DS_IRQ_TIMER0 = 0x3, + DS_IRQ_TIMER1 = 0x4, + DS_IRQ_TIMER2 = 0x5, + DS_IRQ_TIMER3 = 0x6, + DS_IRQ_SIO = 0x7, + DS_IRQ_DMA0 = 0x8, + DS_IRQ_DMA1 = 0x9, + DS_IRQ_DMA2 = 0xA, + DS_IRQ_DMA3 = 0xB, + DS_IRQ_KEYPAD = 0xC, + DS_IRQ_SLOT2 = 0xD, + DS_IRQ_IPC_SYNC = 0x10, + DS_IRQ_IPC_EMPTY = 0x11, + DS_IRQ_IPC_NOT_EMPTY = 0x12, + DS_IRQ_SLOT1_TRANS = 0x13, + DS_IRQ_SLOT1 = 0x14, + DS_IRQ_GEOM_FIFO = 0x15, + DS_IRQ_LID = 0x16, + DS_IRQ_SPI = 0x17, + DS_IRQ_WIFI = 0x18, +}; + +struct DS; +struct Patch; +struct VFile; +struct mDebugger; + +mLOG_DECLARE_CATEGORY(DS); + +struct DS { + struct mCPUComponent d; + + struct ARMCore* arm7; + struct ARMCore* arm9; + struct DSVideo video; + + struct mCoreSync* sync; + + struct ARMDebugger* debugger; + + int springIRQ7; + int springIRQ9; + + uint32_t biosChecksum; + int* keySource; + struct mRTCSource* rtcSource; + struct mRumble* rumble; + + uint32_t romCrc32; + struct VFile* romVf; + + struct mKeyCallback* keyCallback; +}; + +struct DSCartridge { + char title[12]; + uint32_t id; + + uint16_t maker; + uint8_t type; + uint8_t encryptionSeed; + uint8_t size; + uint8_t reserved[8]; + uint8_t region; + uint8_t version; + uint8_t autostart; + uint32_t arm9Offset; + uint32_t arm9Entry; + uint32_t arm9Base; + uint32_t arm9Size; + uint32_t arm7Offset; + uint32_t arm7Entry; + uint32_t arm7Base; + uint32_t arm7Size; + uint32_t fntOffset; + uint32_t fntSize; + uint32_t fatOffset; + uint32_t fatSize; + uint32_t arm9FileOverlayOffset; + uint32_t arm9FileOverlaySize; + uint32_t arm7FileOverlayOffset; + uint32_t arm7FileOverlaySize; + uint32_t busTiming; + uint32_t busKEY1Timing; + uint32_t iconOffset; + uint16_t secureAreaCrc16; + uint16_t secureAreaDelay; + // TODO: Fill in more + // And ROM data... +}; + +void DSCreate(struct DS* ds); +void DSDestroy(struct DS* ds); + +void DSAttachDebugger(struct DS* ds, struct mDebugger* debugger); +void DSDetachDebugger(struct DS* ds); + +bool DSLoadROM(struct DS* ds, struct VFile* vf); +void DSUnloadROM(struct DS* ds); +void DSApplyPatch(struct DS* ds, struct Patch* patch); + +bool DSIsROM(struct VFile* vf); +void DSGetGameCode(struct DS* ds, char* out); +void DSGetGameTitle(struct DS* ds, char* out); + +#endif
A src/ds/extra/cli.c

@@ -0,0 +1,62 @@

+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "cli.h" + +#include "arm/debugger/cli-debugger.h" + +#ifdef USE_CLI_DEBUGGER + +static void _DSCLIDebuggerInit(struct CLIDebuggerSystem*); +static bool _DSCLIDebuggerCustom(struct CLIDebuggerSystem*); +static uint32_t _DSCLIDebuggerLookupIdentifier(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv); + +static void _frame(struct CLIDebugger*, struct CLIDebugVector*); + +struct CLIDebuggerCommandSummary _DSCLIDebuggerCommands[] = { + { "frame", _frame, 0, "Frame advance" }, + { 0, 0, 0, 0 } +}; + +struct DSCLIDebugger* DSCLIDebuggerCreate(struct mCore* core) { + struct DSCLIDebugger* debugger = malloc(sizeof(struct DSCLIDebugger)); + ARMCLIDebuggerCreate(&debugger->d); + debugger->d.init = _DSCLIDebuggerInit; + debugger->d.deinit = NULL; + debugger->d.custom = _DSCLIDebuggerCustom; + debugger->d.lookupIdentifier = _DSCLIDebuggerLookupIdentifier; + + debugger->d.name = "DS"; + debugger->d.commands = _DSCLIDebuggerCommands; + + debugger->core = core; + + return debugger; +} + +static void _DSCLIDebuggerInit(struct CLIDebuggerSystem* debugger) { + struct DSCLIDebugger* dsDebugger = (struct DSCLIDebugger*) debugger; + + dsDebugger->frameAdvance = false; +} + +static bool _DSCLIDebuggerCustom(struct CLIDebuggerSystem* debugger) { + return false; +} + +static uint32_t _DSCLIDebuggerLookupIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) { + UNUSED(debugger); + dv->type = CLIDV_ERROR_TYPE; + return 0; +} + +static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + UNUSED(dv); + debugger->d.state = DEBUGGER_CUSTOM; + + struct DSCLIDebugger* dsDebugger = (struct DSCLIDebugger*) debugger->system; + dsDebugger->frameAdvance = true; +} +#endif
A src/ds/extra/cli.h

@@ -0,0 +1,26 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef DS_CLI_H +#define DS_CLI_H + +#ifdef USE_CLI_DEBUGGER +#include "debugger/cli-debugger.h" + +struct mCore; + +struct DSCLIDebugger { + struct CLIDebuggerSystem d; + + struct mCore* core; + + bool frameAdvance; + bool inVblank; +}; + +struct DSCLIDebugger* DSCLIDebuggerCreate(struct mCore*); +#endif + +#endif
A src/ds/video.h

@@ -0,0 +1,51 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef DS_VIDEO_H +#define DS_VIDEO_H + +#include "util/common.h" + +#include "core/log.h" + +mLOG_DECLARE_CATEGORY(DS_VIDEO); + +enum { + DS_VIDEO_HORIZONTAL_PIXELS = 256, + DS_VIDEO_HBLANK_PIXELS = 99, + DS_VIDEO_HORIZONTAL_LENGTH = (DS_VIDEO_HORIZONTAL_PIXELS + DS_VIDEO_HBLANK_PIXELS) * 6, + + DS_VIDEO_VERTICAL_PIXELS = 192, + DS_VIDEO_VBLANK_PIXELS = 71, + DS_VIDEO_VERTICAL_TOTAL_PIXELS = DS_VIDEO_VERTICAL_PIXELS + DS_VIDEO_VBLANK_PIXELS, + + DS_VIDEO_TOTAL_LENGTH = DS_VIDEO_HORIZONTAL_LENGTH * DS_VIDEO_VERTICAL_TOTAL_PIXELS, +}; + +struct DS; +struct DSVideo { + struct DS* p; + + // VCOUNT + int vcount; + + int32_t nextHblank; + int32_t nextEvent; + int32_t eventDiff; + + int32_t nextHblankIRQ; + int32_t nextVblankIRQ; + int32_t nextVcounterIRQ; + + int32_t frameCounter; + int frameskip; + int frameskipCounter; +}; + +void DSVideoInit(struct DSVideo* video); +void DSVideoReset(struct DSVideo* video); +void DSVideoDeinit(struct DSVideo* video); + +#endif