GBA: Add GBACore

This commit is contained in:
Jeffrey Pfau 2016-02-04 00:49:45 -08:00
parent 28268a601b
commit 33a4c45f3f
14 changed files with 324 additions and 138 deletions

View File

@ -23,6 +23,7 @@ typedef uint32_t color_t;
#define BYTES_PER_PIXEL 4 #define BYTES_PER_PIXEL 4
#endif #endif
struct blip_t;
struct mCoreSync; struct mCoreSync;
struct mCore { struct mCore {
void* cpu; void* cpu;
@ -40,6 +41,8 @@ struct mCore {
void (*desiredVideoDimensions)(struct mCore*, unsigned* width, unsigned* height); void (*desiredVideoDimensions)(struct mCore*, unsigned* width, unsigned* height);
void (*setVideoBuffer)(struct mCore*, color_t* buffer, size_t stride); void (*setVideoBuffer)(struct mCore*, color_t* buffer, size_t stride);
struct blip_t* (*getAudioChannel)(struct mCore*, int ch);
bool (*isROM)(struct VFile* vf); bool (*isROM)(struct VFile* vf);
bool (*loadROM)(struct mCore*, struct VFile* vf); bool (*loadROM)(struct mCore*, struct VFile* vf);
bool (*loadSave)(struct mCore*, struct VFile* vf); bool (*loadSave)(struct mCore*, struct VFile* vf);

View File

@ -72,6 +72,18 @@ static void _GBCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t st
gbcore->renderer.outputBufferStride = stride; gbcore->renderer.outputBufferStride = stride;
} }
static struct blip_t* _GBCoreGetAudioChannel(struct mCore* core, int ch) {
struct GB* gb = core->board;
switch (ch) {
case 0:
return gb->audio.left;
case 1:
return gb->audio.right;
default:
return NULL;
}
}
static bool _GBCoreLoadROM(struct mCore* core, struct VFile* vf) { static bool _GBCoreLoadROM(struct mCore* core, struct VFile* vf) {
return GBLoadROM(core->board, vf); return GBLoadROM(core->board, vf);
} }
@ -158,6 +170,7 @@ struct mCore* GBCoreCreate(void) {
core->setSync = _GBCoreSetSync; core->setSync = _GBCoreSetSync;
core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions; core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions;
core->setVideoBuffer = _GBCoreSetVideoBuffer; core->setVideoBuffer = _GBCoreSetVideoBuffer;
core->getAudioChannel = _GBCoreGetAudioChannel;
core->isROM = GBIsROM; core->isROM = GBIsROM;
core->loadROM = _GBCoreLoadROM; core->loadROM = _GBCoreLoadROM;
core->loadSave = _GBCoreLoadSave; core->loadSave = _GBCoreLoadSave;

192
src/gba/core.c Normal file
View File

@ -0,0 +1,192 @@
/* 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/core.h"
#include "core/log.h"
#include "gba/gba.h"
#include "gba/renderers/video-software.h"
#include "util/memory.h"
struct GBACore {
struct mCore d;
struct GBAVideoSoftwareRenderer renderer;
int keys;
};
static bool _GBACoreInit(struct mCore* core) {
struct GBACore* gbacore = (struct GBACore*) core;
struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore));
struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA));
if (!cpu || !gba) {
free(cpu);
free(gba);
return false;
}
core->cpu = cpu;
core->board = gba;
GBACreate(gba);
// TODO: Restore debugger and cheats
ARMSetComponents(cpu, &gba->d, 0, 0);
ARMInit(cpu);
GBAVideoSoftwareRendererCreate(&gbacore->renderer);
GBAVideoAssociateRenderer(&gba->video, &gbacore->renderer.d);
gba->keySource = &gbacore->keys;
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
mDirectorySetInit(&core->dirs);
#endif
return true;
}
static void _GBACoreDeinit(struct mCore* core) {
ARMDeinit(core->cpu);
GBADestroy(core->board);
mappedMemoryFree(core->cpu, sizeof(struct ARMCore));
mappedMemoryFree(core->board, sizeof(struct GBA));
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
mDirectorySetDeinit(&core->dirs);
#endif
}
static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) {
struct GBA* gba = core->board;
gba->sync = sync;
}
static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
UNUSED(core);
*width = VIDEO_HORIZONTAL_PIXELS;
*height = VIDEO_VERTICAL_PIXELS;
}
static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->renderer.outputBuffer = buffer;
gbacore->renderer.outputBufferStride = stride;
}
static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) {
struct GBA* gba = core->board;
switch (ch) {
case 0:
return gba->audio.psg.left;
case 1:
return gba->audio.psg.right;
default:
return NULL;
}
}
static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
return GBALoadROM2(core->board, vf);
}
static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) {
return GBALoadSave(core->board, vf);
}
static bool _GBACoreLoadPatch(struct mCore* core, struct VFile* vf) {
// TODO
UNUSED(core);
UNUSED(vf);
mLOG(GBA, STUB, "Patches are not yet supported");
return false;
}
static void _GBACoreUnloadROM(struct mCore* core) {
return GBAUnloadROM(core->board);
}
static void _GBACoreReset(struct mCore* core) {
ARMReset(core->cpu);
}
static void _GBACoreRunFrame(struct mCore* core) {
struct GBA* gba = core->board;
int32_t frameCounter = gba->video.frameCounter;
while (gba->video.frameCounter == frameCounter) {
ARMRunLoop(core->cpu);
}
}
static void _GBACoreRunLoop(struct mCore* core) {
ARMRunLoop(core->cpu);
}
static void _GBACoreStep(struct mCore* core) {
ARMRun(core->cpu);
}
static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->keys = keys;
}
static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->keys |= keys;
}
static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->keys &= ~keys;
}
static int32_t _GBACoreFrameCounter(struct mCore* core) {
struct GBA* gba = core->board;
return gba->video.frameCounter;
}
static int32_t _GBACoreFrameCycles(struct mCore* core) {
UNUSED(core);
return VIDEO_TOTAL_LENGTH;
}
static int32_t _GBACoreFrequency(struct mCore* core) {
UNUSED(core);
return GBA_ARM7TDMI_FREQUENCY;
}
static void _GBACoreSetRTC(struct mCore* core, struct mRTCSource* rtc) {
struct GBA* gba = core->board;
gba->rtcSource = rtc;
}
struct mCore* GBACoreCreate(void) {
struct GBACore* gbacore = malloc(sizeof(*gbacore));
struct mCore* core = &gbacore->d;
core->cpu = 0;
core->board = 0;
core->init = _GBACoreInit;
core->deinit = _GBACoreDeinit;
core->setSync = _GBACoreSetSync;
core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
core->setVideoBuffer = _GBACoreSetVideoBuffer;
core->getAudioChannel = _GBACoreGetAudioChannel;
core->isROM = GBAIsROM;
core->loadROM = _GBACoreLoadROM;
core->loadSave = _GBACoreLoadSave;
core->loadPatch = _GBACoreLoadPatch;
core->unloadROM = _GBACoreUnloadROM;
core->reset = _GBACoreReset;
core->runFrame = _GBACoreRunFrame;
core->runLoop = _GBACoreRunLoop;
core->step = _GBACoreStep;
core->setKeys = _GBACoreSetKeys;
core->addKeys = _GBACoreAddKeys;
core->clearKeys = _GBACoreClearKeys;
core->frameCounter = _GBACoreFrameCounter;
core->frameCycles = _GBACoreFrameCycles;
core->frequency = _GBACoreFrequency;
core->setRTC = _GBACoreSetRTC;
return core;
}

12
src/gba/core.h Normal file
View File

@ -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 GBA_CORE_H
#define GBA_CORE_H
struct mCore;
struct mCore* GBACoreCreate(void);
#endif

View File

@ -22,6 +22,8 @@
#include "util/patch.h" #include "util/patch.h"
#include "util/vfs.h" #include "util/vfs.h"
mLOG_DEFINE_CATEGORY(GBA, "GBA");
const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000; const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000;
const uint32_t GBA_COMPONENT_MAGIC = 0x1000000; const uint32_t GBA_COMPONENT_MAGIC = 0x1000000;
@ -443,7 +445,7 @@ bool GBALoadMB(struct GBA* gba, struct VFile* vf, const char* fname) {
return true; return true;
} }
bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname) { bool GBALoadROM2(struct GBA* gba, struct VFile* vf) {
GBAUnloadROM(gba); GBAUnloadROM(gba);
gba->romVf = vf; gba->romVf = vf;
gba->pristineRomSize = vf->size(vf); gba->pristineRomSize = vf->size(vf);
@ -466,14 +468,26 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char
} }
gba->yankedRomSize = 0; gba->yankedRomSize = 0;
gba->memory.rom = gba->pristineRom; gba->memory.rom = gba->pristineRom;
gba->activeFile = fname;
gba->memory.romSize = gba->pristineRomSize; gba->memory.romSize = gba->pristineRomSize;
gba->memory.romMask = toPow2(gba->memory.romSize) - 1; gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
GBASavedataInit(&gba->memory.savedata, sav);
GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]); GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]);
return true;
// TODO: error check // TODO: error check
return true;
}
bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname) {
if (!GBALoadROM2(gba, vf)) {
return false;
}
gba->activeFile = fname;
GBALoadSave(gba, sav);
return true;
}
bool GBALoadSave(struct GBA* gba, struct VFile* sav) {
GBASavedataInit(&gba->memory.savedata, sav);
return true;
} }
void GBAYankROM(struct GBA* gba) { void GBAYankROM(struct GBA* gba) {

View File

@ -8,7 +8,8 @@
#include "util/common.h" #include "util/common.h"
#include "arm.h" #include "arm/arm.h"
#include "core/log.h"
#include "debugger/debugger.h" #include "debugger/debugger.h"
#include "gba/interface.h" #include "gba/interface.h"
@ -59,6 +60,8 @@ struct GBAThread;
struct Patch; struct Patch;
struct VFile; struct VFile;
mLOG_DECLARE_CATEGORY(GBA);
DECL_BITFIELD(GBATimerFlags, uint32_t); DECL_BITFIELD(GBATimerFlags, uint32_t);
DECL_BITS(GBATimerFlags, PrescaleBits, 0, 4); DECL_BITS(GBATimerFlags, PrescaleBits, 0, 4);
DECL_BIT(GBATimerFlags, CountUp, 4); DECL_BIT(GBATimerFlags, CountUp, 4);
@ -171,6 +174,8 @@ void GBASetBreakpoint(struct GBA* gba, struct ARMComponent* component, uint32_t
void GBAClearBreakpoint(struct GBA* gba, uint32_t address, enum ExecutionMode mode, uint32_t opcode); void GBAClearBreakpoint(struct GBA* gba, uint32_t address, enum ExecutionMode mode, uint32_t opcode);
bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname); bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname);
bool GBALoadROM2(struct GBA* gba, struct VFile* vf);
bool GBALoadSave(struct GBA* gba, struct VFile* sav);
void GBAYankROM(struct GBA* gba); void GBAYankROM(struct GBA* gba);
void GBAUnloadROM(struct GBA* gba); void GBAUnloadROM(struct GBA* gba);
void GBALoadBIOS(struct GBA* gba, struct VFile* vf); void GBALoadBIOS(struct GBA* gba, struct VFile* vf);

View File

@ -20,7 +20,7 @@ AudioProcessorSDL::AudioProcessorSDL(QObject* parent)
} }
AudioProcessorSDL::~AudioProcessorSDL() { AudioProcessorSDL::~AudioProcessorSDL() {
GBSDLDeinitAudio(&m_audio); mSDLDeinitAudio(&m_audio);
} }
bool AudioProcessorSDL::start() { bool AudioProcessorSDL::start() {
@ -30,26 +30,26 @@ bool AudioProcessorSDL::start() {
} }
if (m_audio.thread) { if (m_audio.thread) {
GBSDLResumeAudio(&m_audio); mSDLResumeAudio(&m_audio);
return true; return true;
} else { } else {
if (!m_audio.samples) { if (!m_audio.samples) {
m_audio.samples = input()->audioBuffers; m_audio.samples = input()->audioBuffers;
} }
return GBSDLInitAudio(&m_audio, input()); return mSDLInitAudio(&m_audio, input());
} }
} }
void AudioProcessorSDL::pause() { void AudioProcessorSDL::pause() {
GBSDLPauseAudio(&m_audio); mSDLPauseAudio(&m_audio);
} }
void AudioProcessorSDL::setBufferSamples(int samples) { void AudioProcessorSDL::setBufferSamples(int samples) {
AudioProcessor::setBufferSamples(samples); AudioProcessor::setBufferSamples(samples);
m_audio.samples = samples; m_audio.samples = samples;
if (m_audio.thread) { if (m_audio.thread) {
GBSDLDeinitAudio(&m_audio); mSDLDeinitAudio(&m_audio);
GBSDLInitAudio(&m_audio, input()); mSDLInitAudio(&m_audio, input());
} }
} }
@ -59,8 +59,8 @@ void AudioProcessorSDL::inputParametersChanged() {
void AudioProcessorSDL::requestSampleRate(unsigned rate) { void AudioProcessorSDL::requestSampleRate(unsigned rate) {
m_audio.sampleRate = rate; m_audio.sampleRate = rate;
if (m_audio.thread) { if (m_audio.thread) {
GBSDLDeinitAudio(&m_audio); mSDLDeinitAudio(&m_audio);
GBSDLInitAudio(&m_audio, input()); mSDLInitAudio(&m_audio, input());
} }
} }

View File

@ -34,7 +34,7 @@ public slots:
virtual void requestSampleRate(unsigned) override; virtual void requestSampleRate(unsigned) override;
private: private:
GBSDLAudio m_audio; mSDLAudio m_audio;
}; };
} }

View File

@ -70,7 +70,7 @@ endif()
if(BUILD_PANDORA) if(BUILD_PANDORA)
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/pandora-sdl.c) list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/pandora-sdl.c)
else() else()
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c) #list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c)
if(BUILD_GL) if(BUILD_GL)
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c) list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c)
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c) list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c)

View File

@ -8,13 +8,7 @@
#include "gl-common.h" #include "gl-common.h"
#include "core/core.h" #include "core/core.h"
#ifdef M_CORE_GBA #include "core/thread.h"
#include "gba/supervisor/thread.h"
#endif
#ifdef M_CORE_GB
#include "gb/core.h"
#include "gb/gb.h"
#endif
#include "platform/opengl/gl.h" #include "platform/opengl/gl.h"
#define GB_GBA_CENTER ((VIDEO_HORIZONTAL_PIXELS - GB_VIDEO_HORIZONTAL_PIXELS + VIDEO_HORIZONTAL_PIXELS * (VIDEO_VERTICAL_PIXELS - GB_VIDEO_VERTICAL_PIXELS)) / 2) #define GB_GBA_CENTER ((VIDEO_HORIZONTAL_PIXELS - GB_VIDEO_HORIZONTAL_PIXELS + VIDEO_HORIZONTAL_PIXELS * (VIDEO_VERTICAL_PIXELS - GB_VIDEO_VERTICAL_PIXELS)) / 2)
@ -27,28 +21,32 @@ static void _doViewport(int w, int h, struct VideoBackend* v) {
} }
#ifdef M_CORE_GBA #ifdef M_CORE_GBA
#include "gba/gba.h"
static bool mSDLGLInitGBA(struct mSDLRenderer* renderer); static bool mSDLGLInitGBA(struct mSDLRenderer* renderer);
static void mSDLGLRunloopGBA(struct mSDLRenderer* renderer, void* user);
static void mSDLGLDeinitGBA(struct mSDLRenderer* renderer);
#endif #endif
#ifdef M_CORE_GB #ifdef M_CORE_GB
#include "gb/gb.h"
static bool mSDLGLInitGB(struct mSDLRenderer* renderer); static bool mSDLGLInitGB(struct mSDLRenderer* renderer);
static void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user);
static void mSDLGLDeinitGB(struct mSDLRenderer* renderer);
#endif #endif
static void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user);
static void mSDLGLDeinit(struct mSDLRenderer* renderer);
#ifdef M_CORE_GBA #ifdef M_CORE_GBA
void mSDLGLCreate(struct mSDLRenderer* renderer) { void mSDLGLCreateGBA(struct mSDLRenderer* renderer) {
renderer->init = mSDLGLInitGBA; renderer->init = mSDLGLInitGBA;
renderer->deinit = mSDLGLDeinitGBA; renderer->deinit = mSDLGLDeinit;
renderer->runloop = mSDLGLRunloopGBA; renderer->runloop = mSDLGLRunloop;
} }
bool mSDLGLInitGBA(struct mSDLRenderer* renderer) { bool mSDLGLInitGBA(struct mSDLRenderer* renderer) {
mSDLGLCommonInit(renderer); mSDLGLCommonInit(renderer);
renderer->d.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); renderer->outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS; memset(renderer->outputBuffer, 0, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, VIDEO_HORIZONTAL_PIXELS);
GBAGLContextCreate(&renderer->gl); GBAGLContextCreate(&renderer->gl);
renderer->gl.d.user = renderer; renderer->gl.d.user = renderer;
@ -60,53 +58,13 @@ bool mSDLGLInitGBA(struct mSDLRenderer* renderer) {
_doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d); _doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
return true; return true;
} }
void mSDLGLRunloopGBA(struct mSDLRenderer* renderer, void* user) {
struct GBAThread* context = user;
SDL_Event event;
struct VideoBackend* v = &renderer->gl.d;
renderer->audio.psg = &context->gba->audio.psg;
while (context->state < THREAD_EXITING) {
while (SDL_PollEvent(&event)) {
mSDLHandleEventGBA(context, &renderer->player, &event);
#if SDL_VERSION_ATLEAST(2, 0, 0)
// Event handling can change the size of the screen
if (renderer->player.windowUpdated) {
SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
_doViewport(renderer->viewportWidth, renderer->viewportHeight, v);
renderer->player.windowUpdated = 0;
}
#endif
}
if (mCoreSyncWaitFrameStart(&context->sync)) {
v->postFrame(v, renderer->d.outputBuffer);
}
mCoreSyncWaitFrameEnd(&context->sync);
v->drawFrame(v);
v->swap(v);
}
renderer->audio.psg = 0;
}
void mSDLGLDeinitGBA(struct mSDLRenderer* renderer) {
if (renderer->gl.d.deinit) {
renderer->gl.d.deinit(&renderer->gl.d);
}
free(renderer->d.outputBuffer);
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_GL_DeleteContext(renderer->glCtx);
#endif
}
#endif #endif
#ifdef M_CORE_GB #ifdef M_CORE_GB
void mSDLGLCreateGB(struct mSDLRenderer* renderer) { void mSDLGLCreateGB(struct mSDLRenderer* renderer) {
renderer->init = mSDLGLInitGB; renderer->init = mSDLGLInitGB;
renderer->deinit = mSDLGLDeinitGB; renderer->deinit = mSDLGLDeinit;
renderer->runloop = mSDLGLRunloopGB; renderer->runloop = mSDLGLRunloop;
} }
bool mSDLGLInitGB(struct mSDLRenderer* renderer) { bool mSDLGLInitGB(struct mSDLRenderer* renderer) {
@ -127,12 +85,12 @@ bool mSDLGLInitGB(struct mSDLRenderer* renderer) {
_doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d); _doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
return true; return true;
} }
#endif
void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user) { void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user) {
struct mCoreThread* context = user; struct mCoreThread* context = user;
SDL_Event event; SDL_Event event;
struct VideoBackend* v = &renderer->gl.d; struct VideoBackend* v = &renderer->gl.d;
renderer->audio.psg = &((struct GB*) renderer->core->board)->audio;
while (context->state < THREAD_EXITING) { while (context->state < THREAD_EXITING) {
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
@ -154,10 +112,9 @@ void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user) {
v->drawFrame(v); v->drawFrame(v);
v->swap(v); v->swap(v);
} }
renderer->audio.psg = 0;
} }
void mSDLGLDeinitGB(struct mSDLRenderer* renderer) { void mSDLGLDeinit(struct mSDLRenderer* renderer) {
if (renderer->gl.d.deinit) { if (renderer->gl.d.deinit) {
renderer->gl.d.deinit(&renderer->gl.d); renderer->gl.d.deinit(&renderer->gl.d);
} }
@ -166,4 +123,3 @@ void mSDLGLDeinitGB(struct mSDLRenderer* renderer) {
SDL_GL_DeleteContext(renderer->glCtx); SDL_GL_DeleteContext(renderer->glCtx);
#endif #endif
} }
#endif

View File

@ -15,8 +15,11 @@
#include "core/core.h" #include "core/core.h"
#include "core/config.h" #include "core/config.h"
#include "core/input.h"
#include "core/thread.h" #include "core/thread.h"
#include "gba/input.h"
#ifdef M_CORE_GBA #ifdef M_CORE_GBA
#include "gba/core.h"
#include "gba/gba.h" #include "gba/gba.h"
#include "gba/supervisor/thread.h" #include "gba/supervisor/thread.h"
#include "gba/video.h" #include "gba/video.h"
@ -52,9 +55,7 @@ static void mSDLDeinit(struct mSDLRenderer* renderer);
#ifdef M_CORE_GBA #ifdef M_CORE_GBA
static int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct mCoreConfig* config); static int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct mCoreConfig* config);
#endif #endif
#ifdef M_CORE_GB static int mSDLRun(struct mSDLRenderer* renderer, struct GBAArguments* args);
static int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args);
#endif
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -119,9 +120,9 @@ int main(int argc, char** argv) {
if (!opts.height) { if (!opts.height) {
opts.height = VIDEO_VERTICAL_PIXELS; opts.height = VIDEO_VERTICAL_PIXELS;
} }
GBAVideoSoftwareRendererCreate(&renderer.d); renderer.core = GBACoreCreate();
#ifdef BUILD_GL #ifdef BUILD_GL
mSDLGLCreate(&renderer); mSDLGLCreateGBA(&renderer);
#elif defined(BUILD_GLES2) || defined(USE_EPOXY) #elif defined(BUILD_GLES2) || defined(USE_EPOXY)
mSDLGLES2Create(&renderer); mSDLGLES2Create(&renderer);
#else #else
@ -149,7 +150,7 @@ int main(int argc, char** argv) {
} }
#endif #endif
else { else {
printf("Could not run game. Are you sure the file exists and is a Game Boy Advance game?\n"); printf("Could not run game. Are you sure the file exists and is a compatible game?\n");
freeArguments(&args); freeArguments(&args);
mCoreConfigFreeOpts(&opts); mCoreConfigFreeOpts(&opts);
mCoreConfigDeinit(&config); mCoreConfigDeinit(&config);
@ -197,17 +198,8 @@ int main(int argc, char** argv) {
int ret; int ret;
switch (platform) { // TODO: Use opts and config
case PLATFORM_GBA: ret = mSDLRun(&renderer, &args);
ret = mSDLRunGBA(&renderer, &args, &opts, &config);
break;
case PLATFORM_GB:
ret = mSDLRunGB(&renderer, &args);
break;
default:
ret = 1;
break;
}
mSDLDetachPlayer(&renderer.events, &renderer.player); mSDLDetachPlayer(&renderer.events, &renderer.player);
mInputMapDeinit(&inputMap); mInputMapDeinit(&inputMap);
@ -223,7 +215,6 @@ int main(int argc, char** argv) {
#ifdef M_CORE_GBA #ifdef M_CORE_GBA
int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct mCoreConfig* config) { int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct mCoreConfig* config) {
struct GBAThread context = { struct GBAThread context = {
.renderer = &renderer->d.d,
.userData = renderer .userData = renderer
}; };
@ -240,7 +231,7 @@ int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct
if (opts->sampleRate) { if (opts->sampleRate) {
renderer->audio.sampleRate = opts->sampleRate; renderer->audio.sampleRate = opts->sampleRate;
} }
if (!GBSDLInitAudio(&renderer->audio, &context)) { if (!mSDLInitAudio(&renderer->audio, &context)) {
didFail = true; didFail = true;
} }
@ -250,9 +241,7 @@ int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct
mSDLSuspendScreensaver(&renderer->events); mSDLSuspendScreensaver(&renderer->events);
#endif #endif
if (GBAThreadStart(&context)) { if (GBAThreadStart(&context)) {
renderer->audio.psg = &context.gba->audio.psg;
renderer->runloop(renderer, &context); renderer->runloop(renderer, &context);
renderer->audio.psg = 0;
GBAThreadJoin(&context); GBAThreadJoin(&context);
} else { } else {
didFail = true; didFail = true;
@ -276,8 +265,7 @@ int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct
} }
#endif #endif
#ifdef M_CORE_GB int mSDLRun(struct mSDLRenderer* renderer, struct GBAArguments* args) {
int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args) {
struct mCoreThread thread = { struct mCoreThread thread = {
.core = renderer->core, .core = renderer->core,
.sync = { .sync = {
@ -292,18 +280,18 @@ int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args) {
renderer->audio.samples = 1024; renderer->audio.samples = 1024;
renderer->audio.sampleRate = 44100; renderer->audio.sampleRate = 44100;
bool didFail = !GBSDLInitAudio(&renderer->audio, 0); bool didFail = !mSDLInitAudio(&renderer->audio, 0);
if (!didFail) { if (!didFail) {
renderer->audio.core = renderer->core;
renderer->audio.sync = &thread.sync; renderer->audio.sync = &thread.sync;
if (mCoreThreadStart(&thread)) { if (mCoreThreadStart(&thread)) {
renderer->audio.psg = 0; mSDLResumeAudio(&renderer->audio);
GBSDLResumeAudio(&renderer->audio);
renderer->runloop(renderer, &thread); renderer->runloop(renderer, &thread);
mCoreThreadJoin(&thread); mCoreThreadJoin(&thread);
} else { } else {
didFail = true; didFail = true;
printf("Could not run game. Are you sure the file exists and is a Game Boy game?\n"); printf("Could not run game. Are you sure the file exists and is a compatible game?\n");
} }
if (mCoreThreadHasCrashed(&thread)) { if (mCoreThreadHasCrashed(&thread)) {
@ -314,7 +302,6 @@ int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args) {
renderer->core->unloadROM(renderer->core); renderer->core->unloadROM(renderer->core);
return didFail; return didFail;
} }
#endif
static bool mSDLInit(struct mSDLRenderer* renderer) { static bool mSDLInit(struct mSDLRenderer* renderer) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) { if (SDL_Init(SDL_INIT_VIDEO) < 0) {
@ -327,7 +314,7 @@ static bool mSDLInit(struct mSDLRenderer* renderer) {
static void mSDLDeinit(struct mSDLRenderer* renderer) { static void mSDLDeinit(struct mSDLRenderer* renderer) {
mSDLDeinitEvents(&renderer->events); mSDLDeinitEvents(&renderer->events);
GBSDLDeinitAudio(&renderer->audio); mSDLDeinitAudio(&renderer->audio);
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_DestroyWindow(renderer->window); SDL_DestroyWindow(renderer->window);
#endif #endif

View File

@ -44,11 +44,8 @@ struct mCore;
struct mSDLRenderer { struct mSDLRenderer {
struct mCore* core; struct mCore* core;
color_t* outputBuffer; color_t* outputBuffer;
#ifdef M_CORE_GBA
// TODO: Remove struct mSDLAudio audio;
struct GBAVideoSoftwareRenderer d;
#endif
struct GBSDLAudio audio;
struct mSDLEvents events; struct mSDLEvents events;
struct mSDLPlayer player; struct mSDLPlayer player;
@ -101,7 +98,7 @@ struct mSDLRenderer {
void mSDLSWCreate(struct mSDLRenderer* renderer); void mSDLSWCreate(struct mSDLRenderer* renderer);
#ifdef BUILD_GL #ifdef BUILD_GL
void mSDLGLCreate(struct mSDLRenderer* renderer); void mSDLGLCreateGBA(struct mSDLRenderer* renderer);
void mSDLGLCreateGB(struct mSDLRenderer* renderer); void mSDLGLCreateGB(struct mSDLRenderer* renderer);
#endif #endif

View File

@ -12,9 +12,9 @@
#define BUFFER_SIZE (GBA_AUDIO_SAMPLES >> 2) #define BUFFER_SIZE (GBA_AUDIO_SAMPLES >> 2)
static void _GBSDLAudioCallback(void* context, Uint8* data, int len); static void _mSDLAudioCallback(void* context, Uint8* data, int len);
bool GBSDLInitAudio(struct GBSDLAudio* context, struct GBAThread* threadContext) { bool mSDLInitAudio(struct mSDLAudio* context, struct GBAThread* threadContext) {
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system: %s", SDL_GetError()); GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system: %s", SDL_GetError());
return false; return false;
@ -24,7 +24,7 @@ bool GBSDLInitAudio(struct GBSDLAudio* context, struct GBAThread* threadContext)
context->desiredSpec.format = AUDIO_S16SYS; context->desiredSpec.format = AUDIO_S16SYS;
context->desiredSpec.channels = 2; context->desiredSpec.channels = 2;
context->desiredSpec.samples = context->samples; context->desiredSpec.samples = context->samples;
context->desiredSpec.callback = _GBSDLAudioCallback; context->desiredSpec.callback = _mSDLAudioCallback;
context->desiredSpec.userdata = context; context->desiredSpec.userdata = context;
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
@ -37,7 +37,7 @@ bool GBSDLInitAudio(struct GBSDLAudio* context, struct GBAThread* threadContext)
return false; return false;
} }
context->samples = context->obtainedSpec.samples; context->samples = context->obtainedSpec.samples;
context->psg = 0; context->core = 0;
context->thread = 0; context->thread = 0;
if (threadContext) { if (threadContext) {
@ -59,9 +59,8 @@ bool GBSDLInitAudio(struct GBSDLAudio* context, struct GBAThread* threadContext)
return true; return true;
} }
void GBSDLDeinitAudio(struct GBSDLAudio* context) { void mSDLDeinitAudio(struct mSDLAudio* context) {
UNUSED(context); UNUSED(context);
context->psg = 0;
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_PauseAudioDevice(context->deviceId, 1); SDL_PauseAudioDevice(context->deviceId, 1);
SDL_CloseAudioDevice(context->deviceId); SDL_CloseAudioDevice(context->deviceId);
@ -72,7 +71,7 @@ void GBSDLDeinitAudio(struct GBSDLAudio* context) {
SDL_QuitSubSystem(SDL_INIT_AUDIO); SDL_QuitSubSystem(SDL_INIT_AUDIO);
} }
void GBSDLPauseAudio(struct GBSDLAudio* context) { void mSDLPauseAudio(struct mSDLAudio* context) {
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_PauseAudioDevice(context->deviceId, 1); SDL_PauseAudioDevice(context->deviceId, 1);
#else #else
@ -81,7 +80,7 @@ void GBSDLPauseAudio(struct GBSDLAudio* context) {
#endif #endif
} }
void GBSDLResumeAudio(struct GBSDLAudio* context) { void mSDLResumeAudio(struct mSDLAudio* context) {
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_PauseAudioDevice(context->deviceId, 0); SDL_PauseAudioDevice(context->deviceId, 0);
#else #else
@ -90,31 +89,39 @@ void GBSDLResumeAudio(struct GBSDLAudio* context) {
#endif #endif
} }
static void _GBSDLAudioCallback(void* context, Uint8* data, int len) { static void _mSDLAudioCallback(void* context, Uint8* data, int len) {
struct GBSDLAudio* audioContext = context; struct mSDLAudio* audioContext = context;
if (!context || (!audioContext->psg && !audioContext->thread)) { if (!context || (!audioContext->core && !audioContext->thread)) {
memset(data, 0, len); memset(data, 0, len);
return; return;
} }
struct GBAudio* psg = audioContext->psg; blip_t* left = NULL;
if (!psg) { blip_t* right = NULL;
psg = &audioContext->thread->gba->audio.psg; int32_t clockRate;
if (audioContext->core) {
left = audioContext->core->getAudioChannel(audioContext->core, 0);
right = audioContext->core->getAudioChannel(audioContext->core, 1);
clockRate = audioContext->core->frequency(audioContext->core);
} else if (audioContext->thread) {
left = audioContext->thread->gba->audio.psg.left;
right = audioContext->thread->gba->audio.psg.right;
clockRate = GBA_ARM7TDMI_FREQUENCY;
} }
double fauxClock = 1; double fauxClock = 1;
if (audioContext->thread) { if (audioContext->thread) {
fauxClock = GBAAudioCalculateRatio(1, audioContext->thread->fpsTarget, 1); fauxClock = GBAAudioCalculateRatio(1, audioContext->thread->fpsTarget, 1);
mCoreSyncLockAudio(&audioContext->thread->sync); mCoreSyncLockAudio(&audioContext->thread->sync);
} }
blip_set_rates(psg->left, psg->clockRate, audioContext->obtainedSpec.freq * fauxClock); blip_set_rates(left, clockRate, audioContext->obtainedSpec.freq * fauxClock);
blip_set_rates(psg->right, psg->clockRate, audioContext->obtainedSpec.freq * fauxClock); blip_set_rates(right, clockRate, audioContext->obtainedSpec.freq * fauxClock);
len /= 2 * audioContext->obtainedSpec.channels; len /= 2 * audioContext->obtainedSpec.channels;
int available = blip_samples_avail(psg->left); int available = blip_samples_avail(left);
if (available > len) { if (available > len) {
available = len; available = len;
} }
blip_read_samples(psg->left, (short*) data, available, audioContext->obtainedSpec.channels == 2); blip_read_samples(left, (short*) data, available, audioContext->obtainedSpec.channels == 2);
if (audioContext->obtainedSpec.channels == 2) { if (audioContext->obtainedSpec.channels == 2) {
blip_read_samples(psg->right, ((short*) data) + 1, available, 1); blip_read_samples(right, ((short*) data) + 1, available, 1);
} }
if (audioContext->sync) { if (audioContext->sync) {

View File

@ -10,7 +10,7 @@
#include <SDL.h> #include <SDL.h>
struct GBSDLAudio { struct mSDLAudio {
// Input // Input
size_t samples; size_t samples;
unsigned sampleRate; unsigned sampleRate;
@ -22,14 +22,14 @@ struct GBSDLAudio {
SDL_AudioDeviceID deviceId; SDL_AudioDeviceID deviceId;
#endif #endif
struct GBAudio* psg; struct mCore* core;
struct GBAThread* thread; struct GBAThread* thread;
struct mCoreSync* sync; struct mCoreSync* sync;
}; };
bool GBSDLInitAudio(struct GBSDLAudio* context, struct GBAThread*); bool mSDLInitAudio(struct mSDLAudio* context, struct GBAThread*);
void GBSDLDeinitAudio(struct GBSDLAudio* context); void mSDLDeinitAudio(struct mSDLAudio* context);
void GBSDLPauseAudio(struct GBSDLAudio* context); void mSDLPauseAudio(struct mSDLAudio* context);
void GBSDLResumeAudio(struct GBSDLAudio* context); void mSDLResumeAudio(struct mSDLAudio* context);
#endif #endif