GBA SIO: Replace writeRegister with writeSIOCNT

This commit is contained in:
Vicki Pfau 2024-05-22 01:40:01 -07:00
parent 9998de4880
commit 5da4b1fc4d
6 changed files with 88 additions and 120 deletions

View File

@ -117,7 +117,7 @@ struct GBASIODriver {
bool (*handlesMode)(struct GBASIODriver* driver, enum GBASIOMode mode);
int (*connectedDevices)(struct GBASIODriver* driver);
int (*deviceId)(struct GBASIODriver* driver);
uint16_t (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value);
uint16_t (*writeSIOCNT)(struct GBASIODriver* driver, uint16_t value);
};
enum GBASIOBattleChipGateFlavor {

View File

@ -34,7 +34,7 @@ enum {
};
static bool GBASIOBattlechipGateLoad(struct GBASIODriver* driver);
static uint16_t GBASIOBattlechipGateWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
static uint16_t GBASIOBattlechipGateWriteSIOCNT(struct GBASIODriver* driver, uint16_t value);
static bool GBASIOBattlechipGateHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode);
static int GBASIOBattlechipGateConnectedDevices(struct GBASIODriver* driver);
@ -46,7 +46,7 @@ void GBASIOBattlechipGateCreate(struct GBASIOBattlechipGate* gate) {
gate->d.deinit = NULL;
gate->d.load = GBASIOBattlechipGateLoad;
gate->d.unload = NULL;
gate->d.writeRegister = GBASIOBattlechipGateWriteRegister;
gate->d.writeSIOCNT = GBASIOBattlechipGateWriteSIOCNT;
gate->d.setMode = NULL;
gate->d.handlesMode = GBASIOBattlechipGateHandlesMode;
gate->d.connectedDevices = GBASIOBattlechipGateConnectedDevices;
@ -68,22 +68,12 @@ bool GBASIOBattlechipGateLoad(struct GBASIODriver* driver) {
return true;
}
uint16_t GBASIOBattlechipGateWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
uint16_t GBASIOBattlechipGateWriteSIOCNT(struct GBASIODriver* driver, uint16_t value) {
struct GBASIOBattlechipGate* gate = (struct GBASIOBattlechipGate*) driver;
switch (address) {
case GBA_REG_SIOCNT:
value &= ~0xC;
value |= 0x8;
if (value & 0x80) {
_battlechipTransfer(gate);
}
break;
case GBA_REG_SIOMLT_SEND:
break;
case GBA_REG_RCNT:
break;
default:
break;
value &= ~0xC;
value |= 0x8;
if (value & 0x80) {
_battlechipTransfer(gate);
}
return value;
}

View File

@ -193,9 +193,6 @@ void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value) {
sio->rcnt &= 0xF;
sio->rcnt |= value & ~0xF;
_switchMode(sio);
if (sio->activeDriver && sio->activeDriver->writeRegister) {
sio->activeDriver->writeRegister(sio->activeDriver, GBA_REG_RCNT, value);
}
}
void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
@ -213,7 +210,7 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
id = sio->activeDriver->deviceId(sio->activeDriver);
}
connected = sio->activeDriver->connectedDevices(sio->activeDriver);
handled = !!sio->activeDriver->writeRegister;
handled = !!sio->activeDriver->writeSIOCNT;
}
}
@ -229,7 +226,7 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
break;
}
if (handled) {
value = sio->activeDriver->writeRegister(sio->activeDriver, GBA_REG_SIOCNT, value);
value = sio->activeDriver->writeSIOCNT(sio->activeDriver, value);
} else {
// Dummy drivers
switch (sio->mode) {
@ -328,10 +325,6 @@ uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t valu
// TODO
break;
}
if (sio->activeDriver && sio->activeDriver->writeRegister && sio->activeDriver->handlesMode(sio->activeDriver, sio->mode)) {
sio->activeDriver->writeRegister(sio->activeDriver, address, value);
}
return value;
}

View File

@ -36,7 +36,7 @@ void GBASIODolphinCreate(struct GBASIODolphin* dol) {
dol->d.init = GBASIODolphinInit;
dol->d.load = GBASIODolphinLoad;
dol->d.unload = GBASIODolphinUnload;
dol->d.writeRegister = NULL;
dol->d.writeSIOCNT = NULL;
dol->d.setMode = NULL;
dol->d.handlesMode = GBASIODolphinHandlesMode;
dol->d.connectedDevices = GBASIODolphinConnectedDevices;

View File

@ -13,7 +13,7 @@
#include <mgba-util/memory.h>
static uint16_t _gbpRead(struct mKeyCallback*);
static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
static uint16_t _gbpSioWriteSIOCNT(struct GBASIODriver* driver, uint16_t value);
static bool _gbpSioHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode);
static int _gbpSioConnectedDevices(struct GBASIODriver* driver);
static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate);
@ -49,7 +49,7 @@ void GBASIOPlayerInit(struct GBASIOPlayer* gbp) {
gbp->d.deinit = NULL;
gbp->d.load = NULL;
gbp->d.unload = NULL;
gbp->d.writeRegister = _gbpSioWriteRegister;
gbp->d.writeSIOCNT = _gbpSioWriteSIOCNT;
gbp->d.setMode = NULL;
gbp->d.handlesMode = _gbpSioHandlesMode;
gbp->d.connectedDevices = _gbpSioConnectedDevices;
@ -106,28 +106,27 @@ uint16_t _gbpRead(struct mKeyCallback* callback) {
return 0;
}
uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
uint16_t _gbpSioWriteSIOCNT(struct GBASIODriver* driver, uint16_t value) {
struct GBASIOPlayer* gbp = (struct GBASIOPlayer*) driver;
if (address == GBA_REG_SIOCNT) {
if (value & 0x0080) {
uint32_t rx = gbp->p->memory.io[GBA_REG(SIODATA32_LO)] | (gbp->p->memory.io[GBA_REG(SIODATA32_HI)] << 16);
if (gbp->txPosition < 12 && gbp->txPosition > 0) {
// TODO: Check expected
} else if (gbp->txPosition >= 12) {
// 0x00 = Stop
// 0x11 = Hard Stop
// 0x22 = Start
if (gbp->p->rumble) {
int32_t currentTime = mTimingCurrentTime(&gbp->p->timing);
gbp->p->rumble->setRumble(gbp->p->rumble, (rx & 0x33) == 0x22, currentTime - gbp->p->lastRumble);
gbp->p->lastRumble = currentTime;
}
if (value & 0x0080) {
uint32_t rx = gbp->p->memory.io[GBA_REG(SIODATA32_LO)] | (gbp->p->memory.io[GBA_REG(SIODATA32_HI)] << 16);
if (gbp->txPosition < 12 && gbp->txPosition > 0) {
// TODO: Check expected
} else if (gbp->txPosition >= 12) {
uint32_t mask = 0x33;
// 0x00 = Stop
// 0x11 = Hard Stop
// 0x22 = Start
if (gbp->p->rumble) {
int32_t currentTime = mTimingCurrentTime(&gbp->p->timing);
gbp->p->rumble->setRumble(gbp->p->rumble, (rx & 0x33) == 0x22, currentTime - gbp->p->lastRumble);
gbp->p->lastRumble = currentTime;
}
mTimingDeschedule(&gbp->p->timing, &gbp->event);
mTimingSchedule(&gbp->p->timing, &gbp->event, 2048);
}
value &= 0x78FB;
mTimingDeschedule(&gbp->p->timing, &gbp->event);
mTimingSchedule(&gbp->p->timing, &gbp->event, 2048);
}
value &= 0x78FB;
return value;
}

View File

@ -19,8 +19,8 @@ static void GBASIOLockstepNodeSetMode(struct GBASIODriver* driver, enum GBASIOMo
static bool GBASIOLockstepNodeHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode);
static int GBASIOLockstepNodeConnectedDevices(struct GBASIODriver* driver);
static int GBASIOLockstepNodeDeviceId(struct GBASIODriver* driver);
static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
static uint16_t GBASIOLockstepNodeMultiWriteSIOCNT(struct GBASIODriver* driver, uint16_t value);
static uint16_t GBASIOLockstepNodeNormalWriteSIOCNT(struct GBASIODriver* driver, uint16_t value);
static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* driver, uint32_t cyclesLate);
static void _finishTransfer(struct GBASIOLockstepNode* node);
@ -46,7 +46,7 @@ void GBASIOLockstepNodeCreate(struct GBASIOLockstepNode* node) {
node->d.handlesMode = GBASIOLockstepNodeHandlesMode;
node->d.connectedDevices = GBASIOLockstepNodeConnectedDevices;
node->d.deviceId = GBASIOLockstepNodeDeviceId;
node->d.writeRegister = NULL;
node->d.writeSIOCNT = NULL;
}
bool GBASIOLockstepAttachNode(struct GBASIOLockstep* lockstep, struct GBASIOLockstepNode* node) {
@ -112,7 +112,7 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) {
switch (node->mode) {
case GBA_SIO_MULTI:
node->d.writeRegister = GBASIOLockstepNodeMultiWriteRegister;
node->d.writeSIOCNT = GBASIOLockstepNodeMultiWriteSIOCNT;
ATOMIC_ADD(node->p->attachedMulti, 1);
node->d.p->siocnt = GBASIOMultiplayerSetReady(node->d.p->siocnt, node->p->attachedMulti == node->p->d.attached);
if (node->id) {
@ -134,7 +134,7 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) {
} else {
node->d.p->siocnt = GBASIONormalClearSi(node->d.p->siocnt);
}
node->d.writeRegister = GBASIOLockstepNodeNormalWriteRegister;
node->d.writeSIOCNT = GBASIOLockstepNodeNormalWriteSIOCNT;
break;
default:
break;
@ -231,41 +231,35 @@ static int GBASIOLockstepNodeDeviceId(struct GBASIODriver* driver) {
return node->id;
}
static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
static uint16_t GBASIOLockstepNodeMultiWriteSIOCNT(struct GBASIODriver* driver, uint16_t value) {
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
mLockstepLock(&node->p->d);
if (address == GBA_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;
int attached;
ATOMIC_LOAD(transferActive, node->p->d.transferActive);
ATOMIC_LOAD(attached, node->p->d.attached);
enum mLockstepPhase transferActive;
int attached;
ATOMIC_LOAD(transferActive, node->p->d.transferActive);
ATOMIC_LOAD(attached, node->p->d.attached);
driver->p->siocnt = GBASIOMultiplayerSetSlave(driver->p->siocnt, node->id || attached < 2);
driver->p->siocnt = GBASIOMultiplayerSetSlave(driver->p->siocnt, node->id || attached < 2);
if (value & 0x0080 && transferActive == TRANSFER_IDLE) {
if (!node->id && attached > 1 && GBASIOMultiplayerIsReady(node->d.p->siocnt)) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id);
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING);
ATOMIC_STORE(node->p->d.transferCycles, GBASIOTransferCycles(node->d.p));
if (value & 0x0080 && transferActive == TRANSFER_IDLE) {
if (!node->id && attached > 1 && GBASIOMultiplayerIsReady(node->d.p->siocnt)) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id);
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING);
ATOMIC_STORE(node->p->d.transferCycles, GBASIOTransferCycles(node->d.p));
if (mTimingIsScheduled(&driver->p->p->timing, &node->event)) {
node->eventDiff -= node->event.when - mTimingCurrentTime(&driver->p->p->timing);
mTimingDeschedule(&driver->p->p->timing, &node->event);
}
mTimingSchedule(&driver->p->p->timing, &node->event, 0);
if (mTimingIsScheduled(&driver->p->p->timing, &node->event)) {
node->eventDiff -= node->event.when - mTimingCurrentTime(&driver->p->p->timing);
mTimingDeschedule(&driver->p->p->timing, &node->event);
}
mTimingSchedule(&driver->p->p->timing, &node->event, 0);
}
value &= 0xFF83;
value |= driver->p->siocnt & 0x00FC;
} else if (address == GBA_REG_SIOMLT_SEND) {
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);
}
value &= 0xFF83;
value |= driver->p->siocnt & 0x00FC;
mLockstepUnlock(&node->p->d);
@ -525,62 +519,54 @@ static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* user,
mLockstepUnlock(&node->p->d);
}
static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
static uint16_t GBASIOLockstepNodeNormalWriteSIOCNT(struct GBASIODriver* driver, uint16_t value) {
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
mLockstepLock(&node->p->d);
if (address == GBA_REG_SIOCNT) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04X", node->id, value);
int attached;
ATOMIC_LOAD(attached, node->p->attachedNormal);
value &= 0xFF8B;
if (node->id > 0) {
value = GBASIONormalSetSi(value, GBASIONormalGetIdleSo(node->p->players[node->id - 1]->d.p->siocnt));
} else {
value = GBASIONormalClearSi(value);
}
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04X", node->id, value);
int attached;
ATOMIC_LOAD(attached, node->p->attachedNormal);
value &= 0xFF8B;
if (node->id > 0) {
value = GBASIONormalSetSi(value, GBASIONormalGetIdleSo(node->p->players[node->id - 1]->d.p->siocnt));
} else {
value = GBASIONormalClearSi(value);
}
enum mLockstepPhase transferActive;
ATOMIC_LOAD(transferActive, node->p->d.transferActive);
if (node->id < 3 && attached > node->id + 1 && transferActive == TRANSFER_IDLE) {
int try;
for (try = 0; try < 3; ++try) {
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;
}
enum mLockstepPhase transferActive;
ATOMIC_LOAD(transferActive, node->p->d.transferActive);
if (node->id < 3 && attached > node->id + 1 && transferActive == TRANSFER_IDLE) {
int try;
for (try = 0; try < 3; ++try) {
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;
}
}
if ((value & 0x0081) == 0x0081) {
if (!node->id) {
// Frequency
int32_t cycles = GBASIOTransferCycles(node->d.p);
}
if ((value & 0x0081) == 0x0081) {
if (!node->id) {
// Frequency
int32_t cycles = GBASIOTransferCycles(node->d.p);
if (transferActive == TRANSFER_IDLE) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id);
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING);
ATOMIC_STORE(node->p->d.transferCycles, cycles);
if (transferActive == TRANSFER_IDLE) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id);
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING);
ATOMIC_STORE(node->p->d.transferCycles, cycles);
if (mTimingIsScheduled(&driver->p->p->timing, &node->event)) {
node->eventDiff -= node->event.when - mTimingCurrentTime(&driver->p->p->timing);
mTimingDeschedule(&driver->p->p->timing, &node->event);
}
mTimingSchedule(&driver->p->p->timing, &node->event, 0);
} else {
value &= ~0x0080;
if (mTimingIsScheduled(&driver->p->p->timing, &node->event)) {
node->eventDiff -= node->event.when - mTimingCurrentTime(&driver->p->p->timing);
mTimingDeschedule(&driver->p->p->timing, &node->event);
}
mTimingSchedule(&driver->p->p->timing, &node->event, 0);
} else {
// TODO
value &= ~0x0080;
}
} else {
// TODO
}
} else if (address == GBA_REG_SIODATA32_LO) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_LO <- %04X", node->id, value);
} else if (address == GBA_REG_SIODATA32_HI) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04X", node->id, value);
} else if (address == GBA_REG_SIODATA8) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA8 <- %02X", node->id, value);
}
mLockstepUnlock(&node->p->d);