diff --git a/src/core/core.h b/src/core/core.h index 3682b35bf..d781f38cf 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -64,6 +64,7 @@ struct mCore { void (*setAudioBufferSize)(struct mCore*, size_t samples); size_t (*getAudioBufferSize)(struct mCore*); + void (*setCoreCallbacks)(struct mCore*, struct mCoreCallbacks*); void (*setAVStream)(struct mCore*, struct mAVStream*); bool (*isROM)(struct VFile* vf); diff --git a/src/core/interface.h b/src/core/interface.h index aae405834..8438dc543 100644 --- a/src/core/interface.h +++ b/src/core/interface.h @@ -20,6 +20,13 @@ typedef uint32_t color_t; struct blip_t; +struct mCoreCallbacks { + void* context; + void (*videoFrameStarted)(void* context); + void (*videoFrameEnded)(void* context); + void (*coreCrashed)(void* context); +}; + struct mAVStream { void (*videoDimensionsChanged)(struct mAVStream*, unsigned width, unsigned height); void (*postVideoFrame)(struct mAVStream*, const color_t* buffer, size_t stride); diff --git a/src/core/thread.c b/src/core/thread.c index 839928c7c..186d50323 100644 --- a/src/core/thread.c +++ b/src/core/thread.c @@ -85,6 +85,40 @@ static void _pauseThread(struct mCoreThread* threadContext) { _waitUntilNotState(threadContext, THREAD_PAUSING); } +void _frameStarted(void* context) { + struct mCoreThread* thread = context; + if (!thread) { + return; + } + if (thread->core->opts.rewindEnable && thread->core->opts.rewindBufferCapacity > 0) { + if (thread->state != THREAD_REWINDING) { + mCoreRewindAppend(&thread->rewind, thread->core); + } else if (thread->state == THREAD_REWINDING) { + if (!mCoreRewindRestore(&thread->rewind, thread->core)) { + mCoreRewindAppend(&thread->rewind, thread->core); + } + } + } +} + +void _frameEnded(void* context) { + struct mCoreThread* thread = context; + if (!thread) { + return; + } + if (thread->frameCallback) { + thread->frameCallback(thread); + } +} + +void _crashed(void* context) { + struct mCoreThread* thread = context; + if (!thread) { + return; + } + _changeState(thread, THREAD_CRASHED, true); +} + static THREAD_ENTRY _mCoreThreadRun(void* context) { struct mCoreThread* threadContext = context; #ifdef USE_PTHREADS @@ -104,6 +138,13 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { #endif struct mCore* core = threadContext->core; + struct mCoreCallbacks callbacks = { + .videoFrameStarted = _frameStarted, + .videoFrameEnded = _frameEnded, + .coreCrashed = _crashed, + .context = threadContext + }; + core->setCoreCallbacks(core, &callbacks); core->setSync(core, &threadContext->sync); core->reset(core); @@ -179,6 +220,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { if (threadContext->cleanCallback) { threadContext->cleanCallback(threadContext); } + core->setCoreCallbacks(core, NULL); return 0; } @@ -483,43 +525,10 @@ struct mCoreThread* mCoreThreadGet(void) { } #endif -void mCoreThreadFrameStarted(struct mCoreThread* thread) { - if (!thread) { - return; - } - if (thread->core->opts.rewindEnable && thread->core->opts.rewindBufferCapacity > 0) { - if (thread->state != THREAD_REWINDING) { - mCoreRewindAppend(&thread->rewind, thread->core); - } else if (thread->state == THREAD_REWINDING) { - if (!mCoreRewindRestore(&thread->rewind, thread->core)) { - mCoreRewindAppend(&thread->rewind, thread->core); - } - } - } -} - -void mCoreThreadFrameEnded(struct mCoreThread* thread) { - if (!thread) { - return; - } - if (thread->frameCallback) { - thread->frameCallback(thread); - } -} - #else struct mCoreThread* mCoreThreadGet(void) { return NULL; } - -void mCoreThreadFrameStarted(struct mCoreThread* thread) { - UNUSED(thread); -} - -void mCoreThreadFrameEnded(struct mCoreThread* thread) { - UNUSED(thread); -} - #endif static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) { diff --git a/src/core/thread.h b/src/core/thread.h index 5ef252799..b28569212 100644 --- a/src/core/thread.h +++ b/src/core/thread.h @@ -95,10 +95,6 @@ void mCoreThreadStopWaiting(struct mCoreThread* threadContext); void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool); struct mCoreThread* mCoreThreadGet(void); - -void mCoreThreadFrameStarted(struct mCoreThread*); -void mCoreThreadFrameEnded(struct mCoreThread*); - struct mLogger* mCoreThreadLogger(void); #endif diff --git a/src/gb/core.c b/src/gb/core.c index 59aed3c42..fd5aa989c 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -153,6 +153,11 @@ static size_t _GBCoreGetAudioBufferSize(struct mCore* core) { return gb->audio.samples; } +static void _GBCoreSetCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) { + struct GB* gb = core->board; + gb->coreCallbacks = coreCallbacks; +} + static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) { struct GB* gb = core->board; gb->stream = stream; @@ -534,6 +539,7 @@ struct mCore* GBCoreCreate(void) { core->setAudioBufferSize = _GBCoreSetAudioBufferSize; core->getAudioBufferSize = _GBCoreGetAudioBufferSize; core->setAVStream = _GBCoreSetAVStream; + core->setCoreCallbacks = _GBCoreSetCoreCallbacks; core->isROM = GBIsROM; core->loadROM = _GBCoreLoadROM; core->loadBIOS = _GBCoreLoadBIOS; diff --git a/src/gb/gb.c b/src/gb/gb.c index 604bc24be..a4fab4ca9 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -76,6 +76,7 @@ static void GBInit(void* cpu, struct mCPUComponent* component) { gb->pristineRomSize = 0; gb->yankedRomSize = 0; + gb->coreCallbacks = NULL; gb->stream = NULL; } diff --git a/src/gb/gb.h b/src/gb/gb.h index 5b8be0735..87a6223e6 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -44,6 +44,7 @@ enum GBIRQVector { struct mCoreSync; struct mAVStream; +struct mCoreCallbacks; struct GB { struct mCPUComponent d; @@ -72,6 +73,7 @@ struct GB { int32_t sramDirtAge; bool sramMaskWriteback; + struct mCoreCallbacks* coreCallbacks; struct mAVStream* stream; int32_t eiPending; diff --git a/src/gb/video.c b/src/gb/video.c index cc1f70aea..3a638baa6 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -133,8 +133,10 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) { } video->p->memory.io[REG_IF] |= (1 << GB_IRQ_VBLANK); - struct mCoreThread* thread = mCoreThreadGet(); - mCoreThreadFrameEnded(thread); + struct mCoreCallbacks* callbacks = video->p->coreCallbacks; + if (callbacks && callbacks->videoFrameEnded) { + callbacks->videoFrameEnded(callbacks->context); + } } if (GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->ly) { video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); @@ -220,8 +222,10 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) { video->renderer->getPixels(video->renderer, &stride, (const void**) &pixels); video->p->stream->postVideoFrame(video->p->stream, pixels, stride); } - struct mCoreThread* thread = mCoreThreadGet(); - mCoreThreadFrameStarted(thread); + struct mCoreCallbacks* callbacks = video->p->coreCallbacks; + if (callbacks && callbacks->videoFrameStarted) { + callbacks->videoFrameStarted(callbacks->context); + } } else { video->nextFrame = 4 - ((video->p->cpu->executionState + 1) & 3); if (video->nextFrame < video->nextEvent) { diff --git a/src/gba/core.c b/src/gba/core.c index 3ee2df585..1a37df6d8 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -184,6 +184,11 @@ static size_t _GBACoreGetAudioBufferSize(struct mCore* core) { return gba->audio.samples; } +static void _GBACoreSetCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) { + struct GBA* gba = core->board; + gba->coreCallbacks = coreCallbacks; +} + static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) { struct GBA* gba = core->board; gba->stream = stream; @@ -550,6 +555,7 @@ struct mCore* GBACoreCreate(void) { core->getAudioChannel = _GBACoreGetAudioChannel; core->setAudioBufferSize = _GBACoreSetAudioBufferSize; core->getAudioBufferSize = _GBACoreGetAudioBufferSize; + core->setCoreCallbacks = _GBACoreSetCoreCallbacks; core->setAVStream = _GBACoreSetAVStream; core->isROM = GBAIsROM; core->loadROM = _GBACoreLoadROM; diff --git a/src/gba/gba.c b/src/gba/gba.c index bcbd732fb..93ebc712b 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -94,9 +94,11 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) { gba->romVf = 0; gba->biosVf = 0; - gba->stream = 0; - gba->keyCallback = 0; - gba->stopCallback = 0; + gba->stream = NULL; + gba->keyCallback = NULL; + gba->stopCallback = NULL; + gba->stopCallback = NULL; + gba->coreCallbacks = NULL; gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS); @@ -854,8 +856,10 @@ void GBABreakpoint(struct ARMCore* cpu, int immediate) { void GBAFrameStarted(struct GBA* gba) { UNUSED(gba); - struct mCoreThread* thread = mCoreThreadGet(); - mCoreThreadFrameStarted(thread); + struct mCoreCallbacks* callbacks = gba->coreCallbacks; + if (callbacks && callbacks->videoFrameStarted) { + callbacks->videoFrameStarted(callbacks->context); + } } void GBAFrameEnded(struct GBA* gba) { @@ -885,10 +889,10 @@ void GBAFrameEnded(struct GBA* gba) { GBAHardwarePlayerUpdate(gba); } - struct mCoreThread* thread = mCoreThreadGet(); - mCoreThreadFrameEnded(thread); - - // TODO: Put back RR + struct mCoreCallbacks* callbacks = gba->coreCallbacks; + if (callbacks && callbacks->videoFrameEnded) { + callbacks->videoFrameEnded(callbacks->context); + } } void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) { diff --git a/src/gba/gba.h b/src/gba/gba.h index ce50234b2..feb01d0ed 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -112,6 +112,7 @@ struct GBA { struct mAVStream* stream; struct mKeyCallback* keyCallback; struct mStopCallback* stopCallback; + struct mCoreCallbacks* coreCallbacks; enum GBAIdleLoopOptimization idleOptimization; uint32_t idleLoop; diff --git a/src/gba/memory.c b/src/gba/memory.c index 1f329f7eb..2bf4a4cba 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -310,6 +310,9 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { cpu->memory.activeMask = 0; if (gba->yankedRomSize || !gba->hardCrash) { mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address); + } else if (gba->coreCallbacks && gba->coreCallbacks->coreCrashed) { + mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address); + gba->coreCallbacks->coreCrashed(gba->coreCallbacks->context); } else { mLOG(GBA_MEM, FATAL, "Jumped to invalid address: %08X", address); }