mirror of https://github.com/mgba-emu/mgba.git
DS: Start DS core
This commit is contained in:
parent
4ac4733cfd
commit
e75cb6f7b4
|
@ -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})
|
||||
|
@ -585,6 +601,15 @@ 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})
|
||||
source_group("Third-party code" FILES ${THIRD_PARTY_SRC})
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
#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 @@ static struct mCoreFilter {
|
|||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
{ GBIsROM, GBCoreCreate, PLATFORM_GB },
|
||||
#endif
|
||||
#ifdef M_CORE_DS
|
||||
{ DSIsROM, DSCoreCreate, PLATFORM_DS },
|
||||
#endif
|
||||
{ 0, 0, PLATFORM_NONE }
|
||||
};
|
||||
|
|
|
@ -28,6 +28,9 @@ enum mPlatform {
|
|||
#ifdef M_CORE_GB
|
||||
PLATFORM_GB,
|
||||
#endif
|
||||
#ifdef M_CORE_DS
|
||||
PLATFORM_DS,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct mRTCSource;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue