mirror of https://github.com/mgba-emu/mgba.git
GBA SIO: Fix Normal mode being totally broken (fixes #1800)
This commit is contained in:
parent
c6fb561465
commit
c6ca0d25c0
1
CHANGES
1
CHANGES
|
@ -27,6 +27,7 @@ Emulation fixes:
|
|||
- 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
|
||||
|
|
|
@ -527,6 +527,8 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
|
|||
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:
|
||||
|
|
|
@ -30,6 +30,7 @@ void GBASIOLockstepInit(struct GBASIOLockstep* lockstep) {
|
|||
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 GBASIOLock
|
|||
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 GBASIOLock
|
|||
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 @@ void GBASIOLockstepDetachNode(struct GBASIOLockstep* lockstep, struct GBASIOLock
|
|||
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 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) {
|
|||
}
|
||||
break;
|
||||
case SIO_NORMAL_32:
|
||||
ATOMIC_ADD(node->p->attachedNormal, 1);
|
||||
node->d.writeRegister = GBASIOLockstepNodeNormalWriteRegister;
|
||||
break;
|
||||
default:
|
||||
|
@ -132,6 +140,9 @@ bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver) {
|
|||
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 @@ bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver) {
|
|||
|
||||
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 @@ static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver
|
|||
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 @@ static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver
|
|||
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 @@ static void _finishTransfer(struct GBASIOLockstepNode* node) {
|
|||
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 @@ static int32_t _masterUpdate(struct GBASIOLockstepNode* node) {
|
|||
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 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive
|
|||
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);
|
||||
|
|
|
@ -221,6 +221,7 @@ bool MultiplayerController::attachGame(CoreController* controller) {
|
|||
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 @@ void MultiplayerController::detachGame(CoreController* controller) {
|
|||
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;
|
||||
|
|
Loading…
Reference in New Issue