mirror of https://github.com/mgba-emu/mgba.git
GBA SIO: Start moving common SIO logic out of drivers
This commit is contained in:
parent
451da0f8a4
commit
09a69a32c0
|
@ -120,8 +120,6 @@ struct GBASIODriver {
|
||||||
uint16_t (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value);
|
uint16_t (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value);
|
||||||
};
|
};
|
||||||
|
|
||||||
void GBASIOJOYCreate(struct GBASIODriver* sio);
|
|
||||||
|
|
||||||
enum GBASIOBattleChipGateFlavor {
|
enum GBASIOBattleChipGateFlavor {
|
||||||
GBA_FLAVOR_BATTLECHIP_GATE = 4,
|
GBA_FLAVOR_BATTLECHIP_GATE = 4,
|
||||||
GBA_FLAVOR_PROGRESS_GATE = 5,
|
GBA_FLAVOR_PROGRESS_GATE = 5,
|
||||||
|
|
|
@ -31,7 +31,6 @@ set(SOURCE_FILES
|
||||||
sharkport.c
|
sharkport.c
|
||||||
sio.c
|
sio.c
|
||||||
sio/gbp.c
|
sio/gbp.c
|
||||||
sio/joybus.c
|
|
||||||
timer.c
|
timer.c
|
||||||
video.c)
|
video.c)
|
||||||
|
|
||||||
|
|
100
src/gba/sio.c
100
src/gba/sio.c
|
@ -186,7 +186,32 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
|
||||||
sio->siocnt = value & 0x3000;
|
sio->siocnt = value & 0x3000;
|
||||||
_switchMode(sio);
|
_switchMode(sio);
|
||||||
}
|
}
|
||||||
if (sio->activeDriver && sio->activeDriver->writeRegister) {
|
int id = 0;
|
||||||
|
int connected = 0;
|
||||||
|
bool handled = false;
|
||||||
|
if (sio->activeDriver) {
|
||||||
|
handled = sio->activeDriver->handlesMode(sio->activeDriver, sio->mode);
|
||||||
|
if (handled) {
|
||||||
|
if (sio->activeDriver->deviceId) {
|
||||||
|
id = sio->activeDriver->deviceId(sio->activeDriver);
|
||||||
|
}
|
||||||
|
connected = sio->activeDriver->connectedDevices(sio->activeDriver);
|
||||||
|
handled = !!sio->activeDriver->writeRegister;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (sio->mode) {
|
||||||
|
case GBA_SIO_MULTI:
|
||||||
|
value &= 0xFF83;
|
||||||
|
value = GBASIOMultiplayerSetSlave(value, id || !connected);
|
||||||
|
value = GBASIOMultiplayerSetId(value, id);
|
||||||
|
value |= sio->siocnt & 0x00FC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (handled) {
|
||||||
value = sio->activeDriver->writeRegister(sio->activeDriver, GBA_REG_SIOCNT, value);
|
value = sio->activeDriver->writeRegister(sio->activeDriver, GBA_REG_SIOCNT, value);
|
||||||
} else {
|
} else {
|
||||||
// Dummy drivers
|
// Dummy drivers
|
||||||
|
@ -203,8 +228,7 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GBA_SIO_MULTI:
|
case GBA_SIO_MULTI:
|
||||||
value &= 0xFF83;
|
value = GBASIOMultiplayerFillReady(value);
|
||||||
value |= 0xC;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -215,7 +239,12 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t value) {
|
uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t value) {
|
||||||
if (sio->activeDriver && sio->activeDriver->writeRegister) {
|
bool handled = false;
|
||||||
|
if (sio->activeDriver) {
|
||||||
|
handled = sio->activeDriver->writeRegister && sio->activeDriver->handlesMode(sio->activeDriver, sio->mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
return sio->activeDriver->writeRegister(sio->activeDriver, address, value);
|
return sio->activeDriver->writeRegister(sio->activeDriver, address, value);
|
||||||
}
|
}
|
||||||
// Dummy drivers
|
// Dummy drivers
|
||||||
|
@ -223,9 +252,22 @@ uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t valu
|
||||||
case GBA_SIO_JOYBUS:
|
case GBA_SIO_JOYBUS:
|
||||||
switch (address) {
|
switch (address) {
|
||||||
case GBA_REG_JOYCNT:
|
case GBA_REG_JOYCNT:
|
||||||
|
mLOG(GBA_SIO, DEBUG, "JOY write: CNT <- %04X", value);
|
||||||
return (value & 0x0040) | (sio->p->memory.io[GBA_REG(JOYCNT)] & ~(value & 0x7) & ~0x0040);
|
return (value & 0x0040) | (sio->p->memory.io[GBA_REG(JOYCNT)] & ~(value & 0x7) & ~0x0040);
|
||||||
case GBA_REG_JOYSTAT:
|
case GBA_REG_JOYSTAT:
|
||||||
|
mLOG(GBA_SIO, DEBUG, "JOY write: STAT <- %04X", value);
|
||||||
return (value & 0x0030) | (sio->p->memory.io[GBA_REG(JOYSTAT)] & ~0x30);
|
return (value & 0x0030) | (sio->p->memory.io[GBA_REG(JOYSTAT)] & ~0x30);
|
||||||
|
case GBA_REG_JOY_TRANS_LO:
|
||||||
|
mLOG(GBA_SIO, DEBUG, "JOY write: TRANS_LO <- %04X", value);
|
||||||
|
break;
|
||||||
|
case GBA_REG_JOY_TRANS_HI:
|
||||||
|
mLOG(GBA_SIO, DEBUG, "JOY write: TRANS_HI <- %04X", value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mLOG(GBA_SIO, DEBUG, "JOY write: Unknown reg %03X <- %04X", address, value);
|
||||||
|
break;
|
||||||
|
case GBA_REG_RCNT:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -234,3 +276,53 @@ uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t valu
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand command, uint8_t* data) {
|
||||||
|
switch (command) {
|
||||||
|
case JOY_RESET:
|
||||||
|
sio->p->p->memory.io[GBA_REG(JOYCNT)] |= JOYCNT_RESET;
|
||||||
|
if (sio->p->p->memory.io[GBA_REG(JOYCNT)] & 0x40) {
|
||||||
|
GBARaiseIRQ(sio->p->p, GBA_IRQ_SIO, 0);
|
||||||
|
}
|
||||||
|
// Fall through
|
||||||
|
case JOY_POLL:
|
||||||
|
data[0] = 0x00;
|
||||||
|
data[1] = 0x04;
|
||||||
|
data[2] = sio->p->p->memory.io[GBA_REG(JOYSTAT)];
|
||||||
|
|
||||||
|
mLOG(GBA_SIO, DEBUG, "JOY %s: %02X (%02X)", command == JOY_POLL ? "poll" : "reset", data[2], sio->p->p->memory.io[GBA_REG(JOYCNT)]);
|
||||||
|
return 3;
|
||||||
|
case JOY_RECV:
|
||||||
|
sio->p->p->memory.io[GBA_REG(JOYCNT)] |= JOYCNT_RECV;
|
||||||
|
sio->p->p->memory.io[GBA_REG(JOYSTAT)] |= JOYSTAT_RECV;
|
||||||
|
|
||||||
|
sio->p->p->memory.io[GBA_REG(JOY_RECV_LO)] = data[0] | (data[1] << 8);
|
||||||
|
sio->p->p->memory.io[GBA_REG(JOY_RECV_HI)] = data[2] | (data[3] << 8);
|
||||||
|
|
||||||
|
data[0] = sio->p->p->memory.io[GBA_REG(JOYSTAT)];
|
||||||
|
|
||||||
|
mLOG(GBA_SIO, DEBUG, "JOY recv: %02X (%02X)", data[0], sio->p->p->memory.io[GBA_REG(JOYCNT)]);
|
||||||
|
|
||||||
|
if (sio->p->p->memory.io[GBA_REG(JOYCNT)] & 0x40) {
|
||||||
|
GBARaiseIRQ(sio->p->p, GBA_IRQ_SIO, 0);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
case JOY_TRANS:
|
||||||
|
data[0] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_LO)];
|
||||||
|
data[1] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_LO)] >> 8;
|
||||||
|
data[2] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_HI)];
|
||||||
|
data[3] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_HI)] >> 8;
|
||||||
|
data[4] = sio->p->p->memory.io[GBA_REG(JOYSTAT)];
|
||||||
|
|
||||||
|
sio->p->p->memory.io[GBA_REG(JOYCNT)] |= JOYCNT_TRANS;
|
||||||
|
sio->p->p->memory.io[GBA_REG(JOYSTAT)] &= ~JOYSTAT_TRANS;
|
||||||
|
|
||||||
|
mLOG(GBA_SIO, DEBUG, "JOY trans: %02X%02X%02X%02X:%02X (%02X)", data[0], data[1], data[2], data[3], data[4], sio->p->p->memory.io[GBA_REG(JOYCNT)]);
|
||||||
|
|
||||||
|
if (sio->p->p->memory.io[GBA_REG(JOYCNT)] & 0x40) {
|
||||||
|
GBARaiseIRQ(sio->p->p, GBA_IRQ_SIO, 0);
|
||||||
|
}
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -25,16 +25,22 @@ enum {
|
||||||
static bool GBASIODolphinInit(struct GBASIODriver* driver);
|
static bool GBASIODolphinInit(struct GBASIODriver* driver);
|
||||||
static bool GBASIODolphinLoad(struct GBASIODriver* driver);
|
static bool GBASIODolphinLoad(struct GBASIODriver* driver);
|
||||||
static bool GBASIODolphinUnload(struct GBASIODriver* driver);
|
static bool GBASIODolphinUnload(struct GBASIODriver* driver);
|
||||||
|
static bool GBASIODolphinHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode);
|
||||||
|
static int GBASIODolphinConnectedDevices(struct GBASIODriver* driver);
|
||||||
static void GBASIODolphinProcessEvents(struct mTiming* timing, void* context, uint32_t cyclesLate);
|
static void GBASIODolphinProcessEvents(struct mTiming* timing, void* context, uint32_t cyclesLate);
|
||||||
|
|
||||||
static int32_t _processCommand(struct GBASIODolphin* dol, uint32_t cyclesLate);
|
static int32_t _processCommand(struct GBASIODolphin* dol, uint32_t cyclesLate);
|
||||||
static void _flush(struct GBASIODolphin* dol);
|
static void _flush(struct GBASIODolphin* dol);
|
||||||
|
|
||||||
void GBASIODolphinCreate(struct GBASIODolphin* dol) {
|
void GBASIODolphinCreate(struct GBASIODolphin* dol) {
|
||||||
GBASIOJOYCreate(&dol->d);
|
|
||||||
dol->d.init = GBASIODolphinInit;
|
dol->d.init = GBASIODolphinInit;
|
||||||
dol->d.load = GBASIODolphinLoad;
|
dol->d.load = GBASIODolphinLoad;
|
||||||
dol->d.unload = GBASIODolphinUnload;
|
dol->d.unload = GBASIODolphinUnload;
|
||||||
|
dol->d.writeRegister = NULL;
|
||||||
|
dol->d.setMode = NULL;
|
||||||
|
dol->d.handlesMode = GBASIODolphinHandlesMode;
|
||||||
|
dol->d.connectedDevices = GBASIODolphinConnectedDevices;
|
||||||
|
dol->d.deviceId = NULL;
|
||||||
dol->event.context = dol;
|
dol->event.context = dol;
|
||||||
dol->event.name = "GB SIO Lockstep";
|
dol->event.name = "GB SIO Lockstep";
|
||||||
dol->event.callback = GBASIODolphinProcessEvents;
|
dol->event.callback = GBASIODolphinProcessEvents;
|
||||||
|
@ -116,6 +122,16 @@ static bool GBASIODolphinUnload(struct GBASIODriver* driver) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool GBASIODolphinHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode) {
|
||||||
|
UNUSED(driver);
|
||||||
|
return mode == GBA_SIO_JOYBUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GBASIODolphinConnectedDevices(struct GBASIODriver* driver) {
|
||||||
|
UNUSED(driver);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void GBASIODolphinProcessEvents(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
void GBASIODolphinProcessEvents(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||||
struct GBASIODolphin* dol = context;
|
struct GBASIODolphin* dol = context;
|
||||||
if (SOCKET_FAILED(dol->data)) {
|
if (SOCKET_FAILED(dol->data)) {
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
/* Copyright (c) 2013-2017 Jeffrey Pfau
|
|
||||||
*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
#include <mgba/internal/gba/sio.h>
|
|
||||||
|
|
||||||
#include <mgba/internal/gba/gba.h>
|
|
||||||
#include <mgba/internal/gba/io.h>
|
|
||||||
|
|
||||||
static uint16_t GBASIOJOYWriteRegister(struct GBASIODriver* sio, uint32_t address, uint16_t value);
|
|
||||||
static bool GBASIOJOYHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode);
|
|
||||||
static int GBASIOJOYConnectedDevices(struct GBASIODriver* driver);
|
|
||||||
|
|
||||||
void GBASIOJOYCreate(struct GBASIODriver* sio) {
|
|
||||||
sio->init = NULL;
|
|
||||||
sio->deinit = NULL;
|
|
||||||
sio->load = NULL;
|
|
||||||
sio->unload = NULL;
|
|
||||||
sio->writeRegister = GBASIOJOYWriteRegister;
|
|
||||||
sio->setMode = NULL;
|
|
||||||
sio->handlesMode = GBASIOJOYHandlesMode;
|
|
||||||
sio->connectedDevices = GBASIOJOYConnectedDevices;
|
|
||||||
sio->deviceId = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t GBASIOJOYWriteRegister(struct GBASIODriver* sio, uint32_t address, uint16_t value) {
|
|
||||||
switch (address) {
|
|
||||||
case GBA_REG_JOYCNT:
|
|
||||||
mLOG(GBA_SIO, DEBUG, "JOY write: CNT <- %04X", value);
|
|
||||||
return (value & 0x0040) | (sio->p->p->memory.io[GBA_REG(JOYCNT)] & ~(value & 0x7) & ~0x0040);
|
|
||||||
case GBA_REG_JOYSTAT:
|
|
||||||
mLOG(GBA_SIO, DEBUG, "JOY write: STAT <- %04X", value);
|
|
||||||
return (value & 0x0030) | (sio->p->p->memory.io[GBA_REG(JOYSTAT)] & ~0x30);
|
|
||||||
case GBA_REG_JOY_TRANS_LO:
|
|
||||||
mLOG(GBA_SIO, DEBUG, "JOY write: TRANS_LO <- %04X", value);
|
|
||||||
break;
|
|
||||||
case GBA_REG_JOY_TRANS_HI:
|
|
||||||
mLOG(GBA_SIO, DEBUG, "JOY write: TRANS_HI <- %04X", value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mLOG(GBA_SIO, DEBUG, "JOY write: Unknown reg %03X <- %04X", address, value);
|
|
||||||
// Fall through
|
|
||||||
case GBA_REG_RCNT:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GBASIOJOYHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode) {
|
|
||||||
UNUSED(driver);
|
|
||||||
return mode == GBA_SIO_JOYBUS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int GBASIOJOYConnectedDevices(struct GBASIODriver* driver) {
|
|
||||||
UNUSED(driver);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand command, uint8_t* data) {
|
|
||||||
switch (command) {
|
|
||||||
case JOY_RESET:
|
|
||||||
sio->p->p->memory.io[GBA_REG(JOYCNT)] |= JOYCNT_RESET;
|
|
||||||
if (sio->p->p->memory.io[GBA_REG(JOYCNT)] & 0x40) {
|
|
||||||
GBARaiseIRQ(sio->p->p, GBA_IRQ_SIO, 0);
|
|
||||||
}
|
|
||||||
// Fall through
|
|
||||||
case JOY_POLL:
|
|
||||||
data[0] = 0x00;
|
|
||||||
data[1] = 0x04;
|
|
||||||
data[2] = sio->p->p->memory.io[GBA_REG(JOYSTAT)];
|
|
||||||
|
|
||||||
mLOG(GBA_SIO, DEBUG, "JOY %s: %02X (%02X)", command == JOY_POLL ? "poll" : "reset", data[2], sio->p->p->memory.io[GBA_REG(JOYCNT)]);
|
|
||||||
return 3;
|
|
||||||
case JOY_RECV:
|
|
||||||
sio->p->p->memory.io[GBA_REG(JOYCNT)] |= JOYCNT_RECV;
|
|
||||||
sio->p->p->memory.io[GBA_REG(JOYSTAT)] |= JOYSTAT_RECV;
|
|
||||||
|
|
||||||
sio->p->p->memory.io[GBA_REG(JOY_RECV_LO)] = data[0] | (data[1] << 8);
|
|
||||||
sio->p->p->memory.io[GBA_REG(JOY_RECV_HI)] = data[2] | (data[3] << 8);
|
|
||||||
|
|
||||||
data[0] = sio->p->p->memory.io[GBA_REG(JOYSTAT)];
|
|
||||||
|
|
||||||
mLOG(GBA_SIO, DEBUG, "JOY recv: %02X (%02X)", data[0], sio->p->p->memory.io[GBA_REG(JOYCNT)]);
|
|
||||||
|
|
||||||
if (sio->p->p->memory.io[GBA_REG(JOYCNT)] & 0x40) {
|
|
||||||
GBARaiseIRQ(sio->p->p, GBA_IRQ_SIO, 0);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
case JOY_TRANS:
|
|
||||||
data[0] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_LO)];
|
|
||||||
data[1] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_LO)] >> 8;
|
|
||||||
data[2] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_HI)];
|
|
||||||
data[3] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_HI)] >> 8;
|
|
||||||
data[4] = sio->p->p->memory.io[GBA_REG(JOYSTAT)];
|
|
||||||
|
|
||||||
sio->p->p->memory.io[GBA_REG(JOYCNT)] |= JOYCNT_TRANS;
|
|
||||||
sio->p->p->memory.io[GBA_REG(JOYSTAT)] &= ~JOYSTAT_TRANS;
|
|
||||||
|
|
||||||
mLOG(GBA_SIO, DEBUG, "JOY trans: %02X%02X%02X%02X:%02X (%02X)", data[0], data[1], data[2], data[3], data[4], sio->p->p->memory.io[GBA_REG(JOYCNT)]);
|
|
||||||
|
|
||||||
if (sio->p->p->memory.io[GBA_REG(JOYCNT)] & 0x40) {
|
|
||||||
GBARaiseIRQ(sio->p->p, GBA_IRQ_SIO, 0);
|
|
||||||
}
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -215,7 +215,7 @@ static bool GBASIOLockstepNodeHandlesMode(struct GBASIODriver* driver, enum GBAS
|
||||||
|
|
||||||
static int GBASIOLockstepNodeConnectedDevices(struct GBASIODriver* driver) {
|
static int GBASIOLockstepNodeConnectedDevices(struct GBASIODriver* driver) {
|
||||||
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
|
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
|
||||||
int attached = 0;
|
int attached = 1;
|
||||||
|
|
||||||
switch (node->mode) {
|
switch (node->mode) {
|
||||||
case GBA_SIO_NORMAL_8:
|
case GBA_SIO_NORMAL_8:
|
||||||
|
|
Loading…
Reference in New Issue