mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' into qt
This commit is contained in:
commit
c5d243fca2
|
@ -31,6 +31,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)
|
||||
|
|
|
@ -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 _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;
|
||||
}
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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;
|
||||
gba->memory.io[REG_SOUNDBIAS >> 1] = 0x200;
|
||||
}
|
||||
|
@ -254,6 +255,18 @@ 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;
|
||||
case REG_SIOMLT_SEND:
|
||||
GBASIOWriteSIOMLT_SEND(&gba->sio, value);
|
||||
break;
|
||||
|
||||
// Interrupts and misc
|
||||
case REG_WAITCNT:
|
||||
GBAAdjustWaitstates(&gba->memory, value);
|
||||
|
@ -369,6 +382,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:
|
||||
|
@ -400,6 +418,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:
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
|
@ -99,6 +105,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) {
|
||||
|
@ -120,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);
|
||||
|
@ -237,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;
|
||||
|
@ -259,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);
|
||||
|
@ -275,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;
|
||||
|
@ -283,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);
|
||||
|
|
|
@ -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 {
|
||||
|
@ -36,6 +37,7 @@ struct GBAThread {
|
|||
|
||||
// Input
|
||||
struct GBAVideoRenderer* renderer;
|
||||
struct GBASIODriverSet sioDrivers;
|
||||
struct ARMDebugger* debugger;
|
||||
int fd;
|
||||
int biosFd;
|
||||
|
@ -48,6 +50,7 @@ struct GBAThread {
|
|||
|
||||
Mutex stateMutex;
|
||||
Condition stateCond;
|
||||
enum ThreadState savedState;
|
||||
|
||||
GBALogHandler logHandler;
|
||||
ThreadCallback startCallback;
|
||||
|
@ -70,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);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "gba-bios.h"
|
||||
#include "gba-io.h"
|
||||
#include "gba-sio.h"
|
||||
#include "gba-thread.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
@ -122,6 +123,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));
|
||||
|
||||
|
@ -195,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);
|
||||
|
@ -444,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");
|
||||
}
|
||||
|
|
|
@ -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 GBA {
|
|||
struct GBAMemory memory;
|
||||
struct GBAVideo video;
|
||||
struct GBAAudio audio;
|
||||
struct GBASIO sio;
|
||||
|
||||
struct GBASync* sync;
|
||||
|
||||
|
|
|
@ -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 @@ 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)
|
||||
|
|
|
@ -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 @@ 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
|
||||
|
||||
#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 @@ 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);
|
||||
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 @@ 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,13 +5,21 @@
|
|||
#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 @@ 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) {
|
||||
case SDLK_z:
|
||||
key = GBA_KEY_A;
|
||||
|
@ -83,22 +90,25 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_Ke
|
|||
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 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_Ke
|
|||
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 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_Ke
|
|||
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 @@ 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
|
||||
|
@ -217,7 +219,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:
|
||||
|
|
|
@ -7,12 +7,18 @@
|
|||
|
||||
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);
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue