From 0c332d972b6fb755a07d9292d9622f2e0b625a60 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 1 Feb 2014 20:24:38 -0800 Subject: [PATCH 01/26] Add ability to detach debugger --- src/gba/gba.c | 5 +++++ src/gba/gba.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/gba/gba.c b/src/gba/gba.c index a6b29c2e5..c0b8223ae 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -346,6 +346,11 @@ void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger) { gba->debugger = debugger; } +void GBADetachDebugger(struct GBA* gba) { + ARMDebuggerDeinit(gba->debugger); + gba->debugger = 0; +} + void GBALoadROM(struct GBA* gba, int fd, const char* fname) { struct stat info; gba->memory.rom = fileMemoryMap(fd, SIZE_CART0, MEMORY_READ); diff --git a/src/gba/gba.h b/src/gba/gba.h index 90ea5744d..1abb95ab6 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -140,6 +140,7 @@ int GBAWaitForIRQ(struct GBA* gba); int GBAHalt(struct GBA* gba); void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger); +void GBADetachDebugger(struct GBA* gba); void GBALoadROM(struct GBA* gba, int fd, const char* fname); void GBALoadBIOS(struct GBA* gba, int fd); From 97e4e7a28c3953916c2f02cb6b50bc72914961ca Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 1 Feb 2014 20:48:00 -0800 Subject: [PATCH 02/26] Add define for GDB stub --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ed7dfc465..19b24a760 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ else() endif() if(USE_GDB_STUB) + add_definitions(-DUSE_GDB_STUB) set(DEBUGGER_SRC "${DEBUGGER_SRC};${CMAKE_SOURCE_DIR}/src/debugger/gdb-stub.c") endif() source_group("ARM debugger" FILES ${DEBUGGER_SRC}) From 020aec4e7bfc88404fa653fe35196854c706714a Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 1 Feb 2014 20:48:25 -0800 Subject: [PATCH 03/26] The debugger should not stop by default --- src/debugger/debugger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debugger/debugger.c b/src/debugger/debugger.c index 7ce6a90c7..af88b485c 100644 --- a/src/debugger/debugger.c +++ b/src/debugger/debugger.c @@ -25,7 +25,7 @@ static void _checkBreakpoints(struct ARMDebugger* debugger) { void ARMDebuggerInit(struct ARMDebugger* debugger, struct ARMCore* cpu) { debugger->cpu = cpu; - debugger->state = DEBUGGER_PAUSED; + debugger->state = DEBUGGER_RUNNING; debugger->breakpoints = 0; debugger->memoryShim.original = cpu->memory; debugger->memoryShim.p = debugger; From 02aec4fc6573661573912c501717cfce03aed24f Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 2 Feb 2014 02:39:34 -0800 Subject: [PATCH 04/26] Add SDL2 support --- src/platform/sdl/CMakeLists.txt | 17 ++++++++++++++++- src/platform/sdl/gl-main.c | 20 ++++++++++++++++++++ src/platform/sdl/sdl-events.c | 2 ++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/platform/sdl/CMakeLists.txt b/src/platform/sdl/CMakeLists.txt index 7745464d6..2136addd2 100644 --- a/src/platform/sdl/CMakeLists.txt +++ b/src/platform/sdl/CMakeLists.txt @@ -1,4 +1,19 @@ -find_package(SDL 1.2 REQUIRED) +set(SDL_VERSION "2" CACHE STRING "Version of SDL to use (1.2 or 2)") + +if (SDL_VERSION EQUAL "2") + include(FindPkgConfig) + pkg_search_module(SDL2 sdl2) + if (SDL2_FOUND) + set(SDL_INCLUDE_DIR ${SDL2_INCLUDE_DIRS}) + set(SDL_LIBRARY ${SDL2_LIBRARIES}) + set(SDLMAIN_LIBRARY "") + endif() +endif() + +if(SDL_VERSION EQUAL "1.2" OR NOT SDL2_FOUND) + find_package(SDL 1.2 REQUIRED) +endif() + file(GLOB PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sdl-*.c) set(PLATFORM_LIBRARY "${SDL_LIBRARY};${SDLMAIN_LIBRARY}") include_directories(${CMAKE_SOURCE_DIR}/src/platform/sdl) diff --git a/src/platform/sdl/gl-main.c b/src/platform/sdl/gl-main.c index 56039614f..813486b5c 100644 --- a/src/platform/sdl/gl-main.c +++ b/src/platform/sdl/gl-main.c @@ -22,6 +22,9 @@ struct GLSoftwareRenderer { struct GBAVideoSoftwareRenderer d; struct GBASDLAudio audio; struct GBASDLEvents events; +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_Window* window; +#endif int viewportWidth; int viewportHeight; @@ -105,15 +108,25 @@ static int _GBASDLInit(struct GLSoftwareRenderer* renderer) { GBASDLInitEvents(&renderer->events); GBASDLInitAudio(&renderer->audio); +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); +#else SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); +#endif SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); +#if SDL_VERSION_ATLEAST(2, 0, 0) + renderer->window = SDL_CreateWindow("GBAc", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL); + SDL_GL_CreateContext(renderer->window); + SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight); +#else #ifdef COLOR_16_BIT SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 16, SDL_OPENGL); #else SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 32, SDL_OPENGL); +#endif #endif renderer->d.outputBuffer = malloc(256 * 256 * 4); @@ -158,7 +171,11 @@ static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer* } } GBASyncWaitFrameEnd(&context->sync); +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_GL_SwapWindow(renderer->window); +#else SDL_GL_SwapBuffers(); +#endif while (SDL_PollEvent(&event)) { GBASDLHandleEvent(context, &event); @@ -171,6 +188,9 @@ static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer) { GBASDLDeinitEvents(&renderer->events); GBASDLDeinitAudio(&renderer->audio); +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_DestroyWindow(renderer->window); +#endif SDL_Quit(); } diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 3161629d0..05ba606e1 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -11,7 +11,9 @@ int GBASDLInitEvents(struct GBASDLEvents* context) { } SDL_JoystickEventState(SDL_ENABLE); context->joystick = SDL_JoystickOpen(0); +#if !SDL_VERSION_ATLEAST(2, 0, 0) SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); +#endif return 1; } From ad38ae63ec3615da4a9e485affe38b7371bf47ea Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 2 Feb 2014 02:47:50 -0800 Subject: [PATCH 05/26] Properly support 16-bit color --- CMakeLists.txt | 7 +++++++ src/platform/sdl/CMakeLists.txt | 2 -- src/platform/sdl/gl-main.c | 13 ++++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 19b24a760..9f1635f18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,13 @@ else() source_group("POSIX-specific code" FILES ${OS_SRC}) endif() +if(BUILD_BBB OR BUILD_RASPI) + enable_language(ASM) + if(NOT BUILD_EGL) + add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5) + endif() +endif() + set(DEBUGGER_SRC "${CMAKE_SOURCE_DIR}/src/debugger/debugger.c;${CMAKE_SOURCE_DIR}/src/debugger/memory-debugger.c") if(USE_CLI_DEBUGGER) diff --git a/src/platform/sdl/CMakeLists.txt b/src/platform/sdl/CMakeLists.txt index 2136addd2..e95bef330 100644 --- a/src/platform/sdl/CMakeLists.txt +++ b/src/platform/sdl/CMakeLists.txt @@ -24,8 +24,6 @@ if(BUILD_RASPI AND BUILD_EGL) set(OPENGL_INCLUDE_DIR "") add_definitions(-DBUILD_RASPI) elseif(BUILD_BBB OR BUILD_RASPI) - enable_language(ASM) - add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5) set(MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-main.c) else() set(MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-main.c) diff --git a/src/platform/sdl/gl-main.c b/src/platform/sdl/gl-main.c index 813486b5c..9512059f3 100644 --- a/src/platform/sdl/gl-main.c +++ b/src/platform/sdl/gl-main.c @@ -113,10 +113,21 @@ static int _GBASDLInit(struct GLSoftwareRenderer* renderer) { #else SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); #endif + +#ifndef COLOR_16_BIT SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); +#else + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); +#ifdef COLOR_5_6_5 + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); +#else + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); +#endif + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); +#endif + #if SDL_VERSION_ATLEAST(2, 0, 0) renderer->window = SDL_CreateWindow("GBAc", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL); SDL_GL_CreateContext(renderer->window); From 19142a288101cfe8265b332e4a51db7b379102ce Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 2 Feb 2014 02:56:02 -0800 Subject: [PATCH 06/26] Use command key on OS X --- src/platform/sdl/sdl-events.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 05ba606e1..3dd80723a 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -5,6 +5,12 @@ #include "gba-serialize.h" #include "gba-video.h" +#if SDL_VERSION_ATLEAST(2, 0, 0) && defined(__APPLE__) +#define GUI_MOD KMOD_GUI +#else +#define GUI_MOD KMOD_CTRL +#endif + int GBASDLInitEvents(struct GBASDLEvents* context) { if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { return 0; @@ -79,7 +85,7 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_Ke } default: if (event->type == SDL_KEYDOWN) { - if (event->keysym.mod & KMOD_CTRL) { + if (event->keysym.mod & GUI_MOD) { switch (event->keysym.sym) { case SDLK_p: GBAThreadTogglePause(context); From 243cf2236b7e7f9c39585a65c6940c61935b9dfa Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 2 Feb 2014 03:05:30 -0800 Subject: [PATCH 07/26] Ability to fullscreen the window in SDL2 --- src/platform/sdl/gl-main.c | 10 +++++++++- src/platform/sdl/sdl-events.c | 12 +++++++++--- src/platform/sdl/sdl-events.h | 6 +++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/platform/sdl/gl-main.c b/src/platform/sdl/gl-main.c index 9512059f3..bce26894f 100644 --- a/src/platform/sdl/gl-main.c +++ b/src/platform/sdl/gl-main.c @@ -132,6 +132,8 @@ static int _GBASDLInit(struct GLSoftwareRenderer* renderer) { renderer->window = SDL_CreateWindow("GBAc", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL); SDL_GL_CreateContext(renderer->window); SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight); + renderer->events.window = renderer->window; + renderer->events.fullscreen = 0; #else #ifdef COLOR_16_BIT SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 16, SDL_OPENGL); @@ -189,7 +191,13 @@ static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer* #endif while (SDL_PollEvent(&event)) { - GBASDLHandleEvent(context, &event); + int fullscreen = renderer->events.fullscreen; + GBASDLHandleEvent(context, &renderer->events, &event); + // Event handling can change the size of the screen + if (renderer->events.fullscreen != fullscreen) { + SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight); + glViewport(0, 0, renderer->viewportWidth, renderer->viewportHeight); + } } } } diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 3dd80723a..2133d37bb 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -33,7 +33,7 @@ static void _pauseAfterFrame(struct GBAThread* context) { GBAThreadPause(context); } -static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_KeyboardEvent* event) { +static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) { enum GBAKey key = 0; int isPaused = GBAThreadIsPaused(context); switch (event->keysym.sym) { @@ -87,6 +87,12 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_Ke if (event->type == SDL_KEYDOWN) { if (event->keysym.mod & GUI_MOD) { switch (event->keysym.sym) { +#if SDL_VERSION_ATLEAST(2, 0, 0) + case SDLK_f: + SDL_SetWindowFullscreen(sdlContext->window, sdlContext->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP); + sdlContext->fullscreen = !sdlContext->fullscreen; + break; +#endif case SDLK_p: GBAThreadTogglePause(context); break; @@ -210,7 +216,7 @@ static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyH context->activeKeys |= key; } -void GBASDLHandleEvent(struct GBAThread* context, const union SDL_Event* event) { +void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) { switch (event->type) { case SDL_QUIT: // FIXME: this isn't thread-safe @@ -224,7 +230,7 @@ void GBASDLHandleEvent(struct GBAThread* context, const union SDL_Event* event) break; case SDL_KEYDOWN: case SDL_KEYUP: - _GBASDLHandleKeypress(context, &event->key); + _GBASDLHandleKeypress(context, sdlContext, &event->key); break; case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: diff --git a/src/platform/sdl/sdl-events.h b/src/platform/sdl/sdl-events.h index 6e5294532..bbf2c832a 100644 --- a/src/platform/sdl/sdl-events.h +++ b/src/platform/sdl/sdl-events.h @@ -7,11 +7,15 @@ struct GBASDLEvents { SDL_Joystick* joystick; +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_Window* window; + int fullscreen; +#endif }; int GBASDLInitEvents(struct GBASDLEvents*); void GBASDLDeinitEvents(struct GBASDLEvents*); -void GBASDLHandleEvent(struct GBAThread* context, const union SDL_Event* event); +void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event); #endif From 56c51181e1fa5b9c6a9cebc469771adee2f4cc21 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 2 Feb 2014 03:57:41 -0800 Subject: [PATCH 08/26] Debugger can get detached during a callback, clean up appropriately --- src/gba/gba-thread.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 894a5d612..dee501702 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -108,8 +108,9 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { while (threadContext->state < THREAD_EXITING) { if (threadContext->debugger) { - ARMDebuggerRun(threadContext->debugger); - if (threadContext->debugger->state == DEBUGGER_SHUTDOWN) { + struct ARMDebugger* debugger = threadContext->debugger; + ARMDebuggerRun(debugger); + if (debugger->state == DEBUGGER_SHUTDOWN) { _changeState(threadContext, THREAD_EXITING, 0); } } else { From 0f6523941c165a8f7981c8c4afe2d9573878479c Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 3 Feb 2014 00:42:20 -0800 Subject: [PATCH 09/26] Null out threadContext->gba when shutting down --- src/gba/gba-thread.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index dee501702..318415ec1 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -133,6 +133,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { threadContext->cleanCallback(threadContext); } + threadContext->gba = 0; GBADeinit(&gba); ConditionWake(&threadContext->sync.videoFrameAvailableCond); From 285b94b66a77c1cc439f9e2308a990ed37634c7e Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 3 Feb 2014 03:41:32 -0800 Subject: [PATCH 10/26] Add thread-safe function for telling if the GBA thread has started --- src/gba/gba-thread.c | 8 ++++++++ src/gba/gba-thread.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 318415ec1..22bb502cc 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -185,6 +185,14 @@ int GBAThreadStart(struct GBAThread* threadContext) { return 0; } +int GBAThreadHasStarted(struct GBAThread* threadContext) { + int hasStarted; + MutexLock(&threadContext->stateMutex); + hasStarted = threadContext->state > THREAD_INITIALIZED; + MutexUnlock(&threadContext->stateMutex); + return hasStarted; +} + void GBAThreadEnd(struct GBAThread* threadContext) { MutexLock(&threadContext->stateMutex); if (threadContext->debugger && threadContext->debugger->state == DEBUGGER_RUNNING) { diff --git a/src/gba/gba-thread.h b/src/gba/gba-thread.h index 33098b681..582d4990f 100644 --- a/src/gba/gba-thread.h +++ b/src/gba/gba-thread.h @@ -66,6 +66,7 @@ struct GBAThread { }; int GBAThreadStart(struct GBAThread* threadContext); +int GBAThreadHasStarted(struct GBAThread* threadContext); void GBAThreadEnd(struct GBAThread* threadContext); void GBAThreadJoin(struct GBAThread* threadContext); From 5a17030c65e663cd6d3f9be710c658333f207add Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 3 Feb 2014 03:42:02 -0800 Subject: [PATCH 11/26] Automatically break into the debugger if it was provided at launch time --- src/gba/gba-thread.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 22bb502cc..5b0f88af3 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -96,6 +96,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { if (threadContext->debugger) { GBAAttachDebugger(&gba, threadContext->debugger); + ARMDebuggerEnter(threadContext->debugger, DEBUGGER_ENTER_ATTACHED); } gba.keySource = &threadContext->activeKeys; From 90760a30a3681c99db8b5964e671e4d1ac6d581b Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 3 Feb 2014 22:27:58 -0800 Subject: [PATCH 12/26] Move key mapping into its own function --- src/platform/sdl/sdl-events.c | 43 ++++++++++++++++++----------------- src/platform/sdl/sdl-events.h | 2 ++ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 2133d37bb..1efea8360 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -28,6 +28,26 @@ void GBASDLDeinitEvents(struct GBASDLEvents* context) { SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } +enum GBAKey GBASDLMapButtonToKey(int button) { + // Sorry, hardcoded to my gamepad for now + switch (button) { + case 2: + return GBA_KEY_A; + case 1: + return GBA_KEY_B; + case 6: + return GBA_KEY_L; + case 7: + return GBA_KEY_R; + case 8: + return GBA_KEY_START; + case 9: + return GBA_KEY_SELECT; + default: + return GBA_KEY_NONE; + } +} + static void _pauseAfterFrame(struct GBAThread* context) { context->frameCallback = 0; GBAThreadPause(context); @@ -165,27 +185,8 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents static void _GBASDLHandleJoyButton(struct GBAThread* context, const struct SDL_JoyButtonEvent* event) { enum GBAKey key = 0; - // Sorry, hardcoded to my gamepad for now - switch (event->button) { - case 2: - key = GBA_KEY_A; - break; - case 1: - key = GBA_KEY_B; - break; - case 6: - key = GBA_KEY_L; - break; - case 7: - key = GBA_KEY_R; - break; - case 8: - key = GBA_KEY_START; - break; - case 9: - key = GBA_KEY_SELECT; - break; - default: + key = GBASDLMapButtonToKey(event->button); + if (key == GBA_KEY_NONE) { return; } diff --git a/src/platform/sdl/sdl-events.h b/src/platform/sdl/sdl-events.h index bbf2c832a..6d8b4a0ac 100644 --- a/src/platform/sdl/sdl-events.h +++ b/src/platform/sdl/sdl-events.h @@ -18,4 +18,6 @@ void GBASDLDeinitEvents(struct GBASDLEvents*); void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event); +enum GBAKey GBASDLMapButtonToKey(int button); + #endif From 23e0737649091d592a12040702ce961def8d29ea Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 3 Feb 2014 22:56:24 -0800 Subject: [PATCH 13/26] Add missing GBA_KEY_NONE --- src/gba/gba.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gba/gba.h b/src/gba/gba.h index 1abb95ab6..8b55ccd5d 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -55,7 +55,8 @@ enum GBAKey { GBA_KEY_UP = 6, GBA_KEY_DOWN = 7, GBA_KEY_R = 8, - GBA_KEY_L = 9 + GBA_KEY_L = 9, + GBA_KEY_NONE = -1 }; struct GBARotationSource; From 20a5fa8476993eb5ca89b3d974641f65489b8dfa Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 3 Feb 2014 23:01:26 -0800 Subject: [PATCH 14/26] Abstract out sockets --- src/debugger/gdb-stub.c | 54 +++++++------------------- src/debugger/gdb-stub.h | 5 ++- src/util/socket.h | 84 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 42 deletions(-) create mode 100644 src/util/socket.h diff --git a/src/debugger/gdb-stub.c b/src/debugger/gdb-stub.c index 7ad1fe27d..b8759a12d 100644 --- a/src/debugger/gdb-stub.c +++ b/src/debugger/gdb-stub.c @@ -1,13 +1,8 @@ #include "gdb-stub.h" #include -#include -#include #include -#include #include -#include -#include enum GDBError { GDB_NO_ERROR = 0x00, @@ -50,15 +45,12 @@ static void _gdbStubEntered(struct ARMDebugger* debugger, enum DebuggerEntryReas static void _gdbStubPoll(struct ARMDebugger* debugger) { struct GDBStub* stub = (struct GDBStub*) debugger; - int flags; while (stub->d.state == DEBUGGER_PAUSED) { if (stub->connection >= 0) { - flags = fcntl(stub->connection, F_GETFL); - if (flags == -1) { + if (!SocketSetBlocking(stub->connection, 1)) { GDBStubHangup(stub); return; } - fcntl(stub->connection, F_SETFL, flags & ~O_NONBLOCK); } GDBStubUpdate(stub); } @@ -66,7 +58,7 @@ static void _gdbStubPoll(struct ARMDebugger* debugger) { static void _ack(struct GDBStub* stub) { char ack = '+'; - send(stub->connection, &ack, 1, 0); + SocketSend(stub->connection, &ack, 1); } static void _nak(struct GDBStub* stub) { @@ -74,7 +66,7 @@ static void _nak(struct GDBStub* stub) { if (stub->d.log) { stub->d.log(&stub->d, DEBUGGER_LOG_WARN, "Packet error"); } - send(stub->connection, &nak, 1, 0); + SocketSend(stub->connection, &nak, 1); } static uint32_t _hex2int(const char* hex, int maxDigits) { @@ -155,7 +147,7 @@ static void _sendMessage(struct GDBStub* stub) { if (stub->d.log) { stub->d.log(&stub->d, DEBUGGER_LOG_DEBUG, "> %s", stub->outgoing); } - send(stub->connection, stub->outgoing, i + 3, 0); + SocketSend(stub->connection, stub->outgoing, i + 3); } static void _error(struct GDBStub* stub, enum GDBError error) { @@ -171,12 +163,10 @@ static void _writeHostInfo(struct GDBStub* stub) { static void _continue(struct GDBStub* stub, const char* message) { stub->d.state = DEBUGGER_RUNNING; if (stub->connection >= 0) { - int flags = fcntl(stub->connection, F_GETFL); - if (flags == -1) { + if (!SocketSetBlocking(stub->connection, 0)) { GDBStubHangup(stub); return; } - fcntl(stub->connection, F_SETFL, flags | O_NONBLOCK); } // TODO: parse message (void) (message); @@ -445,34 +435,20 @@ int GDBStubListen(struct GDBStub* stub, int port, uint32_t bindAddress) { GDBStubShutdown(stub); } // TODO: support IPv6 - stub->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + stub->socket = SocketOpenTCP(port, bindAddress); if (stub->socket < 0) { if (stub->d.log) { stub->d.log(&stub->d, DEBUGGER_LOG_ERROR, "Couldn't open socket"); } return 0; } - - struct sockaddr_in bindInfo = { - .sin_family = AF_INET, - .sin_port = htons(port), - .sin_addr = { - .s_addr = htonl(bindAddress) - } - }; - int err = bind(stub->socket, (const struct sockaddr*) &bindInfo, sizeof(struct sockaddr_in)); + int err = SocketListen(stub->socket, 1); if (err) { goto cleanup; } - err = listen(stub->socket, 1); - if (err) { + if (!SocketSetBlocking(stub->socket, 0)) { goto cleanup; } - int flags = fcntl(stub->socket, F_GETFL); - if (flags == -1) { - goto cleanup; - } - fcntl(stub->socket, F_SETFL, flags | O_NONBLOCK); return 1; @@ -480,14 +456,14 @@ cleanup: if (stub->d.log) { stub->d.log(&stub->d, DEBUGGER_LOG_ERROR, "Couldn't listen on port"); } - close(stub->socket); + SocketClose(stub->socket); stub->socket = -1; return 0; } void GDBStubHangup(struct GDBStub* stub) { if (stub->connection >= 0) { - close(stub->connection); + SocketClose(stub->connection); stub->connection = -1; } if (stub->d.state == DEBUGGER_PAUSED) { @@ -498,7 +474,7 @@ void GDBStubHangup(struct GDBStub* stub) { void GDBStubShutdown(struct GDBStub* stub) { GDBStubHangup(stub); if (stub->socket >= 0) { - close(stub->socket); + SocketClose(stub->socket); stub->socket = -1; } } @@ -508,13 +484,11 @@ void GDBStubUpdate(struct GDBStub* stub) { return; } if (stub->connection == -1) { - stub->connection = accept(stub->socket, 0, 0); + stub->connection = SocketAccept(stub->socket, 0, 0); if (stub->connection >= 0) { - int flags = fcntl(stub->connection, F_GETFL); - if (flags == -1) { + if (!SocketSetBlocking(stub->connection, 0)) { goto connectionLost; } - fcntl(stub->connection, F_SETFL, flags | O_NONBLOCK); ARMDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED); } else if (errno == EWOULDBLOCK || errno == EAGAIN) { return; @@ -523,7 +497,7 @@ void GDBStubUpdate(struct GDBStub* stub) { } } while (1) { - ssize_t messageLen = recv(stub->connection, stub->line, GDB_STUB_MAX_LINE - 1, 0); + ssize_t messageLen = SocketRecv(stub->connection, stub->line, GDB_STUB_MAX_LINE - 1); if (messageLen == 0) { goto connectionLost; } diff --git a/src/debugger/gdb-stub.h b/src/debugger/gdb-stub.h index 5be0fd0ad..b60540edf 100644 --- a/src/debugger/gdb-stub.h +++ b/src/debugger/gdb-stub.h @@ -2,6 +2,7 @@ #define GDB_STUB_H #include "debugger.h" +#include "socket.h" #define GDB_STUB_MAX_LINE 1200 @@ -19,8 +20,8 @@ struct GDBStub { char outgoing[GDB_STUB_MAX_LINE]; enum GDBStubAckState lineAck; - int socket; - int connection; + Socket socket; + Socket connection; }; void GDBStubCreate(struct GDBStub*); diff --git a/src/util/socket.h b/src/util/socket.h new file mode 100644 index 000000000..1f643346e --- /dev/null +++ b/src/util/socket.h @@ -0,0 +1,84 @@ +#ifndef SOCKET_H +#define SOCKET_H + +#ifdef _WIN32 +#include + +typedef SOCKET Socket; +#else +#include +#include +#include +#include +#include + +typedef int Socket; +#endif + + +void SocketSubsystemInitialize() { +#ifdef _WIN32 + WSAStartup(MAKEWORD(2, 2), 0); +#endif +} + +ssize_t SocketSend(Socket socket, const void* buffer, size_t size) { + return write(socket, buffer, size); +} + +ssize_t SocketRecv(Socket socket, void* buffer, size_t size) { + return read(socket, buffer, size); +} + +Socket SocketOpenTCP(int port, uint32_t bindAddress) { + Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + return sock; + } + + struct sockaddr_in bindInfo = { + .sin_family = AF_INET, + .sin_port = htons(port), + .sin_addr = { + .s_addr = htonl(bindAddress) + } + }; + int err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(struct sockaddr_in)); + if (err) { + close(sock); + return -1; + } + return sock; +} + +Socket SocketListen(Socket socket, int queueLength) { + return listen(socket, queueLength); +} + +Socket SocketAccept(Socket socket, struct sockaddr* restrict address, socklen_t* restrict addressLength) { + return accept(socket, address, addressLength); +} + +int SocketClose(Socket socket) { + return close(socket) >= 0; +} + +int SocketSetBlocking(Socket socket, int blocking) { +#ifdef _WIN32 + blocking = !blocking; + return ioctlsocket(socket, FIONBIO, &blocking) == NO_ERROR; +#else + int flags = fcntl(socket, F_GETFL); + if (flags == -1) { + return 0; + } + if (blocking) { + flags &= ~O_NONBLOCK; + } else { + flags |= O_NONBLOCK; + } + return fcntl(socket, F_SETFL, flags) >= 0; +#endif +} + +#endif From 70e16613420f3f84149810e9621c4cb65c52bd2c Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 4 Feb 2014 00:39:55 -0800 Subject: [PATCH 15/26] Begin SIO --- src/gba/gba-io.c | 12 +++++++- src/gba/gba-sio.c | 29 +++++++++++++++++++ src/gba/gba-sio.h | 72 +++++++++++++++++++++++++++++++++++++++++++++++ src/gba/gba.c | 3 ++ src/gba/gba.h | 2 ++ 5 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 src/gba/gba-sio.c create mode 100644 src/gba/gba-sio.h diff --git a/src/gba/gba-io.c b/src/gba/gba-io.c index eb80bb0b5..9c163cb31 100644 --- a/src/gba/gba-io.c +++ b/src/gba/gba-io.c @@ -1,6 +1,7 @@ #include "gba-io.h" #include "gba-serialize.h" +#include "gba-sio.h" #include "gba-video.h" static const int _isValidRegister[REG_MAX >> 1] = { @@ -89,7 +90,7 @@ static const int _isSpecialRegister[REG_MAX >> 1] = { void GBAIOInit(struct GBA* gba) { gba->memory.io[REG_DISPCNT >> 1] = 0x0080; - gba->memory.io[REG_RCNT >> 1] = 0x8000; + gba->memory.io[REG_RCNT >> 1] = RCNT_INITIAL; gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF; } @@ -250,6 +251,15 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { GBATimerWriteTMCNT_HI(gba, 3, value); break; + // SIO + case REG_SIOCNT: + GBASIOWriteSIOCNT(&gba->sio, value); + break; + case REG_RCNT: + value &= 0xC1FF; + GBASIOWriteRCNT(&gba->sio, value); + break; + // Interrupts and misc case REG_WAITCNT: GBAAdjustWaitstates(&gba->memory, value); diff --git a/src/gba/gba-sio.c b/src/gba/gba-sio.c new file mode 100644 index 000000000..31e84b97d --- /dev/null +++ b/src/gba/gba-sio.c @@ -0,0 +1,29 @@ +#include "gba-sio.h" + +#include "gba-io.h" + +static void _switchMode(struct GBASIO* sio) { + int mode = ((sio->rcnt >> 14) & 0xC) | ((sio->siocnt >> 12) & 0x3); + if (mode < 8) { + sio->mode = (enum GBASIOMode) (mode & 0x3); + } else { + sio->mode = (enum GBASIOMode) (mode & 0xC); + } + // TODO: hangup if we have an existing connection +} + +void GBASIOInit(struct GBASIO* sio) { + sio->rcnt = RCNT_INITIAL; + sio->siocnt = 0; + _switchMode(sio); +} + +void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value) { + sio->rcnt = value; + _switchMode(sio); +} + +void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) { + sio->siocnt = value; + _switchMode(sio); +} diff --git a/src/gba/gba-sio.h b/src/gba/gba-sio.h new file mode 100644 index 000000000..184b5067b --- /dev/null +++ b/src/gba/gba-sio.h @@ -0,0 +1,72 @@ +#ifndef GBA_SIO_H +#define GBA_SIO_H + +#include + +enum GBASIOMode { + SIO_NORMAL_8 = 0, + SIO_NORMAL_32 = 1, + SIO_MULTI = 2, + SIO_UART = 3, + SIO_GPIO = 8, + SIO_JOYBUS = 12 +}; + +enum GBASIOMultiMode { + VBA_LINK_COMPAT +}; + +enum { + RCNT_INITIAL = 0x8000 +}; + +struct GBASIODriver { + int (*attach)(struct GBASIODriver* driver); +}; + +struct GBASIO { + struct GBA* p; + + enum GBASIOMode mode; + enum GBASIOMultiMode multiMode; + struct GBASIODriver* driver; + + uint16_t rcnt; + union { + struct { + unsigned sc : 1; + unsigned internalSc : 1; + unsigned si : 1; + unsigned idleSo : 1; + unsigned : 4; + unsigned start : 1; + unsigned : 3; + unsigned length : 1; + unsigned : 1; + unsigned irq : 1; + unsigned : 1; + } normalControl; + + struct { + unsigned baud : 2; + unsigned slave : 1; + unsigned ready : 1; + unsigned id : 2; + unsigned error : 1; + unsigned busy : 1; + unsigned : 6; + unsigned irq : 1; + unsigned : 1; + } multiplayerControl; + + uint16_t siocnt; + }; +}; + +void GBASIOInit(struct GBASIO* sio); + +void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value); +void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value); +void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value); + +#endif diff --git a/src/gba/gba.c b/src/gba/gba.c index c0b8223ae..8adeeaa83 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -122,6 +122,9 @@ void GBAInit(struct GBA* gba) { GBAIOInit(gba); + gba->sio.p = gba; + GBASIOInit(&gba->sio); + gba->timersEnabled = 0; memset(gba->timers, 0, sizeof(gba->timers)); diff --git a/src/gba/gba.h b/src/gba/gba.h index 8b55ccd5d..0b33f5cae 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -7,6 +7,7 @@ #include "gba-memory.h" #include "gba-video.h" #include "gba-audio.h" +#include "gba-sio.h" #include @@ -74,6 +75,7 @@ struct GBA { struct GBAMemory memory; struct GBAVideo video; struct GBAAudio audio; + struct GBASIO sio; struct GBASync* sync; From e5ee1aa07f0f7bffe86ddda36747b5480964e9fe Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 4 Feb 2014 01:28:16 -0800 Subject: [PATCH 16/26] Fill out SIO driver infrastructure --- src/gba/gba-sio.c | 73 +++++++++++++++++++++++++++++++++++++++++++- src/gba/gba-sio.h | 22 +++++++++---- src/gba/gba-thread.c | 2 ++ src/gba/gba-thread.h | 1 + 4 files changed, 91 insertions(+), 7 deletions(-) diff --git a/src/gba/gba-sio.c b/src/gba/gba-sio.c index 31e84b97d..5766b52c2 100644 --- a/src/gba/gba-sio.c +++ b/src/gba/gba-sio.c @@ -2,14 +2,34 @@ #include "gba-io.h" +static struct GBASIODriver* _lookupDriver(struct GBASIO* sio, enum GBASIOMode mode) { + switch (mode) { + case SIO_MULTI: + return sio->drivers.multiplayer; + case SIO_JOYBUS: + return sio->drivers.joybus; + default: + return 0; + } +} + static void _switchMode(struct GBASIO* sio) { int mode = ((sio->rcnt >> 14) & 0xC) | ((sio->siocnt >> 12) & 0x3); + enum GBASIOMode oldMode = sio->mode; if (mode < 8) { sio->mode = (enum GBASIOMode) (mode & 0x3); } else { sio->mode = (enum GBASIOMode) (mode & 0xC); } - // TODO: hangup if we have an existing connection + if (oldMode != mode) { + if (sio->activeDriver && sio->activeDriver->detach) { + sio->activeDriver->detach(sio->activeDriver); + } + sio->activeDriver = _lookupDriver(sio, mode); + if (sio->activeDriver && sio->activeDriver->attach) { + sio->activeDriver->attach(sio->activeDriver); + } + } } void GBASIOInit(struct GBASIO* sio) { @@ -18,12 +38,63 @@ void GBASIOInit(struct GBASIO* sio) { _switchMode(sio); } +void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) { + if (drivers->multiplayer) { + GBASIOSetDriver(sio, drivers->multiplayer, SIO_MULTI); + } + if (drivers->joybus) { + GBASIOSetDriver(sio, drivers->multiplayer, SIO_JOYBUS); + } +} + +void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASIOMode mode) { + struct GBASIODriver** driverLoc; + switch (mode) { + case SIO_MULTI: + driverLoc = &sio->drivers.multiplayer; + break; + case SIO_JOYBUS: + driverLoc = &sio->drivers.joybus; + break; + default: + GBALog(sio->p, GBA_LOG_ERROR, "Setting an unsupported SIO driver: %x", mode); + return; + } + if (*driverLoc) { + if ((*driverLoc)->detach) { + (*driverLoc)->detach(*driverLoc); + } + if ((*driverLoc)->deinit) { + (*driverLoc)->deinit(*driverLoc); + } + } + if (*driverLoc == sio->activeDriver) { + sio->activeDriver = driver; + } + *driverLoc = driver; + if (driver && driver->init) { + driver->init(driver, sio); + } +} + void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value) { sio->rcnt = value; _switchMode(sio); + if (sio->activeDriver && sio->activeDriver->writeRegister) { + sio->activeDriver->writeRegister(sio->activeDriver, REG_RCNT, value); + } } void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) { sio->siocnt = value; _switchMode(sio); + if (sio->activeDriver && sio->activeDriver->writeRegister) { + sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOCNT, value); + } +} + +void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value) { + if (sio->activeDriver && sio->activeDriver->writeRegister) { + sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOMLT_SEND, value); + } } diff --git a/src/gba/gba-sio.h b/src/gba/gba-sio.h index 184b5067b..10c3e7cfc 100644 --- a/src/gba/gba-sio.h +++ b/src/gba/gba-sio.h @@ -12,24 +12,32 @@ enum GBASIOMode { SIO_JOYBUS = 12 }; -enum GBASIOMultiMode { - VBA_LINK_COMPAT -}; - enum { RCNT_INITIAL = 0x8000 }; +struct GBASIO; + struct GBASIODriver { + void (*init)(struct GBASIODriver* driver, struct GBASIO* sio); + void (*deinit)(struct GBASIODriver* driver); + int (*attach)(struct GBASIODriver* driver); + int (*detach)(struct GBASIODriver* driver); + void (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value); +}; + +struct GBASIODriverSet { + struct GBASIODriver* multiplayer; + struct GBASIODriver* joybus; }; struct GBASIO { struct GBA* p; enum GBASIOMode mode; - enum GBASIOMultiMode multiMode; - struct GBASIODriver* driver; + struct GBASIODriverSet drivers; + struct GBASIODriver* activeDriver; uint16_t rcnt; union { @@ -64,6 +72,8 @@ struct GBASIO { }; void GBASIOInit(struct GBASIO* sio); +void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers); +void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASIOMode mode); void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value); void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value); diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 5b0f88af3..00e189c38 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -99,6 +99,8 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { ARMDebuggerEnter(threadContext->debugger, DEBUGGER_ENTER_ATTACHED); } + GBASIOSetDriverSet(&gba.sio, &threadContext->sioDrivers); + gba.keySource = &threadContext->activeKeys; if (threadContext->startCallback) { diff --git a/src/gba/gba-thread.h b/src/gba/gba-thread.h index 582d4990f..99352ee59 100644 --- a/src/gba/gba-thread.h +++ b/src/gba/gba-thread.h @@ -36,6 +36,7 @@ struct GBAThread { // Input struct GBAVideoRenderer* renderer; + struct GBASIODriverSet sioDrivers; struct ARMDebugger* debugger; int fd; int biosFd; From 924c6cf5a63528484be1d03676e09456d5fb5bc5 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 5 Feb 2014 01:03:34 -0800 Subject: [PATCH 17/26] Clarify some function names and add more essenital SIO architecture --- src/gba/gba-sio.c | 47 ++++++++++++++++++++++++++++++++++++----------- src/gba/gba-sio.h | 14 ++++++++++---- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/gba/gba-sio.c b/src/gba/gba-sio.c index 5766b52c2..e320169ba 100644 --- a/src/gba/gba-sio.c +++ b/src/gba/gba-sio.c @@ -2,6 +2,8 @@ #include "gba-io.h" +#include + static struct GBASIODriver* _lookupDriver(struct GBASIO* sio, enum GBASIOMode mode) { switch (mode) { case SIO_MULTI: @@ -22,12 +24,12 @@ static void _switchMode(struct GBASIO* sio) { sio->mode = (enum GBASIOMode) (mode & 0xC); } if (oldMode != mode) { - if (sio->activeDriver && sio->activeDriver->detach) { - sio->activeDriver->detach(sio->activeDriver); + if (sio->activeDriver && sio->activeDriver->unload) { + sio->activeDriver->unload(sio->activeDriver); } sio->activeDriver = _lookupDriver(sio, mode); - if (sio->activeDriver && sio->activeDriver->attach) { - sio->activeDriver->attach(sio->activeDriver); + if (sio->activeDriver && sio->activeDriver->load) { + sio->activeDriver->load(sio->activeDriver); } } } @@ -38,6 +40,15 @@ void GBASIOInit(struct GBASIO* sio) { _switchMode(sio); } +void GBASIODeinit(struct GBASIO* sio) { + if (sio->drivers.multiplayer && sio->drivers.multiplayer->deinit) { + sio->drivers.multiplayer->deinit(sio->drivers.multiplayer); + } + if (sio->drivers.joybus && sio->drivers.joybus->deinit) { + sio->drivers.joybus->deinit(sio->drivers.joybus); + } +} + void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) { if (drivers->multiplayer) { GBASIOSetDriver(sio, drivers->multiplayer, SIO_MULTI); @@ -61,20 +72,27 @@ void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASI return; } if (*driverLoc) { - if ((*driverLoc)->detach) { - (*driverLoc)->detach(*driverLoc); + if ((*driverLoc)->unload) { + (*driverLoc)->unload(*driverLoc); } if ((*driverLoc)->deinit) { (*driverLoc)->deinit(*driverLoc); } } - if (*driverLoc == sio->activeDriver) { - sio->activeDriver = driver; + if (driver) { + driver->p = sio; + + if (driver->init) { + driver->init(driver); + } + if (*driverLoc == sio->activeDriver) { + sio->activeDriver = driver; + if ((*driverLoc)->load) { + (*driverLoc)->load(*driverLoc); + } + } } *driverLoc = driver; - if (driver && driver->init) { - driver->init(driver, sio); - } } void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value) { @@ -98,3 +116,10 @@ void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value) { sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOMLT_SEND, value); } } + +int32_t GBASIOProcessEvents(struct GBASIO* sio, int32_t cycles) { + if (sio->activeDriver && sio->activeDriver->processEvents) { + return sio->activeDriver->processEvents(sio->activeDriver, cycles); + } + return INT_MAX; +} diff --git a/src/gba/gba-sio.h b/src/gba/gba-sio.h index 10c3e7cfc..9e1fed346 100644 --- a/src/gba/gba-sio.h +++ b/src/gba/gba-sio.h @@ -19,12 +19,14 @@ enum { struct GBASIO; struct GBASIODriver { - void (*init)(struct GBASIODriver* driver, struct GBASIO* sio); - void (*deinit)(struct GBASIODriver* driver); + struct GBASIO* p; - int (*attach)(struct GBASIODriver* driver); - int (*detach)(struct GBASIODriver* driver); + void (*init)(struct GBASIODriver* driver); + void (*deinit)(struct GBASIODriver* driver); + int (*load)(struct GBASIODriver* driver); + int (*unload)(struct GBASIODriver* driver); void (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value); + int32_t (*processEvents)(struct GBASIODriver* driver, int32_t cycles); }; struct GBASIODriverSet { @@ -72,6 +74,8 @@ struct GBASIO { }; void GBASIOInit(struct GBASIO* sio); +void GBASIODeinit(struct GBASIO* sio); + void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers); void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASIOMode mode); @@ -79,4 +83,6 @@ void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value); void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value); void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value); +int32_t GBASIOProcessEvents(struct GBASIO* sio, int32_t cycles); + #endif From 043d396320cf21acdaf507de80673c1e8528d3f3 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 5 Feb 2014 01:22:34 -0800 Subject: [PATCH 18/26] Make socket shims inline --- src/util/socket.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/util/socket.h b/src/util/socket.h index 1f643346e..e88d017c4 100644 --- a/src/util/socket.h +++ b/src/util/socket.h @@ -16,21 +16,21 @@ typedef int Socket; #endif -void SocketSubsystemInitialize() { +static inline void SocketSubsystemInitialize() { #ifdef _WIN32 WSAStartup(MAKEWORD(2, 2), 0); #endif } -ssize_t SocketSend(Socket socket, const void* buffer, size_t size) { +static inline ssize_t SocketSend(Socket socket, const void* buffer, size_t size) { return write(socket, buffer, size); } -ssize_t SocketRecv(Socket socket, void* buffer, size_t size) { +static inline ssize_t SocketRecv(Socket socket, void* buffer, size_t size) { return read(socket, buffer, size); } -Socket SocketOpenTCP(int port, uint32_t bindAddress) { +static inline Socket SocketOpenTCP(int port, uint32_t bindAddress) { Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { return sock; @@ -51,19 +51,19 @@ Socket SocketOpenTCP(int port, uint32_t bindAddress) { return sock; } -Socket SocketListen(Socket socket, int queueLength) { +static inline Socket SocketListen(Socket socket, int queueLength) { return listen(socket, queueLength); } -Socket SocketAccept(Socket socket, struct sockaddr* restrict address, socklen_t* restrict addressLength) { +static inline Socket SocketAccept(Socket socket, struct sockaddr* restrict address, socklen_t* restrict addressLength) { return accept(socket, address, addressLength); } -int SocketClose(Socket socket) { +static inline int SocketClose(Socket socket) { return close(socket) >= 0; } -int SocketSetBlocking(Socket socket, int blocking) { +static inline int SocketSetBlocking(Socket socket, int blocking) { #ifdef _WIN32 blocking = !blocking; return ioctlsocket(socket, FIONBIO, &blocking) == NO_ERROR; From a2a3f317b5d393d5f14865b5233aef9adf864787 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 5 Feb 2014 01:50:01 -0800 Subject: [PATCH 19/26] Make driver loading signal failure, and fix case where setting a driver can cause a null pointer deref --- src/gba/gba-sio.c | 8 ++++++-- src/gba/gba-sio.h | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/gba/gba-sio.c b/src/gba/gba-sio.c index e320169ba..a5f917000 100644 --- a/src/gba/gba-sio.c +++ b/src/gba/gba-sio.c @@ -83,9 +83,13 @@ void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASI driver->p = sio; if (driver->init) { - driver->init(driver); + if (!driver->init(driver)) { + driver->deinit(driver); + GBALog(sio->p, GBA_LOG_ERROR, "Could not initialize SIO driver"); + return; + } } - if (*driverLoc == sio->activeDriver) { + if (*driverLoc && *driverLoc == sio->activeDriver) { sio->activeDriver = driver; if ((*driverLoc)->load) { (*driverLoc)->load(*driverLoc); diff --git a/src/gba/gba-sio.h b/src/gba/gba-sio.h index 9e1fed346..6ada65f9c 100644 --- a/src/gba/gba-sio.h +++ b/src/gba/gba-sio.h @@ -21,11 +21,11 @@ struct GBASIO; struct GBASIODriver { struct GBASIO* p; - void (*init)(struct GBASIODriver* driver); + int (*init)(struct GBASIODriver* driver); void (*deinit)(struct GBASIODriver* driver); int (*load)(struct GBASIODriver* driver); int (*unload)(struct GBASIODriver* driver); - void (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value); + int (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value); int32_t (*processEvents)(struct GBASIODriver* driver, int32_t cycles); }; From 3422527d5a1a71b4b4c9a99f723e034b2de91b53 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 5 Feb 2014 02:02:13 -0800 Subject: [PATCH 20/26] Read SIO registers from sio field --- src/gba/gba-io.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gba/gba-io.c b/src/gba/gba-io.c index 9c163cb31..b5b5dccae 100644 --- a/src/gba/gba-io.c +++ b/src/gba/gba-io.c @@ -375,6 +375,11 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { } break; + case REG_SIOCNT: + return gba->sio.siocnt; + case REG_RCNT: + return gba->sio.rcnt; + case REG_DMA0CNT_LO: case REG_DMA1CNT_LO: case REG_DMA2CNT_LO: From 9c8e5fc2228f32e5b986bf9f121de8ab58a35ca1 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 10 Feb 2014 01:42:40 -0800 Subject: [PATCH 21/26] SIO registers can now be read and written properly --- src/gba/gba-io.c | 8 ++++++++ src/gba/gba-sio.c | 6 +++--- src/gba/gba.c | 10 ++++++---- src/util/socket.h | 5 +++++ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/gba/gba-io.c b/src/gba/gba-io.c index b5b5dccae..59c2ec678 100644 --- a/src/gba/gba-io.c +++ b/src/gba/gba-io.c @@ -259,6 +259,9 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { value &= 0xC1FF; GBASIOWriteRCNT(&gba->sio, value); break; + case REG_SIOMLT_SEND: + GBASIOWriteSIOMLT_SEND(&gba->sio, value); + break; // Interrupts and misc case REG_WAITCNT: @@ -411,6 +414,11 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { case REG_DMA1CNT_HI: case REG_DMA2CNT_HI: case REG_DMA3CNT_HI: + case REG_SIOMULTI0: + case REG_SIOMULTI1: + case REG_SIOMULTI2: + case REG_SIOMULTI3: + case REG_SIOMLT_SEND: case REG_IE: case REG_IF: case REG_WAITCNT: diff --git a/src/gba/gba-sio.c b/src/gba/gba-sio.c index a5f917000..466d20781 100644 --- a/src/gba/gba-sio.c +++ b/src/gba/gba-sio.c @@ -108,11 +108,11 @@ void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value) { } void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) { + if (sio->activeDriver && sio->activeDriver->writeRegister) { + value = sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOCNT, value); + } sio->siocnt = value; _switchMode(sio); - if (sio->activeDriver && sio->activeDriver->writeRegister) { - sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOCNT, value); - } } void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value) { diff --git a/src/gba/gba.c b/src/gba/gba.c index 8adeeaa83..4550b53c9 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -2,6 +2,7 @@ #include "gba-bios.h" #include "gba-io.h" +#include "gba-sio.h" #include "gba-thread.h" #include "memory.h" @@ -198,6 +199,11 @@ static void GBAProcessEvents(struct ARMBoard* board) { nextEvent = testEvent; } + testEvent = GBASIOProcessEvents(&gbaBoard->p->sio, cycles); + if (testEvent < nextEvent) { + nextEvent = testEvent; + } + board->cpu->cycles -= cycles; board->cpu->nextEvent = nextEvent; } while (board->cpu->cycles >= board->cpu->nextEvent); @@ -447,10 +453,6 @@ void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) { }; void GBAWriteIE(struct GBA* gba, uint16_t value) { - if (value & (1 << IRQ_SIO)) { - GBALog(gba, GBA_LOG_STUB, "SIO interrupts not implemented"); - } - if (value & (1 << IRQ_KEYPAD)) { GBALog(gba, GBA_LOG_STUB, "Keypad interrupts not implemented"); } diff --git a/src/util/socket.h b/src/util/socket.h index e88d017c4..433e9bd8d 100644 --- a/src/util/socket.h +++ b/src/util/socket.h @@ -8,6 +8,7 @@ typedef SOCKET Socket; #else #include #include +#include #include #include #include @@ -81,4 +82,8 @@ static inline int SocketSetBlocking(Socket socket, int blocking) { #endif } +static inline int SocketSetTCPPush(Socket socket, int push) { + return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0; +} + #endif From 764b3fce10c6efe989c5107f249e880cebef26d8 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 8 Feb 2014 03:22:43 -0800 Subject: [PATCH 22/26] Fix SIO loading of a driver that is for the current mode --- src/gba/gba-sio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gba/gba-sio.c b/src/gba/gba-sio.c index 466d20781..03df23785 100644 --- a/src/gba/gba-sio.c +++ b/src/gba/gba-sio.c @@ -89,10 +89,10 @@ void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASI return; } } - if (*driverLoc && *driverLoc == sio->activeDriver) { + if (sio->mode == mode) { sio->activeDriver = driver; - if ((*driverLoc)->load) { - (*driverLoc)->load(*driverLoc); + if (driver->load) { + driver->load(driver); } } } From 6451aeaefc7c2d46861fa2794c7b6abc0e086c1f Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 8 Feb 2014 03:23:05 -0800 Subject: [PATCH 23/26] Support normal mode drivers --- src/gba/gba-sio.c | 7 +++++++ src/gba/gba-sio.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/gba/gba-sio.c b/src/gba/gba-sio.c index 03df23785..4eab4e9ba 100644 --- a/src/gba/gba-sio.c +++ b/src/gba/gba-sio.c @@ -6,6 +6,9 @@ static struct GBASIODriver* _lookupDriver(struct GBASIO* sio, enum GBASIOMode mode) { switch (mode) { + case SIO_NORMAL_8: + case SIO_NORMAL_32: + return sio->drivers.normal; case SIO_MULTI: return sio->drivers.multiplayer; case SIO_JOYBUS: @@ -61,6 +64,10 @@ void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) { void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASIOMode mode) { struct GBASIODriver** driverLoc; switch (mode) { + case SIO_NORMAL_8: + case SIO_NORMAL_32: + driverLoc = &sio->drivers.normal; + break; case SIO_MULTI: driverLoc = &sio->drivers.multiplayer; break; diff --git a/src/gba/gba-sio.h b/src/gba/gba-sio.h index 6ada65f9c..7a8f57c49 100644 --- a/src/gba/gba-sio.h +++ b/src/gba/gba-sio.h @@ -30,6 +30,7 @@ struct GBASIODriver { }; struct GBASIODriverSet { + struct GBASIODriver* normal; struct GBASIODriver* multiplayer; struct GBASIODriver* joybus; }; From eb5580f719aac6d7f08186bf2a079c446e05c92f Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 8 Feb 2014 13:20:47 -0800 Subject: [PATCH 24/26] Make DriverSet setting read in normal driver --- src/gba/gba-sio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gba/gba-sio.c b/src/gba/gba-sio.c index 4eab4e9ba..0da1f8085 100644 --- a/src/gba/gba-sio.c +++ b/src/gba/gba-sio.c @@ -53,6 +53,9 @@ void GBASIODeinit(struct GBASIO* sio) { } void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) { + if (drivers->normal) { + GBASIOSetDriver(sio, drivers->normal, SIO_NORMAL_8); + } if (drivers->multiplayer) { GBASIOSetDriver(sio, drivers->multiplayer, SIO_MULTI); } From e9c441281988d973b8e9fc7956e983249f7c8acd Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 10 Feb 2014 23:13:39 -0800 Subject: [PATCH 25/26] Put missing returns in SDL event handling --- src/platform/sdl/sdl-events.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 1efea8360..00de89561 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -91,7 +91,7 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents if (event->type == SDL_KEYDOWN && context->debugger) { ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL); } - break; + return; case SDLK_TAB: context->sync.audioWait = event->type != SDL_KEYDOWN; return; @@ -103,6 +103,7 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents if (!isPaused) { GBAThreadUnpause(context); } + return; default: if (event->type == SDL_KEYDOWN) { if (event->keysym.mod & GUI_MOD) { From 4d8a00c18068c49108998077af3d0083c3637e6c Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 10 Feb 2014 23:59:07 -0800 Subject: [PATCH 26/26] Add thread-interrupt functions for having multiple threads that want to pause the GBA thread --- src/gba/gba-thread.c | 27 ++++++++++++++++++++++++++- src/gba/gba-thread.h | 11 ++++++++--- src/platform/sdl/sdl-events.c | 25 ++++++------------------- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 00e189c38..56a5555bd 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -37,6 +37,12 @@ static void _changeState(struct GBAThread* threadContext, enum ThreadState newSt MutexUnlock(&threadContext->stateMutex); } +static void _waitOnInterrupt(struct GBAThread* threadContext) { + while (threadContext->state == THREAD_INTERRUPTED) { + ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); + } +} + static THREAD_ENTRY _GBAThreadRun(void* context) { #ifdef USE_PTHREADS pthread_once(&_contextOnce, _createTLS); @@ -122,7 +128,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { } } MutexLock(&threadContext->stateMutex); - while (threadContext->state == THREAD_PAUSED) { + while (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_INTERRUPTED) { ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); } MutexUnlock(&threadContext->stateMutex); @@ -239,9 +245,25 @@ void GBAThreadJoin(struct GBAThread* threadContext) { free(threadContext->rewindBuffer); } +void GBAThreadInterrupt(struct GBAThread* threadContext) { + MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); + threadContext->savedState = threadContext->state; + threadContext->state = THREAD_INTERRUPTED; + if (threadContext->debugger && threadContext->debugger->state == DEBUGGER_RUNNING) { + threadContext->debugger->state = DEBUGGER_EXITING; + } + MutexUnlock(&threadContext->stateMutex); +} + +void GBAThreadContinue(struct GBAThread* threadContext) { + _changeState(threadContext, threadContext->savedState, 1); +} + void GBAThreadPause(struct GBAThread* threadContext) { int frameOn = 1; MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); if (threadContext->state == THREAD_RUNNING) { if (threadContext->debugger && threadContext->debugger->state == DEBUGGER_RUNNING) { threadContext->debugger->state = DEBUGGER_EXITING; @@ -261,6 +283,7 @@ void GBAThreadPause(struct GBAThread* threadContext) { void GBAThreadUnpause(struct GBAThread* threadContext) { int frameOn = 1; MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); if (threadContext->state == THREAD_PAUSED) { threadContext->state = THREAD_RUNNING; ConditionWake(&threadContext->stateCond); @@ -277,6 +300,7 @@ void GBAThreadUnpause(struct GBAThread* threadContext) { int GBAThreadIsPaused(struct GBAThread* threadContext) { int isPaused; MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); isPaused = threadContext->state == THREAD_PAUSED; MutexUnlock(&threadContext->stateMutex); return isPaused; @@ -285,6 +309,7 @@ int GBAThreadIsPaused(struct GBAThread* threadContext) { void GBAThreadTogglePause(struct GBAThread* threadContext) { int frameOn = 1; MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); if (threadContext->state == THREAD_PAUSED) { threadContext->state = THREAD_RUNNING; ConditionWake(&threadContext->stateCond); diff --git a/src/gba/gba-thread.h b/src/gba/gba-thread.h index 99352ee59..b19432f3c 100644 --- a/src/gba/gba-thread.h +++ b/src/gba/gba-thread.h @@ -10,9 +10,10 @@ typedef void (*ThreadCallback)(struct GBAThread* threadContext); enum ThreadState { THREAD_INITIALIZED = -1, THREAD_RUNNING = 0, - THREAD_PAUSED = 1, - THREAD_EXITING = 2, - THREAD_SHUTDOWN = 3 + THREAD_INTERRUPTED = 1, + THREAD_PAUSED = 2, + THREAD_EXITING = 3, + THREAD_SHUTDOWN = 4 }; struct GBASync { @@ -49,6 +50,7 @@ struct GBAThread { Mutex stateMutex; Condition stateCond; + enum ThreadState savedState; GBALogHandler logHandler; ThreadCallback startCallback; @@ -71,6 +73,9 @@ int GBAThreadHasStarted(struct GBAThread* threadContext); void GBAThreadEnd(struct GBAThread* threadContext); void GBAThreadJoin(struct GBAThread* threadContext); +void GBAThreadInterrupt(struct GBAThread* threadContext); +void GBAThreadContinue(struct GBAThread* threadContext); + void GBAThreadPause(struct GBAThread* threadContext); void GBAThreadUnpause(struct GBAThread* threadContext); int GBAThreadIsPaused(struct GBAThread* threadContext); diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 00de89561..af20fc3ec 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -55,7 +55,6 @@ static void _pauseAfterFrame(struct GBAThread* context) { static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) { enum GBAKey key = 0; - int isPaused = GBAThreadIsPaused(context); switch (event->keysym.sym) { case SDLK_z: key = GBA_KEY_A; @@ -96,13 +95,9 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents context->sync.audioWait = event->type != SDL_KEYDOWN; return; case SDLK_LEFTBRACKET: - if (!isPaused) { - GBAThreadPause(context); - } + GBAThreadInterrupt(context); GBARewind(context, 10); - if (!isPaused) { - GBAThreadUnpause(context); - } + GBAThreadContinue(context); return; default: if (event->type == SDL_KEYDOWN) { @@ -138,13 +133,9 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents case SDLK_F8: case SDLK_F9: case SDLK_F10: - if (!isPaused) { - GBAThreadPause(context); - } + GBAThreadInterrupt(context); GBASaveState(context->gba, event->keysym.sym - SDLK_F1); - if (!isPaused) { - GBAThreadUnpause(context); - } + GBAThreadContinue(context); break; default: break; @@ -161,13 +152,9 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents case SDLK_F8: case SDLK_F9: case SDLK_F10: - if (!isPaused) { - GBAThreadPause(context); - } + GBAThreadInterrupt(context); GBALoadState(context->gba, event->keysym.sym - SDLK_F1); - if (!isPaused) { - GBAThreadUnpause(context); - } + GBAThreadContinue(context); break; default: break;