GBA SIO: Fix normal mode SI/SO semantics (fixes #2925)

This commit is contained in:
Vicki Pfau 2023-07-03 23:14:57 -07:00
parent 1acb7dfa9e
commit a51cb3f921
2 changed files with 11 additions and 10 deletions

View File

@ -8,6 +8,7 @@ Emulation fixes:
- GBA Audio: Fix sample timing drifting when changing sample interval - GBA Audio: Fix sample timing drifting when changing sample interval
- GBA Audio: Fix initial channel 3 wave RAM (fixes mgba.io/i/2947) - GBA Audio: Fix initial channel 3 wave RAM (fixes mgba.io/i/2947)
- GBA BIOS: Fix clobbering registers with word-sized CpuSet - GBA BIOS: Fix clobbering registers with word-sized CpuSet
- GBA SIO: Fix normal mode SI/SO semantics (fixes mgba.io/i/2925)
Other fixes: Other fixes:
- mGUI: Fix cases where an older save state screenshot would be shown (fixes mgba.io/i/2183) - mGUI: Fix cases where an older save state screenshot would be shown (fixes mgba.io/i/2183)
Misc: Misc:

View File

@ -127,10 +127,10 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) {
break; break;
case SIO_NORMAL_8: case SIO_NORMAL_8:
case SIO_NORMAL_32: case SIO_NORMAL_32:
if (ATOMIC_ADD(node->p->attachedNormal, 1) > node->id + 1 && node->id < 3) { 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)); node->d.p->siocnt = GBASIONormalSetSi(node->d.p->siocnt, GBASIONormalGetIdleSo(node->p->players[node->id - 1]->d.p->siocnt));
} else { } else {
node->d.p->siocnt = GBASIONormalFillSi(node->d.p->siocnt); node->d.p->siocnt = GBASIONormalClearSi(node->d.p->siocnt);
} }
node->d.writeRegister = GBASIOLockstepNodeNormalWriteRegister; node->d.writeRegister = GBASIOLockstepNodeNormalWriteRegister;
break; break;
@ -514,20 +514,20 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive
int attached; int attached;
ATOMIC_LOAD(attached, node->p->attachedNormal); ATOMIC_LOAD(attached, node->p->attachedNormal);
value &= 0xFF8B; value &= 0xFF8B;
if (node->id < 3 && attached > node->id + 1) { if (node->id > 0) {
value = GBASIONormalSetSi(value, GBASIONormalGetIdleSo(node->p->players[node->id + 1]->d.p->siocnt)); value = GBASIONormalSetSi(value, GBASIONormalGetIdleSo(node->p->players[node->id - 1]->d.p->siocnt));
} else { } else {
value = GBASIONormalFillSi(value); value = GBASIONormalClearSi(value);
} }
enum mLockstepPhase transferActive; enum mLockstepPhase transferActive;
ATOMIC_LOAD(transferActive, node->p->d.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; int try;
for (try = 0; try < 3; ++try) { for (try = 0; try < 3; ++try) {
GBASIONormal parentSiocnt; GBASIONormal nextSiocnct;
ATOMIC_LOAD(parentSiocnt, node->p->players[node->id - 1]->d.p->siocnt); ATOMIC_LOAD(nextSiocnct, 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)))) { if (ATOMIC_CMPXCHG(node->p->players[node->id + 1]->d.p->siocnt, nextSiocnct, GBASIONormalSetSi(nextSiocnct, GBASIONormalGetIdleSo(value)))) {
break; break;
} }
} }