all repos — mgba @ c6ca0d25c01f1b65a2d90636e5b550eee27a545e

mGBA Game Boy Advance Emulator

GBA SIO: Fix Normal mode being totally broken (fixes #1800)
Vicki Pfau vi@endrift.com
Mon, 03 Aug 2020 17:55:44 -0700
commit

c6ca0d25c01f1b65a2d90636e5b550eee27a545e

parent

c6fb561465046bd9eafc8bccf11cd2f1c8bb34ab

4 files changed, 40 insertions(+), 23 deletions(-)

jump to
M CHANGESCHANGES

@@ -27,6 +27,7 @@ - GBA Memory: Improve gamepak prefetch timing

- GBA Memory: Stall on VRAM access in mode 2 (fixes mgba.io/i/190) - GBA Savedata: Fix potential corruption when loading a 1Mbit flash save - GBA SIO: Fix copying Normal mode transfer values + - GBA SIO: Fix Normal mode being totally broken (fixes mgba.io/i/1800) - GBA Video: Latch scanline at end of Hblank (fixes mgba.io/i/1319) - GBA Video: Fix Hblank timing - GBA Video: Fix invalid read in mode 4 mosaic
M src/gba/io.csrc/gba/io.c

@@ -527,6 +527,8 @@ case REG_JOY_TRANS_LO:

case REG_JOY_TRANS_HI: gba->memory.io[REG_JOYSTAT >> 1] |= JOYSTAT_TRANS_BIT; // Fall through + case REG_SIODATA32_LO: + case REG_SIODATA32_HI: case REG_SIOMLT_SEND: case REG_JOYCNT: case REG_JOYSTAT:
M src/gba/sio/lockstep.csrc/gba/sio/lockstep.c

@@ -30,6 +30,7 @@ lockstep->multiRecv[1] = 0xFFFF;

lockstep->multiRecv[2] = 0xFFFF; lockstep->multiRecv[3] = 0xFFFF; lockstep->attachedMulti = 0; + lockstep->attachedNormal = 0; } void GBASIOLockstepNodeCreate(struct GBASIOLockstepNode* node) {

@@ -44,11 +45,14 @@ bool GBASIOLockstepAttachNode(struct GBASIOLockstep* lockstep, struct GBASIOLockstepNode* node) {

if (lockstep->d.attached == MAX_GBAS) { return false; } + mLockstepLock(&lockstep->d); lockstep->players[lockstep->d.attached] = node; node->p = lockstep; node->id = lockstep->d.attached; + node->normalSO = true; node->transferFinished = true; ++lockstep->d.attached; + mLockstepUnlock(&lockstep->d); return true; }

@@ -56,6 +60,7 @@ void GBASIOLockstepDetachNode(struct GBASIOLockstep* lockstep, struct GBASIOLockstepNode* node) {

if (lockstep->d.attached == 0) { return; } + mLockstepLock(&lockstep->d); int i; for (i = 0; i < lockstep->d.attached; ++i) { if (lockstep->players[i] != node) {

@@ -66,8 +71,10 @@ lockstep->players[i - 1] = lockstep->players[i];

lockstep->players[i - 1]->id = i - 1; } --lockstep->d.attached; + lockstep->players[lockstep->d.attached] = NULL; break; } + mLockstepUnlock(&lockstep->d); } bool GBASIOLockstepNodeInit(struct GBASIODriver* driver) {

@@ -107,6 +114,7 @@ node->d.p->siocnt = GBASIOMultiplayerFillSlave(node->d.p->siocnt);

} break; case SIO_NORMAL_32: + ATOMIC_ADD(node->p->attachedNormal, 1); node->d.writeRegister = GBASIOLockstepNodeNormalWriteRegister; break; default:

@@ -132,6 +140,9 @@ switch (node->mode) {

case SIO_MULTI: ATOMIC_SUB(node->p->attachedMulti, 1); break; + case SIO_NORMAL_32: + ATOMIC_SUB(node->p->attachedNormal, 1); + break; default: break; }

@@ -148,11 +159,6 @@ }

node->p->d.unload(&node->p->d, node->id); - node->p->multiRecv[0] = 0xFFFF; - node->p->multiRecv[1] = 0xFFFF; - node->p->multiRecv[2] = 0xFFFF; - node->p->multiRecv[3] = 0xFFFF; - _finishTransfer(node); if (!node->id) {

@@ -173,7 +179,7 @@

mLockstepLock(&node->p->d); if (address == REG_SIOCNT) { - mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04x", node->id, value); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04X", node->id, value); enum mLockstepPhase transferActive; ATOMIC_LOAD(transferActive, node->p->d.transferActive);

@@ -200,7 +206,9 @@ }

value &= 0xFF83; value |= driver->p->siocnt & 0x00FC; } else if (address == REG_SIOMLT_SEND) { - mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOMLT_SEND <- %04x", node->id, value); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOMLT_SEND <- %04X", node->id, value); + } else { + mLOG(GBA_SIO, STUB, "Lockstep %i: Unknown reg %03X <- %04X", node->id, address, value); } mLockstepUnlock(&node->p->d);

@@ -246,7 +254,7 @@ sio->siocnt = GBASIONormalClearStart(sio->siocnt);

if (node->id) { sio->siocnt = GBASIONormalSetSi(sio->siocnt, GBASIONormalGetIdleSo(node->p->players[node->id - 1]->d.p->siocnt)); node->d.p->p->memory.io[REG_SIODATA32_LO >> 1] = node->p->normalRecv[node->id - 1]; - node->d.p->p->memory.io[REG_SIODATA32_HI >> 1] |= node->p->normalRecv[node->id - 1] >> 16; + node->d.p->p->memory.io[REG_SIODATA32_HI >> 1] = node->p->normalRecv[node->id - 1] >> 16; } else { node->d.p->p->memory.io[REG_SIODATA32_LO >> 1] = 0xFFFF; node->d.p->p->memory.io[REG_SIODATA32_HI >> 1] = 0xFFFF;

@@ -303,8 +311,8 @@ node->p->normalRecv[0] = node->d.p->p->memory.io[REG_SIODATA8 >> 1] & 0xFF;

break; case SIO_NORMAL_32: node->p->multiRecv[0] = 0xFFFF; - mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_LO <- %04x", node->id, node->d.p->p->memory.io[REG_SIODATA32_LO >> 1]); - mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04x", node->id, node->d.p->p->memory.io[REG_SIODATA32_HI >> 1]); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_LO <- %04X", node->id, node->d.p->p->memory.io[REG_SIODATA32_LO >> 1]); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04X", node->id, node->d.p->p->memory.io[REG_SIODATA32_HI >> 1]); node->p->normalRecv[0] = node->d.p->p->memory.io[REG_SIODATA32_LO >> 1]; node->p->normalRecv[0] |= node->d.p->p->memory.io[REG_SIODATA32_HI >> 1] << 16; break;

@@ -473,27 +481,31 @@

mLockstepLock(&node->p->d); if (address == REG_SIOCNT) { - mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04x", node->id, value); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04X", node->id, value); value &= 0xFF8B; if (!node->id) { - value = GBASIONormalFillSi(value); + value = GBASIONormalClearSi(value); } - if (value & 0x0080 && !node->id) { - // Internal shift clock - if (value & 1) { - ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING); - } - // Frequency - if (value & 2) { - node->p->d.transferCycles = GBA_ARM7TDMI_FREQUENCY / 1024; + if (value & 0x0080) { + if (!node->id) { + // Internal shift clock + if (value & 1) { + ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING); + } + // Frequency + if (value & 2) { + node->p->d.transferCycles = GBA_ARM7TDMI_FREQUENCY / 1024; + } else { + node->p->d.transferCycles = GBA_ARM7TDMI_FREQUENCY / 8192; + } } else { - node->p->d.transferCycles = GBA_ARM7TDMI_FREQUENCY / 8192; + } } } else if (address == REG_SIODATA32_LO) { - mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_LO <- %04x", node->id, value); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_LO <- %04X", node->id, value); } else if (address == REG_SIODATA32_HI) { - mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04x", node->id, value); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04X", node->id, value); } mLockstepUnlock(&node->p->d);
M src/platform/qt/MultiplayerController.cppsrc/platform/qt/MultiplayerController.cpp

@@ -221,6 +221,7 @@ GBASIOLockstepAttachNode(&m_gbaLockstep, node);

m_players.append({controller, node}); GBASIOSetDriver(&gba->sio, &node->d, SIO_MULTI); + GBASIOSetDriver(&gba->sio, &node->d, SIO_NORMAL_32); emit gameAttached(); return true;

@@ -267,6 +268,7 @@ case PLATFORM_GBA: {

GBA* gba = static_cast<GBA*>(thread->core->board); GBASIOLockstepNode* node = reinterpret_cast<GBASIOLockstepNode*>(gba->sio.drivers.multiplayer); GBASIOSetDriver(&gba->sio, nullptr, SIO_MULTI); + GBASIOSetDriver(&gba->sio, nullptr, SIO_NORMAL_32); if (node) { GBASIOLockstepDetachNode(&m_gbaLockstep, node); delete node;