From a51cb3f92102f74cefb2bcf01097006d141e30d4 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 3 Jul 2023 23:14:57 -0700 Subject: [PATCH] GBA SIO: Fix normal mode SI/SO semantics (fixes #2925) --- CHANGES | 1 + src/gba/sio/lockstep.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 11bf6d60d..103400ab7 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,7 @@ Emulation fixes: - GBA Audio: Fix sample timing drifting when changing sample interval - GBA Audio: Fix initial channel 3 wave RAM (fixes mgba.io/i/2947) - GBA BIOS: Fix clobbering registers with word-sized CpuSet + - GBA SIO: Fix normal mode SI/SO semantics (fixes mgba.io/i/2925) Other fixes: - mGUI: Fix cases where an older save state screenshot would be shown (fixes mgba.io/i/2183) Misc: diff --git a/src/gba/sio/lockstep.c b/src/gba/sio/lockstep.c index 8e641c539..10f1d7f00 100644 --- a/src/gba/sio/lockstep.c +++ b/src/gba/sio/lockstep.c @@ -127,10 +127,10 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) { break; case SIO_NORMAL_8: case SIO_NORMAL_32: - if (ATOMIC_ADD(node->p->attachedNormal, 1) > node->id + 1 && node->id < 3) { - node->d.p->siocnt = GBASIONormalSetSi(node->d.p->siocnt, GBASIONormalGetIdleSo(node->p->players[node->id + 1]->d.p->siocnt)); + if (ATOMIC_ADD(node->p->attachedNormal, 1) > node->id + 1 && node->id > 0) { + node->d.p->siocnt = GBASIONormalSetSi(node->d.p->siocnt, GBASIONormalGetIdleSo(node->p->players[node->id - 1]->d.p->siocnt)); } else { - node->d.p->siocnt = GBASIONormalFillSi(node->d.p->siocnt); + node->d.p->siocnt = GBASIONormalClearSi(node->d.p->siocnt); } node->d.writeRegister = GBASIOLockstepNodeNormalWriteRegister; break; @@ -514,20 +514,20 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive int attached; ATOMIC_LOAD(attached, node->p->attachedNormal); value &= 0xFF8B; - if (node->id < 3 && attached > node->id + 1) { - value = GBASIONormalSetSi(value, GBASIONormalGetIdleSo(node->p->players[node->id + 1]->d.p->siocnt)); + if (node->id > 0) { + value = GBASIONormalSetSi(value, GBASIONormalGetIdleSo(node->p->players[node->id - 1]->d.p->siocnt)); } else { - value = GBASIONormalFillSi(value); + value = GBASIONormalClearSi(value); } enum mLockstepPhase transferActive; ATOMIC_LOAD(transferActive, node->p->d.transferActive); - if (node->id > 0 && transferActive == TRANSFER_IDLE) { + if (node->id < 3 && attached > node->id + 1 && transferActive == TRANSFER_IDLE) { int try; for (try = 0; try < 3; ++try) { - GBASIONormal parentSiocnt; - ATOMIC_LOAD(parentSiocnt, node->p->players[node->id - 1]->d.p->siocnt); - if (ATOMIC_CMPXCHG(node->p->players[node->id - 1]->d.p->siocnt, parentSiocnt, GBASIONormalSetSi(parentSiocnt, GBASIONormalGetIdleSo(value)))) { + GBASIONormal nextSiocnct; + ATOMIC_LOAD(nextSiocnct, node->p->players[node->id + 1]->d.p->siocnt); + if (ATOMIC_CMPXCHG(node->p->players[node->id + 1]->d.p->siocnt, nextSiocnct, GBASIONormalSetSi(nextSiocnct, GBASIONormalGetIdleSo(value)))) { break; } }