GB SIO: Further fix bidirectional transfer starting

This commit is contained in:
Vicki Pfau 2022-11-28 00:59:36 -08:00
parent 9b2d4bc68e
commit 6f08b740f9
2 changed files with 24 additions and 11 deletions

View File

@ -4,6 +4,7 @@ Features:
- Debugger: Add range watchpoints - Debugger: Add range watchpoints
Emulation fixes: Emulation fixes:
- GB Serialize: Don't write BGP/OBP when loading SCGB state (fixes mgba.io/i/2694) - GB Serialize: Don't write BGP/OBP when loading SCGB state (fixes mgba.io/i/2694)
- GB SIO: Further fix bidirectional transfer starting
- GBA: Fix resetting key IRQ state (fixes mgba.io/i/2716) - GBA: Fix resetting key IRQ state (fixes mgba.io/i/2716)
- GBA Video: Ignore disabled backgrounds as OBJ blend target (fixes mgba.io/i/2489) - GBA Video: Ignore disabled backgrounds as OBJ blend target (fixes mgba.io/i/2489)
- GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722) - GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722)

View File

@ -157,7 +157,7 @@ static int32_t _masterUpdate(struct GBSIOLockstepNode* node) {
} }
} }
// Tell the other GBs they can continue up to where we were // Tell the other GBs they can continue up to where we were
node->p->d.addCycles(&node->p->d, node->id, node->eventDiff); node->p->d.addCycles(&node->p->d, 0, node->eventDiff);
#ifndef NDEBUG #ifndef NDEBUG
node->phase = node->p->d.transferActive; node->phase = node->p->d.transferActive;
#endif #endif
@ -169,26 +169,28 @@ static int32_t _masterUpdate(struct GBSIOLockstepNode* node) {
static uint32_t _slaveUpdate(struct GBSIOLockstepNode* node) { static uint32_t _slaveUpdate(struct GBSIOLockstepNode* node) {
enum mLockstepPhase transferActive; enum mLockstepPhase transferActive;
int id;
ATOMIC_LOAD(transferActive, node->p->d.transferActive); ATOMIC_LOAD(transferActive, node->p->d.transferActive);
ATOMIC_LOAD(id, node->id);
bool signal = false; bool signal = false;
switch (transferActive) { switch (transferActive) {
case TRANSFER_IDLE: case TRANSFER_IDLE:
node->p->d.addCycles(&node->p->d, node->id, LOCKSTEP_INCREMENT); node->p->d.addCycles(&node->p->d, id, LOCKSTEP_INCREMENT);
break; break;
case TRANSFER_STARTING: case TRANSFER_STARTING:
case TRANSFER_FINISHING: case TRANSFER_FINISHING:
break; break;
case TRANSFER_STARTED: case TRANSFER_STARTED:
if (node->p->d.unusedCycles(&node->p->d, node->id) > node->eventDiff) { if (node->p->d.unusedCycles(&node->p->d, id) > node->eventDiff) {
break; break;
} }
node->transferFinished = false; node->transferFinished = false;
signal = true; signal = true;
break; break;
case TRANSFER_FINISHED: case TRANSFER_FINISHED:
if (node->p->d.unusedCycles(&node->p->d, node->id) > node->eventDiff) { if (node->p->d.unusedCycles(&node->p->d, id) > node->eventDiff) {
break; break;
} }
_finishTransfer(node); _finishTransfer(node);
@ -199,7 +201,7 @@ static uint32_t _slaveUpdate(struct GBSIOLockstepNode* node) {
node->phase = node->p->d.transferActive; node->phase = node->p->d.transferActive;
#endif #endif
if (signal) { if (signal) {
node->p->d.signal(&node->p->d, 1 << node->id); node->p->d.signal(&node->p->d, 1 << id);
} }
return 0; return 0;
} }
@ -215,11 +217,13 @@ static void _GBSIOLockstepNodeProcessEvents(struct mTiming* timing, void* user,
int32_t cycles = 0; int32_t cycles = 0;
node->nextEvent -= cyclesLate; node->nextEvent -= cyclesLate;
if (node->nextEvent <= 0) { if (node->nextEvent <= 0) {
if (!node->id) { int id;
ATOMIC_LOAD(id, node->id);
if (!id) {
cycles = _masterUpdate(node); cycles = _masterUpdate(node);
} else { } else {
cycles = _slaveUpdate(node); cycles = _slaveUpdate(node);
cycles += node->p->d.useCycles(&node->p->d, node->id, node->eventDiff); cycles += node->p->d.useCycles(&node->p->d, id, node->eventDiff);
} }
node->eventDiff = 0; node->eventDiff = 0;
} else { } else {
@ -240,7 +244,9 @@ static void _GBSIOLockstepNodeProcessEvents(struct mTiming* timing, void* user,
static void GBSIOLockstepNodeWriteSB(struct GBSIODriver* driver, uint8_t value) { static void GBSIOLockstepNodeWriteSB(struct GBSIODriver* driver, uint8_t value) {
struct GBSIOLockstepNode* node = (struct GBSIOLockstepNode*) driver; struct GBSIOLockstepNode* node = (struct GBSIOLockstepNode*) driver;
node->p->pendingSB[node->id] = value; int id;
ATOMIC_LOAD(id, node->id);
node->p->pendingSB[id] = value;
} }
static uint8_t GBSIOLockstepNodeWriteSC(struct GBSIODriver* driver, uint8_t value) { static uint8_t GBSIOLockstepNodeWriteSC(struct GBSIODriver* driver, uint8_t value) {
@ -252,11 +258,17 @@ static uint8_t GBSIOLockstepNodeWriteSC(struct GBSIODriver* driver, uint8_t valu
mLockstepLock(&node->p->d); mLockstepLock(&node->p->d);
bool claimed = false; bool claimed = false;
if (ATOMIC_CMPXCHG(node->p->masterClaimed, claimed, true)) { if (ATOMIC_CMPXCHG(node->p->masterClaimed, claimed, true)) {
if (node->id != 0) { int id;
ATOMIC_LOAD(id, node->id);
if (id != 0) {
unsigned sb;
node->p->players[0]->id = 1; node->p->players[0]->id = 1;
node->p->players[1] = node->p->players[0];
node->p->players[0] = node->p->players[1];
node->id = 0; node->id = 0;
node->p->players[1] = node->p->players[0];
node->p->players[0] = node;
sb = node->p->pendingSB[0];
node->p->pendingSB[0] = node->p->pendingSB[1];
node->p->pendingSB[1] = sb;
} }
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING); ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING);
ATOMIC_STORE(node->p->d.transferCycles, GBSIOCyclesPerTransfer[(value >> 1) & 1]); ATOMIC_STORE(node->p->d.transferCycles, GBSIOCyclesPerTransfer[(value >> 1) & 1]);