diff --git a/include/mgba/gba/interface.h b/include/mgba/gba/interface.h index 6b663b4a7..c2a4fb5d2 100644 --- a/include/mgba/gba/interface.h +++ b/include/mgba/gba/interface.h @@ -120,8 +120,6 @@ struct GBASIODriver { uint16_t (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value); }; -void GBASIOJOYCreate(struct GBASIODriver* sio); - enum GBASIOBattleChipGateFlavor { GBA_FLAVOR_BATTLECHIP_GATE = 4, GBA_FLAVOR_PROGRESS_GATE = 5, diff --git a/src/gba/CMakeLists.txt b/src/gba/CMakeLists.txt index 933ba3fac..01a968a41 100644 --- a/src/gba/CMakeLists.txt +++ b/src/gba/CMakeLists.txt @@ -31,7 +31,6 @@ set(SOURCE_FILES sharkport.c sio.c sio/gbp.c - sio/joybus.c timer.c video.c) diff --git a/src/gba/sio.c b/src/gba/sio.c index ae1132dfe..27702dfbf 100644 --- a/src/gba/sio.c +++ b/src/gba/sio.c @@ -186,7 +186,32 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) { sio->siocnt = value & 0x3000; _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); } else { // Dummy drivers @@ -203,8 +228,7 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) { } break; case GBA_SIO_MULTI: - value &= 0xFF83; - value |= 0xC; + value = GBASIOMultiplayerFillReady(value); break; default: // 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) { - 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); } // Dummy drivers @@ -223,9 +252,22 @@ uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t valu case GBA_SIO_JOYBUS: switch (address) { 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); case GBA_REG_JOYSTAT: + mLOG(GBA_SIO, DEBUG, "JOY write: STAT <- %04X", value); 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; default: @@ -234,3 +276,53 @@ uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t valu } 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; +} diff --git a/src/gba/sio/dolphin.c b/src/gba/sio/dolphin.c index 896d17d3e..badbd05f7 100644 --- a/src/gba/sio/dolphin.c +++ b/src/gba/sio/dolphin.c @@ -25,16 +25,22 @@ enum { static bool GBASIODolphinInit(struct GBASIODriver* driver); static bool GBASIODolphinLoad(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 int32_t _processCommand(struct GBASIODolphin* dol, uint32_t cyclesLate); static void _flush(struct GBASIODolphin* dol); void GBASIODolphinCreate(struct GBASIODolphin* dol) { - GBASIOJOYCreate(&dol->d); dol->d.init = GBASIODolphinInit; dol->d.load = GBASIODolphinLoad; 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.name = "GB SIO Lockstep"; dol->event.callback = GBASIODolphinProcessEvents; @@ -116,6 +122,16 @@ static bool GBASIODolphinUnload(struct GBASIODriver* driver) { 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) { struct GBASIODolphin* dol = context; if (SOCKET_FAILED(dol->data)) { diff --git a/src/gba/sio/joybus.c b/src/gba/sio/joybus.c deleted file mode 100644 index f1e86d6ed..000000000 --- a/src/gba/sio/joybus.c +++ /dev/null @@ -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 - -#include -#include - -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; -} diff --git a/src/gba/sio/lockstep.c b/src/gba/sio/lockstep.c index 9ac1e7174..edd170748 100644 --- a/src/gba/sio/lockstep.c +++ b/src/gba/sio/lockstep.c @@ -215,7 +215,7 @@ static bool GBASIOLockstepNodeHandlesMode(struct GBASIODriver* driver, enum GBAS static int GBASIOLockstepNodeConnectedDevices(struct GBASIODriver* driver) { struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; - int attached = 0; + int attached = 1; switch (node->mode) { case GBA_SIO_NORMAL_8: