GBA SIO: Attempt to sync to clock signal

This commit is contained in:
Jeffrey Pfau 2015-03-03 02:29:19 -08:00
parent af6a069b9e
commit 5185e5065c
2 changed files with 76 additions and 58 deletions

View File

@ -7,8 +7,8 @@
#include "gba/io.h"
#define CLOCK_GRAIN 2048
#define CYCLES_PER_BIT 75
#define CLOCK_GRAIN (CYCLES_PER_BIT * 8)
const uint16_t DOLPHIN_CLOCK_PORT = 49420;
const uint16_t DOLPHIN_DATA_PORT = 54970;
@ -18,15 +18,16 @@ enum {
CMD_POLL = 0x00,
CMD_TRANS = 0x14,
CMD_RECV = 0x15,
CMD_NONE = 0x80
};
// static bool GBASIODolphinInit(struct GBASIODriver* driver);
// static void GBASIODolphinDeinit(struct GBASIODriver* driver);
static bool GBASIODolphinLoad(struct GBASIODriver* driver);
// static bool GBASIODolphinUnload(struct GBASIODriver* driver);
static uint16_t GBASIODolphinWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
static int32_t GBASIODolphinProcessEvents(struct GBASIODriver* driver, int32_t cycles);
static int32_t _processCommand(struct GBASIODolphin* dol, uint8_t command);
void GBASIODolphinCreate(struct GBASIODolphin* dol) {
dol->d.init = 0;
dol->d.deinit = 0;
@ -75,18 +76,21 @@ bool GBASIODolphinConnect(struct GBASIODolphin* dol, const struct Address* addre
dol->clock = SocketConnectTCP(clockPort, address);
if (SOCKET_FAILED(dol->clock)) {
SocketClose(dol->clock);
SocketClose(dol->data);
dol->data = INVALID_SOCKET;
return false;
}
SocketSetBlocking(dol->data, false);
SocketSetBlocking(dol->clock, false);
SocketSetTCPPush(dol->data, true);
return true;
}
static bool GBASIODolphinLoad(struct GBASIODriver* driver) {
struct GBASIODolphin* dol = (struct GBASIODolphin*) driver;
dol->nextEvent = 0;
dol->clockSlice = 0;
return true;
}
@ -108,63 +112,76 @@ uint16_t GBASIODolphinWriteRegister(struct GBASIODriver* driver, uint32_t addres
int32_t GBASIODolphinProcessEvents(struct GBASIODriver* driver, int32_t cycles) {
struct GBASIODolphin* dol = (struct GBASIODolphin*) driver;
dol->nextEvent -= cycles;
dol->clockSlice -= cycles;
if (dol->nextEvent <= 0) {
uint8_t command;
int32_t nextEvent = CLOCK_GRAIN;
uint32_t clocks = 0;
uint32_t clockSlice;
while (SocketRecv(dol->clock, &clockSlice, 4) == 4) {
clocks += ntohl(clockSlice);
}
while (SocketRecv(dol->data, &command, 1) == 1) {
int bitsOnLine = 8 + 1;
uint8_t buffer[5];
switch (command) {
case CMD_RESET:
dol->d.p->p->memory.io[REG_JOYCNT >> 1] |= 1;
if (dol->d.p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
GBARaiseIRQ(dol->d.p->p, IRQ_SIO);
}
// Fall through
case CMD_POLL:
buffer[0] = 0x00;
buffer[1] = 0x04;
buffer[2] = dol->d.p->p->memory.io[REG_JOYSTAT >> 1];
SocketSend(dol->data, buffer, 3);
bitsOnLine += 24 + 1;
break;
case CMD_RECV:
dol->d.p->p->memory.io[REG_JOYCNT >> 1] |= 2;
dol->d.p->p->memory.io[REG_JOYSTAT >> 1] |= 2;
SocketRecv(dol->data, &buffer, 4);
dol->d.p->p->memory.io[REG_JOY_RECV_LO >> 1] = buffer[0] | (buffer[1] << 8);
dol->d.p->p->memory.io[REG_JOY_RECV_HI >> 1] = buffer[2] | (buffer[3] << 8);
buffer[0] = dol->d.p->p->memory.io[REG_JOYSTAT >> 1];
SocketSend(dol->data, buffer, 1);
if (dol->d.p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
GBARaiseIRQ(dol->d.p->p, IRQ_SIO);
}
bitsOnLine += 40 + 1;
break;
case CMD_TRANS:
dol->d.p->p->memory.io[REG_JOYCNT >> 1] |= 4;
dol->d.p->p->memory.io[REG_JOYSTAT >> 1] &= ~8;
buffer[0] = dol->d.p->p->memory.io[REG_JOY_TRANS_LO >> 1];
buffer[1] = dol->d.p->p->memory.io[REG_JOY_TRANS_LO >> 1] >> 8;
buffer[2] = dol->d.p->p->memory.io[REG_JOY_TRANS_HI >> 1];
buffer[3] = dol->d.p->p->memory.io[REG_JOY_TRANS_HI >> 1] >> 8;
buffer[4] = dol->d.p->p->memory.io[REG_JOYSTAT >> 1];
SocketSend(dol->data, buffer, 5);
if (dol->d.p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
GBARaiseIRQ(dol->d.p->p, IRQ_SIO);
}
bitsOnLine += 40 + 1;
break;
int32_t clockSlice = 0;
if (dol->clockSlice <= 0) {
Socket r = dol->clock;
if (SocketPoll(1, &r, 0, 0, 1) == 1 && SocketRecv(dol->clock, &clockSlice, 4) == 4) {
clockSlice = ntohl(clockSlice);
dol->clockSlice += clockSlice;
}
nextEvent = bitsOnLine * CYCLES_PER_BIT;
}
dol->nextEvent += nextEvent;
if (SocketRecv(dol->data, &command, 1) == 1) {
dol->nextEvent += _processCommand(dol, command);
} else {
dol->nextEvent += CLOCK_GRAIN;
}
if (dol->nextEvent > dol->clockSlice) {
dol->nextEvent = dol->clockSlice;
}
}
return dol->nextEvent;
}
int32_t _processCommand(struct GBASIODolphin* dol, uint8_t command) {
int bitsOnLine = 8 + 1;
uint8_t buffer[5];
switch (command) {
case CMD_RESET:
dol->d.p->p->memory.io[REG_JOYCNT >> 1] |= 1;
if (dol->d.p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
GBARaiseIRQ(dol->d.p->p, IRQ_SIO);
}
// Fall through
case CMD_POLL:
buffer[0] = 0x00;
buffer[1] = 0x04;
buffer[2] = dol->d.p->p->memory.io[REG_JOYSTAT >> 1];
SocketSend(dol->data, buffer, 3);
bitsOnLine += 24 + 1;
break;
case CMD_RECV:
dol->d.p->p->memory.io[REG_JOYCNT >> 1] |= 2;
dol->d.p->p->memory.io[REG_JOYSTAT >> 1] |= 2;
SocketRecv(dol->data, &buffer, 4);
dol->d.p->p->memory.io[REG_JOY_RECV_LO >> 1] = buffer[0] | (buffer[1] << 8);
dol->d.p->p->memory.io[REG_JOY_RECV_HI >> 1] = buffer[2] | (buffer[3] << 8);
buffer[0] = dol->d.p->p->memory.io[REG_JOYSTAT >> 1];
SocketSend(dol->data, buffer, 1);
if (dol->d.p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
GBARaiseIRQ(dol->d.p->p, IRQ_SIO);
}
bitsOnLine += 40 + 1;
break;
case CMD_TRANS:
dol->d.p->p->memory.io[REG_JOYCNT >> 1] |= 4;
dol->d.p->p->memory.io[REG_JOYSTAT >> 1] &= ~8;
buffer[0] = dol->d.p->p->memory.io[REG_JOY_TRANS_LO >> 1];
buffer[1] = dol->d.p->p->memory.io[REG_JOY_TRANS_LO >> 1] >> 8;
buffer[2] = dol->d.p->p->memory.io[REG_JOY_TRANS_HI >> 1];
buffer[3] = dol->d.p->p->memory.io[REG_JOY_TRANS_HI >> 1] >> 8;
buffer[4] = dol->d.p->p->memory.io[REG_JOYSTAT >> 1];
SocketSend(dol->data, buffer, 5);
if (dol->d.p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
GBARaiseIRQ(dol->d.p->p, IRQ_SIO);
}
bitsOnLine += 40 + 1;
break;
}
return bitsOnLine * CYCLES_PER_BIT;
}

View File

@ -20,6 +20,7 @@ struct GBASIODolphin {
Socket clock;
int32_t nextEvent;
int32_t clockSlice;
};
void GBASIODolphinCreate(struct GBASIODolphin*);