all repos — mgba @ c5d243fca282cf11d7f2c38010fce18361babdc2

mGBA Game Boy Advance Emulator

Merge branch 'master' into qt
Jeffrey Pfau jeffrey@endrift.com
Mon, 10 Feb 2014 23:59:12 -0800
commit

c5d243fca282cf11d7f2c38010fce18361babdc2

parent

b691c93416d44b89e16df3f700c00198deb7cf1f

M CMakeLists.txtCMakeLists.txt

@@ -31,6 +31,13 @@ file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/posix/*.c)

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)
M src/debugger/gdb-stub.csrc/debugger/gdb-stub.c

@@ -1,13 +1,8 @@

#include "gdb-stub.h" #include <errno.h> -#include <fcntl.h> -#include <netinet/in.h> #include <signal.h> -#include <stdio.h> #include <string.h> -#include <sys/socket.h> -#include <unistd.h> enum GDBError { GDB_NO_ERROR = 0x00,

@@ -50,15 +45,12 @@ }

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 _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 @@ char nak = '-';

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 @@ stub->outgoing[i + 3] = 0;

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 _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 @@ if (stub->socket >= 0) {

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) { - goto cleanup; - } - int flags = fcntl(stub->socket, F_GETFL); - if (flags == -1) { + if (!SocketSetBlocking(stub->socket, 0)) { 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 GDBStubShutdown(struct GDBStub* stub) { GDBStubHangup(stub); if (stub->socket >= 0) { - close(stub->socket); + SocketClose(stub->socket); stub->socket = -1; } }

@@ -508,13 +484,11 @@ if (stub->socket == -1) {

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 @@ goto connectionLost;

} } 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; }
M src/debugger/gdb-stub.hsrc/debugger/gdb-stub.h

@@ -2,6 +2,7 @@ #ifndef GDB_STUB_H

#define GDB_STUB_H #include "debugger.h" +#include "socket.h" #define GDB_STUB_MAX_LINE 1200

@@ -19,8 +20,8 @@ char line[GDB_STUB_MAX_LINE];

char outgoing[GDB_STUB_MAX_LINE]; enum GDBStubAckState lineAck; - int socket; - int connection; + Socket socket; + Socket connection; }; void GDBStubCreate(struct GDBStub*);
M src/gba/gba-io.csrc/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 @@ };

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; gba->memory.io[REG_SOUNDBIAS >> 1] = 0x200; }

@@ -254,6 +255,18 @@ value &= 0x00C7;

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; + case REG_SIOMLT_SEND: + GBASIOWriteSIOMLT_SEND(&gba->sio, value); + break; + // Interrupts and misc case REG_WAITCNT: GBAAdjustWaitstates(&gba->memory, value);

@@ -369,6 +382,11 @@ return 0x3FF ^ *gba->keySource;

} 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:

@@ -400,6 +418,11 @@ case REG_DMA0CNT_HI:

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:
A src/gba/gba-sio.c

@@ -0,0 +1,139 @@

+#include "gba-sio.h" + +#include "gba-io.h" + +#include <limits.h> + +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: + 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); + } + if (oldMode != mode) { + if (sio->activeDriver && sio->activeDriver->unload) { + sio->activeDriver->unload(sio->activeDriver); + } + sio->activeDriver = _lookupDriver(sio, mode); + if (sio->activeDriver && sio->activeDriver->load) { + sio->activeDriver->load(sio->activeDriver); + } + } +} + +void GBASIOInit(struct GBASIO* sio) { + sio->rcnt = RCNT_INITIAL; + sio->siocnt = 0; + _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->normal) { + GBASIOSetDriver(sio, drivers->normal, SIO_NORMAL_8); + } + 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_NORMAL_8: + case SIO_NORMAL_32: + driverLoc = &sio->drivers.normal; + break; + 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)->unload) { + (*driverLoc)->unload(*driverLoc); + } + if ((*driverLoc)->deinit) { + (*driverLoc)->deinit(*driverLoc); + } + } + if (driver) { + driver->p = sio; + + if (driver->init) { + if (!driver->init(driver)) { + driver->deinit(driver); + GBALog(sio->p, GBA_LOG_ERROR, "Could not initialize SIO driver"); + return; + } + } + if (sio->mode == mode) { + sio->activeDriver = driver; + if (driver->load) { + driver->load(driver); + } + } + } + *driverLoc = driver; +} + +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) { + if (sio->activeDriver && sio->activeDriver->writeRegister) { + value = sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOCNT, value); + } + sio->siocnt = value; + _switchMode(sio); +} + +void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value) { + if (sio->activeDriver && sio->activeDriver->writeRegister) { + 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; +}
A src/gba/gba-sio.h

@@ -0,0 +1,89 @@

+#ifndef GBA_SIO_H +#define GBA_SIO_H + +#include <stdint.h> + +enum GBASIOMode { + SIO_NORMAL_8 = 0, + SIO_NORMAL_32 = 1, + SIO_MULTI = 2, + SIO_UART = 3, + SIO_GPIO = 8, + SIO_JOYBUS = 12 +}; + +enum { + RCNT_INITIAL = 0x8000 +}; + +struct GBASIO; + +struct GBASIODriver { + struct GBASIO* p; + + int (*init)(struct GBASIODriver* driver); + void (*deinit)(struct GBASIODriver* driver); + int (*load)(struct GBASIODriver* driver); + int (*unload)(struct GBASIODriver* driver); + int (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value); + int32_t (*processEvents)(struct GBASIODriver* driver, int32_t cycles); +}; + +struct GBASIODriverSet { + struct GBASIODriver* normal; + struct GBASIODriver* multiplayer; + struct GBASIODriver* joybus; +}; + +struct GBASIO { + struct GBA* p; + + enum GBASIOMode mode; + struct GBASIODriverSet drivers; + struct GBASIODriver* activeDriver; + + 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 GBASIODeinit(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); +void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value); + +int32_t GBASIOProcessEvents(struct GBASIO* sio, int32_t cycles); + +#endif
M src/gba/gba-thread.csrc/gba/gba-thread.c

@@ -37,6 +37,12 @@ }

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);

@@ -99,6 +105,8 @@ GBAAttachDebugger(&gba, threadContext->debugger);

ARMDebuggerEnter(threadContext->debugger, DEBUGGER_ENTER_ATTACHED); } + GBASIOSetDriverSet(&gba.sio, &threadContext->sioDrivers); + gba.keySource = &threadContext->activeKeys; if (threadContext->startCallback) {

@@ -120,7 +128,7 @@ ARMRun(&gba.cpu);

} } 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);

@@ -237,9 +245,25 @@ }

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;

@@ -259,6 +283,7 @@

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);

@@ -275,6 +300,7 @@

int GBAThreadIsPaused(struct GBAThread* threadContext) { int isPaused; MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); isPaused = threadContext->state == THREAD_PAUSED; MutexUnlock(&threadContext->stateMutex); return isPaused;

@@ -283,6 +309,7 @@

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);
M src/gba/gba-thread.hsrc/gba/gba-thread.h

@@ -10,9 +10,10 @@

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 {

@@ -36,6 +37,7 @@ struct GBA* gba;

// Input struct GBAVideoRenderer* renderer; + struct GBASIODriverSet sioDrivers; struct ARMDebugger* debugger; int fd; int biosFd;

@@ -48,6 +50,7 @@ Thread thread;

Mutex stateMutex; Condition stateCond; + enum ThreadState savedState; GBALogHandler logHandler; ThreadCallback startCallback;

@@ -69,6 +72,9 @@ int GBAThreadStart(struct GBAThread* threadContext);

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);
M src/gba/gba.csrc/gba/gba.c

@@ -2,6 +2,7 @@ #include "gba.h"

#include "gba-bios.h" #include "gba-io.h" +#include "gba-sio.h" #include "gba-thread.h" #include "memory.h"

@@ -122,6 +123,9 @@ GBAAudioInit(&gba->audio);

GBAIOInit(gba); + gba->sio.p = gba; + GBASIOInit(&gba->sio); + gba->timersEnabled = 0; memset(gba->timers, 0, sizeof(gba->timers));

@@ -191,6 +195,11 @@ nextEvent = testEvent;

} testEvent = GBAMemoryRunDMAs(&gbaBoard->p->memory, cycles); + if (testEvent < nextEvent) { + nextEvent = testEvent; + } + + testEvent = GBASIOProcessEvents(&gbaBoard->p->sio, cycles); if (testEvent < nextEvent) { nextEvent = testEvent; }

@@ -444,10 +453,6 @@ }

}; 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"); }
M src/gba/gba.hsrc/gba/gba.h

@@ -7,6 +7,7 @@

#include "gba-memory.h" #include "gba-video.h" #include "gba-audio.h" +#include "gba-sio.h" #include <stdarg.h>

@@ -74,6 +75,7 @@ struct GBABoard board;

struct GBAMemory memory; struct GBAVideo video; struct GBAAudio audio; + struct GBASIO sio; struct GBASync* sync;
M src/platform/sdl/CMakeLists.txtsrc/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)

@@ -9,8 +24,6 @@ set(OPENGL_LIBRARY "-lEGL -lGLESv2 -lbcm_host")

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)
M src/platform/sdl/gl-main.csrc/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,38 @@

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 + +#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); + 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); #else SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 32, SDL_OPENGL); +#endif #endif renderer->d.outputBuffer = malloc(256 * 256 * 4);

@@ -158,10 +184,20 @@ glFlush();

} } 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); + 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); + } } } }

@@ -171,6 +207,9 @@ free(renderer->d.outputBuffer);

GBASDLDeinitEvents(&renderer->events); GBASDLDeinitAudio(&renderer->audio); +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_DestroyWindow(renderer->window); +#endif SDL_Quit(); }
M src/platform/sdl/sdl-events.csrc/platform/sdl/sdl-events.c

@@ -5,13 +5,21 @@ #include "gba-io.h"

#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; } 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; }

@@ -45,9 +53,8 @@ context->frameCallback = 0;

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) { case SDLK_z: key = GBA_KEY_A;

@@ -83,22 +90,25 @@ case SDLK_F11:

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; 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) { - if (event->keysym.mod & KMOD_CTRL) { + 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;

@@ -123,13 +133,9 @@ case SDLK_F7:

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;

@@ -146,13 +152,9 @@ case SDLK_F7:

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;

@@ -203,7 +205,7 @@ context->activeKeys &= ~((1 << GBA_KEY_UP) | (1 << GBA_KEY_LEFT) | (1 << GBA_KEY_DOWN) | (1 << GBA_KEY_RIGHT));

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

@@ -217,7 +219,7 @@ MutexUnlock(&context->stateMutex);

break; case SDL_KEYDOWN: case SDL_KEYUP: - _GBASDLHandleKeypress(context, &event->key); + _GBASDLHandleKeypress(context, sdlContext, &event->key); break; case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP:
M src/platform/sdl/sdl-events.hsrc/platform/sdl/sdl-events.h

@@ -7,12 +7,18 @@ #include <SDL.h>

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); + +enum GBAKey GBASDLMapButtonToKey(int button); enum GBAKey GBASDLMapButtonToKey(int button);
A src/util/socket.h

@@ -0,0 +1,89 @@

+#ifndef SOCKET_H +#define SOCKET_H + +#ifdef _WIN32 +#include <winsock2.h> + +typedef SOCKET Socket; +#else +#include <fcntl.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <stdio.h> +#include <sys/socket.h> +#include <unistd.h> + +typedef int Socket; +#endif + + +static inline void SocketSubsystemInitialize() { +#ifdef _WIN32 + WSAStartup(MAKEWORD(2, 2), 0); +#endif +} + +static inline ssize_t SocketSend(Socket socket, const void* buffer, size_t size) { + return write(socket, buffer, size); +} + +static inline ssize_t SocketRecv(Socket socket, void* buffer, size_t size) { + return read(socket, buffer, size); +} + +static inline 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; +} + +static inline Socket SocketListen(Socket socket, int queueLength) { + return listen(socket, queueLength); +} + +static inline Socket SocketAccept(Socket socket, struct sockaddr* restrict address, socklen_t* restrict addressLength) { + return accept(socket, address, addressLength); +} + +static inline int SocketClose(Socket socket) { + return close(socket) >= 0; +} + +static inline 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 +} + +static inline int SocketSetTCPPush(Socket socket, int push) { + return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0; +} + +#endif