mirror of https://github.com/mgba-emu/mgba.git
GBA SIO: Move starting/end timing logic out of drivers
This commit is contained in:
parent
435c4aa243
commit
621eb4d425
|
@ -119,6 +119,10 @@ struct GBASIODriver {
|
||||||
int (*deviceId)(struct GBASIODriver* driver);
|
int (*deviceId)(struct GBASIODriver* driver);
|
||||||
uint16_t (*writeSIOCNT)(struct GBASIODriver* driver, uint16_t value);
|
uint16_t (*writeSIOCNT)(struct GBASIODriver* driver, uint16_t value);
|
||||||
uint16_t (*writeRCNT)(struct GBASIODriver* driver, uint16_t value);
|
uint16_t (*writeRCNT)(struct GBASIODriver* driver, uint16_t value);
|
||||||
|
bool (*start)(struct GBASIODriver* driver);
|
||||||
|
void (*finishMultiplayer)(struct GBASIODriver* driver, uint16_t data[4]);
|
||||||
|
uint8_t (*finishNormal8)(struct GBASIODriver* driver);
|
||||||
|
uint32_t (*finishNormal32)(struct GBASIODriver* driver);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GBASIOBattleChipGateFlavor {
|
enum GBASIOBattleChipGateFlavor {
|
||||||
|
@ -130,7 +134,6 @@ enum GBASIOBattleChipGateFlavor {
|
||||||
|
|
||||||
struct GBASIOBattlechipGate {
|
struct GBASIOBattlechipGate {
|
||||||
struct GBASIODriver d;
|
struct GBASIODriver d;
|
||||||
struct mTimingEvent event;
|
|
||||||
uint16_t chipId;
|
uint16_t chipId;
|
||||||
uint16_t data[2];
|
uint16_t data[2];
|
||||||
int state;
|
int state;
|
||||||
|
|
|
@ -191,7 +191,7 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
|
||||||
* | bits 2 - 3: GB Player inputs posted
|
* | bits 2 - 3: GB Player inputs posted
|
||||||
* | bits 4 - 8: GB Player transmit position
|
* | bits 4 - 8: GB Player transmit position
|
||||||
* | bits 9 - 23: Reserved
|
* | bits 9 - 23: Reserved
|
||||||
* 0x002C4 - 0x002C7: Game Boy Player next event
|
* 0x002C4 - 0x002C7: SIO next event
|
||||||
* 0x002C8 - 0x002CB: Current DMA transfer word
|
* 0x002C8 - 0x002CB: Current DMA transfer word
|
||||||
* 0x002CC - 0x002CF: Last DMA transfer PC
|
* 0x002CC - 0x002CF: Last DMA transfer PC
|
||||||
* 0x002D0 - 0x002DF: Matrix memory command buffer
|
* 0x002D0 - 0x002DF: Matrix memory command buffer
|
||||||
|
@ -370,7 +370,7 @@ struct GBASerializedState {
|
||||||
uint8_t lightSample;
|
uint8_t lightSample;
|
||||||
GBASerializedHWFlags2 flags2;
|
GBASerializedHWFlags2 flags2;
|
||||||
GBASerializedHWFlags3 flags3;
|
GBASerializedHWFlags3 flags3;
|
||||||
uint32_t gbpNextEvent;
|
uint32_t sioNextEvent;
|
||||||
} hw;
|
} hw;
|
||||||
|
|
||||||
uint32_t dmaTransferRegister;
|
uint32_t dmaTransferRegister;
|
||||||
|
|
|
@ -21,7 +21,6 @@ struct GBASIOPlayer {
|
||||||
struct GBA* p;
|
struct GBA* p;
|
||||||
unsigned inputsPosted;
|
unsigned inputsPosted;
|
||||||
int txPosition;
|
int txPosition;
|
||||||
struct mTimingEvent event;
|
|
||||||
struct GBASIOPlayerKeyCallback callback;
|
struct GBASIOPlayerKeyCallback callback;
|
||||||
bool oldOpposingDirections;
|
bool oldOpposingDirections;
|
||||||
struct mKeyCallback* oldCallback;
|
struct mKeyCallback* oldCallback;
|
||||||
|
|
|
@ -486,10 +486,10 @@ void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASeria
|
||||||
flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState);
|
flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState);
|
||||||
flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter);
|
flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter);
|
||||||
|
|
||||||
// GBP stuff is only here for legacy reasons
|
// GBP/SIO stuff is only here for legacy reasons
|
||||||
flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->p->sio.gbp.inputsPosted);
|
flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->p->sio.gbp.inputsPosted);
|
||||||
flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->p->sio.gbp.txPosition);
|
flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->p->sio.gbp.txPosition);
|
||||||
STORE_32(hw->p->sio.gbp.event.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent);
|
STORE_32(hw->p->sio.completeEvent.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.sioNextEvent);
|
||||||
|
|
||||||
state->hw.flags2 = flags2;
|
state->hw.flags2 = flags2;
|
||||||
}
|
}
|
||||||
|
@ -520,16 +520,16 @@ void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASer
|
||||||
hw->lightSample = state->hw.lightSample;
|
hw->lightSample = state->hw.lightSample;
|
||||||
hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1);
|
hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1);
|
||||||
|
|
||||||
// GBP stuff is only here for legacy reasons
|
// GBP/SIO stuff is only here for legacy reasons
|
||||||
hw->p->sio.gbp.inputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2);
|
hw->p->sio.gbp.inputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2);
|
||||||
hw->p->sio.gbp.txPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2);
|
hw->p->sio.gbp.txPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2);
|
||||||
|
|
||||||
uint32_t when;
|
uint32_t when;
|
||||||
LOAD_32(when, 0, &state->hw.gbpNextEvent);
|
LOAD_32(when, 0, &state->hw.sioNextEvent);
|
||||||
if (hw->devices & HW_GB_PLAYER) {
|
if (hw->devices & HW_GB_PLAYER) {
|
||||||
GBASIOSetDriver(&hw->p->sio, &hw->p->sio.gbp.d, GBA_SIO_NORMAL_32);
|
GBASIOSetDriver(&hw->p->sio, &hw->p->sio.gbp.d, GBA_SIO_NORMAL_32);
|
||||||
if (hw->p->memory.io[GBA_REG(SIOCNT)] & 0x0080) {
|
}
|
||||||
mTimingSchedule(&hw->p->timing, &hw->p->sio.gbp.event, when);
|
if ((hw->p->memory.io[GBA_REG(SIOCNT)] & 0x0080) && when < 0x20000) {
|
||||||
}
|
mTimingSchedule(&hw->p->timing, &hw->p->sio.completeEvent, when);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,25 +37,15 @@ static bool GBASIOBattlechipGateLoad(struct GBASIODriver* driver);
|
||||||
static uint16_t GBASIOBattlechipGateWriteSIOCNT(struct GBASIODriver* driver, uint16_t value);
|
static uint16_t GBASIOBattlechipGateWriteSIOCNT(struct GBASIODriver* driver, uint16_t value);
|
||||||
static bool GBASIOBattlechipGateHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode);
|
static bool GBASIOBattlechipGateHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode);
|
||||||
static int GBASIOBattlechipGateConnectedDevices(struct GBASIODriver* driver);
|
static int GBASIOBattlechipGateConnectedDevices(struct GBASIODriver* driver);
|
||||||
|
static void GBASIOBattlechipGateFinishMultiplayer(struct GBASIODriver* driver, uint16_t data[4]);
|
||||||
static void _battlechipTransfer(struct GBASIOBattlechipGate* gate);
|
|
||||||
static void _battlechipTransferEvent(struct mTiming* timing, void* user, uint32_t cyclesLate);
|
|
||||||
|
|
||||||
void GBASIOBattlechipGateCreate(struct GBASIOBattlechipGate* gate) {
|
void GBASIOBattlechipGateCreate(struct GBASIOBattlechipGate* gate) {
|
||||||
gate->d.init = NULL;
|
memset(&gate->d, 0, sizeof(gate->d));
|
||||||
gate->d.deinit = NULL;
|
|
||||||
gate->d.load = GBASIOBattlechipGateLoad;
|
gate->d.load = GBASIOBattlechipGateLoad;
|
||||||
gate->d.unload = NULL;
|
|
||||||
gate->d.writeSIOCNT = GBASIOBattlechipGateWriteSIOCNT;
|
gate->d.writeSIOCNT = GBASIOBattlechipGateWriteSIOCNT;
|
||||||
gate->d.setMode = NULL;
|
|
||||||
gate->d.handlesMode = GBASIOBattlechipGateHandlesMode;
|
gate->d.handlesMode = GBASIOBattlechipGateHandlesMode;
|
||||||
gate->d.connectedDevices = GBASIOBattlechipGateConnectedDevices;
|
gate->d.connectedDevices = GBASIOBattlechipGateConnectedDevices;
|
||||||
gate->d.deviceId = NULL;
|
gate->d.finishMultiplayer = GBASIOBattlechipGateFinishMultiplayer;
|
||||||
gate->d.writeRCNT = NULL;
|
|
||||||
|
|
||||||
gate->event.context = gate;
|
|
||||||
gate->event.callback = _battlechipTransferEvent;
|
|
||||||
gate->event.priority = 0x80;
|
|
||||||
|
|
||||||
gate->chipId = 0;
|
gate->chipId = 0;
|
||||||
gate->flavor = GBA_FLAVOR_BATTLECHIP_GATE;
|
gate->flavor = GBA_FLAVOR_BATTLECHIP_GATE;
|
||||||
|
@ -70,12 +60,9 @@ bool GBASIOBattlechipGateLoad(struct GBASIODriver* driver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t GBASIOBattlechipGateWriteSIOCNT(struct GBASIODriver* driver, uint16_t value) {
|
uint16_t GBASIOBattlechipGateWriteSIOCNT(struct GBASIODriver* driver, uint16_t value) {
|
||||||
struct GBASIOBattlechipGate* gate = (struct GBASIOBattlechipGate*) driver;
|
UNUSED(driver);
|
||||||
value &= ~0xC;
|
value &= ~0xC;
|
||||||
value |= 0x8;
|
value |= 0x8;
|
||||||
if (value & 0x80) {
|
|
||||||
_battlechipTransfer(gate);
|
|
||||||
}
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,20 +82,8 @@ static int GBASIOBattlechipGateConnectedDevices(struct GBASIODriver* driver) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _battlechipTransfer(struct GBASIOBattlechipGate* gate) {
|
static void GBASIOBattlechipGateFinishMultiplayer(struct GBASIODriver* driver, uint16_t data[4]) {
|
||||||
int32_t cycles = GBASIOTransferCycles(gate->d.p);
|
struct GBASIOBattlechipGate* gate = (struct GBASIOBattlechipGate*) driver;
|
||||||
mTimingDeschedule(&gate->d.p->p->timing, &gate->event);
|
|
||||||
mTimingSchedule(&gate->d.p->p->timing, &gate->event, cycles);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _battlechipTransferEvent(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
|
||||||
UNUSED(timing);
|
|
||||||
struct GBASIOBattlechipGate* gate = user;
|
|
||||||
|
|
||||||
if (gate->d.p->mode == GBA_SIO_NORMAL_32) {
|
|
||||||
GBASIONormal32FinishTransfer(gate->d.p, 0, cyclesLate);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t cmd = gate->d.p->p->memory.io[GBA_REG(SIOMLT_SEND)];
|
uint16_t cmd = gate->d.p->p->memory.io[GBA_REG(SIOMLT_SEND)];
|
||||||
uint16_t reply = 0xFFFF;
|
uint16_t reply = 0xFFFF;
|
||||||
|
@ -189,8 +164,8 @@ void _battlechipTransferEvent(struct mTiming* timing, void* user, uint32_t cycle
|
||||||
mLOG(GBA_BATTLECHIP, DEBUG, "Gate: %04X (%i)", reply, gate->state);
|
mLOG(GBA_BATTLECHIP, DEBUG, "Gate: %04X (%i)", reply, gate->state);
|
||||||
++gate->state;
|
++gate->state;
|
||||||
|
|
||||||
uint16_t data[4] = {
|
data[0] = cmd;
|
||||||
cmd, reply, 0xFFFF, 0xFFFF
|
data[1] = reply;
|
||||||
};
|
data[2] = 0xFFFF;
|
||||||
GBASIOMultiplayerFinishTransfer(gate->d.p, data, cyclesLate);
|
data[3] = 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,6 +221,17 @@ void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _startTransfer(struct GBASIO* sio) {
|
||||||
|
if (sio->activeDriver && sio->activeDriver->start) {
|
||||||
|
if (!sio->activeDriver->start(sio->activeDriver)) {
|
||||||
|
// Transfer completion is handled internally to the driver
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mTimingDeschedule(&sio->p->timing, &sio->completeEvent);
|
||||||
|
mTimingSchedule(&sio->p->timing, &sio->completeEvent, GBASIOTransferCycles(sio));
|
||||||
|
}
|
||||||
|
|
||||||
void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
|
void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
|
||||||
if ((value ^ sio->siocnt) & 0x3000) {
|
if ((value ^ sio->siocnt) & 0x3000) {
|
||||||
sio->siocnt = value & 0x3000;
|
sio->siocnt = value & 0x3000;
|
||||||
|
@ -256,6 +267,18 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
|
||||||
// investigation than I managed, apparently.
|
// investigation than I managed, apparently.
|
||||||
sio->rcnt = GBASIORegisterRCNTFillSc(sio->rcnt);
|
sio->rcnt = GBASIORegisterRCNTFillSc(sio->rcnt);
|
||||||
|
|
||||||
|
if (GBASIOMultiplayerIsBusy(value) && !GBASIOMultiplayerIsBusy(sio->siocnt)) {
|
||||||
|
if (!id) {
|
||||||
|
sio->p->memory.io[GBA_REG(SIOMULTI0)] = 0xFFFF;
|
||||||
|
sio->p->memory.io[GBA_REG(SIOMULTI1)] = 0xFFFF;
|
||||||
|
sio->p->memory.io[GBA_REG(SIOMULTI2)] = 0xFFFF;
|
||||||
|
sio->p->memory.io[GBA_REG(SIOMULTI3)] = 0xFFFF;
|
||||||
|
sio->rcnt = GBASIORegisterRCNTClearSc(sio->rcnt);
|
||||||
|
_startTransfer(sio);
|
||||||
|
} else {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case GBA_SIO_NORMAL_8:
|
case GBA_SIO_NORMAL_8:
|
||||||
case GBA_SIO_NORMAL_32:
|
case GBA_SIO_NORMAL_32:
|
||||||
|
@ -264,6 +287,13 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
|
||||||
if (GBASIONormalGetSc(value)) {
|
if (GBASIONormalGetSc(value)) {
|
||||||
sio->rcnt = GBASIORegisterRCNTFillSc(sio->rcnt);
|
sio->rcnt = GBASIORegisterRCNTFillSc(sio->rcnt);
|
||||||
}
|
}
|
||||||
|
if (GBASIONormalIsStart(value) && !GBASIONormalIsStart(sio->siocnt)) {
|
||||||
|
if (GBASIONormalIsSc(value)) {
|
||||||
|
_startTransfer(sio);
|
||||||
|
} else {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -277,15 +307,6 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
|
||||||
case GBA_SIO_NORMAL_8:
|
case GBA_SIO_NORMAL_8:
|
||||||
case GBA_SIO_NORMAL_32:
|
case GBA_SIO_NORMAL_32:
|
||||||
value = GBASIONormalFillSi(value);
|
value = GBASIONormalFillSi(value);
|
||||||
if ((value & 0x0081) == 0x0081) {
|
|
||||||
if (GBASIONormalIsIrq(value)) {
|
|
||||||
mTimingDeschedule(&sio->p->timing, &sio->completeEvent);
|
|
||||||
mTimingSchedule(&sio->p->timing, &sio->completeEvent, GBASIOTransferCycles(sio));
|
|
||||||
} else {
|
|
||||||
// TODO: Test this on hardware to see if this is correct
|
|
||||||
value = GBASIONormalClearStart(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case GBA_SIO_MULTI:
|
case GBA_SIO_MULTI:
|
||||||
value = GBASIOMultiplayerFillReady(value);
|
value = GBASIOMultiplayerFillReady(value);
|
||||||
|
@ -473,16 +494,29 @@ void GBASIONormal32FinishTransfer(struct GBASIO* sio, uint32_t data, uint32_t cy
|
||||||
static void _sioFinish(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
static void _sioFinish(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
||||||
UNUSED(timing);
|
UNUSED(timing);
|
||||||
struct GBASIO* sio = user;
|
struct GBASIO* sio = user;
|
||||||
uint16_t data[4] = {0, 0, 0, 0};
|
union {
|
||||||
|
uint16_t multi[4];
|
||||||
|
uint8_t normal8;
|
||||||
|
uint32_t normal32;
|
||||||
|
} data = {0};
|
||||||
switch (sio->mode) {
|
switch (sio->mode) {
|
||||||
case GBA_SIO_MULTI:
|
case GBA_SIO_MULTI:
|
||||||
GBASIOMultiplayerFinishTransfer(sio, data, cyclesLate);
|
if (sio->activeDriver && sio->activeDriver->finishMultiplayer) {
|
||||||
|
sio->activeDriver->finishMultiplayer(sio->activeDriver, data.multi);
|
||||||
|
}
|
||||||
|
GBASIOMultiplayerFinishTransfer(sio, data.multi, cyclesLate);
|
||||||
break;
|
break;
|
||||||
case GBA_SIO_NORMAL_8:
|
case GBA_SIO_NORMAL_8:
|
||||||
GBASIONormal8FinishTransfer(sio, 0, cyclesLate);
|
if (sio->activeDriver && sio->activeDriver->finishNormal8) {
|
||||||
|
data.normal8 = sio->activeDriver->finishNormal8(sio->activeDriver);
|
||||||
|
}
|
||||||
|
GBASIONormal8FinishTransfer(sio, data.normal8, cyclesLate);
|
||||||
break;
|
break;
|
||||||
case GBA_SIO_NORMAL_32:
|
case GBA_SIO_NORMAL_32:
|
||||||
GBASIONormal32FinishTransfer(sio, 0, cyclesLate);
|
if (sio->activeDriver && sio->activeDriver->finishNormal32) {
|
||||||
|
data.normal32 = sio->activeDriver->finishNormal32(sio->activeDriver);
|
||||||
|
}
|
||||||
|
GBASIONormal32FinishTransfer(sio, data.normal32, cyclesLate);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// TODO
|
// TODO
|
||||||
|
|
|
@ -33,15 +33,12 @@ static int32_t _processCommand(struct GBASIODolphin* dol, uint32_t cyclesLate);
|
||||||
static void _flush(struct GBASIODolphin* dol);
|
static void _flush(struct GBASIODolphin* dol);
|
||||||
|
|
||||||
void GBASIODolphinCreate(struct GBASIODolphin* dol) {
|
void GBASIODolphinCreate(struct GBASIODolphin* dol) {
|
||||||
|
memset(&dol->d, 0, sizeof(dol->d));
|
||||||
dol->d.init = GBASIODolphinInit;
|
dol->d.init = GBASIODolphinInit;
|
||||||
dol->d.load = GBASIODolphinLoad;
|
dol->d.load = GBASIODolphinLoad;
|
||||||
dol->d.unload = GBASIODolphinUnload;
|
dol->d.unload = GBASIODolphinUnload;
|
||||||
dol->d.writeSIOCNT = NULL;
|
|
||||||
dol->d.setMode = NULL;
|
|
||||||
dol->d.handlesMode = GBASIODolphinHandlesMode;
|
dol->d.handlesMode = GBASIODolphinHandlesMode;
|
||||||
dol->d.connectedDevices = GBASIODolphinConnectedDevices;
|
dol->d.connectedDevices = GBASIODolphinConnectedDevices;
|
||||||
dol->d.deviceId = NULL;
|
|
||||||
dol->d.writeSIOCNT = NULL;
|
|
||||||
dol->event.context = dol;
|
dol->event.context = dol;
|
||||||
dol->event.name = "GB SIO Lockstep";
|
dol->event.name = "GB SIO Lockstep";
|
||||||
dol->event.callback = GBASIODolphinProcessEvents;
|
dol->event.callback = GBASIODolphinProcessEvents;
|
||||||
|
|
|
@ -16,7 +16,8 @@ static uint16_t _gbpRead(struct mKeyCallback*);
|
||||||
static uint16_t _gbpSioWriteSIOCNT(struct GBASIODriver* driver, uint16_t value);
|
static uint16_t _gbpSioWriteSIOCNT(struct GBASIODriver* driver, uint16_t value);
|
||||||
static bool _gbpSioHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode);
|
static bool _gbpSioHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode);
|
||||||
static int _gbpSioConnectedDevices(struct GBASIODriver* driver);
|
static int _gbpSioConnectedDevices(struct GBASIODriver* driver);
|
||||||
static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate);
|
static bool _gbpSioStart(struct GBASIODriver* driver);
|
||||||
|
static uint32_t _gbpSioFinishNormal32(struct GBASIODriver* driver);
|
||||||
|
|
||||||
static const uint8_t _logoPalette[] = {
|
static const uint8_t _logoPalette[] = {
|
||||||
0xDF, 0xFF, 0x0C, 0x64, 0x0C, 0xE4, 0x2D, 0xE4, 0x4E, 0x64, 0x4E, 0xE4, 0x6E, 0xE4, 0xAF, 0x68,
|
0xDF, 0xFF, 0x0C, 0x64, 0x0C, 0xE4, 0x2D, 0xE4, 0x4E, 0x64, 0x4E, 0xE4, 0x6E, 0xE4, 0xAF, 0x68,
|
||||||
|
@ -45,20 +46,12 @@ void GBASIOPlayerInit(struct GBASIOPlayer* gbp) {
|
||||||
gbp->callback.d.readKeys = _gbpRead;
|
gbp->callback.d.readKeys = _gbpRead;
|
||||||
gbp->callback.d.requireOpposingDirections = true;
|
gbp->callback.d.requireOpposingDirections = true;
|
||||||
gbp->callback.p = gbp;
|
gbp->callback.p = gbp;
|
||||||
gbp->d.init = NULL;
|
memset(&gbp->d, 0, sizeof(gbp->d));
|
||||||
gbp->d.deinit = NULL;
|
|
||||||
gbp->d.load = NULL;
|
|
||||||
gbp->d.unload = NULL;
|
|
||||||
gbp->d.writeSIOCNT = _gbpSioWriteSIOCNT;
|
gbp->d.writeSIOCNT = _gbpSioWriteSIOCNT;
|
||||||
gbp->d.setMode = NULL;
|
|
||||||
gbp->d.handlesMode = _gbpSioHandlesMode;
|
gbp->d.handlesMode = _gbpSioHandlesMode;
|
||||||
gbp->d.connectedDevices = _gbpSioConnectedDevices;
|
gbp->d.connectedDevices = _gbpSioConnectedDevices;
|
||||||
gbp->d.deviceId = NULL;
|
gbp->d.start = _gbpSioStart;
|
||||||
gbp->d.writeRCNT = NULL;
|
gbp->d.finishNormal32 = _gbpSioFinishNormal32;
|
||||||
gbp->event.context = gbp;
|
|
||||||
gbp->event.name = "GBA SIO Game Boy Player";
|
|
||||||
gbp->event.callback = _gbpSioProcessEvents;
|
|
||||||
gbp->event.priority = 0x80;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBASIOPlayerReset(struct GBASIOPlayer* gbp) {
|
void GBASIOPlayerReset(struct GBASIOPlayer* gbp) {
|
||||||
|
@ -108,27 +101,26 @@ uint16_t _gbpRead(struct mKeyCallback* callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t _gbpSioWriteSIOCNT(struct GBASIODriver* driver, uint16_t value) {
|
uint16_t _gbpSioWriteSIOCNT(struct GBASIODriver* driver, uint16_t value) {
|
||||||
|
UNUSED(driver);
|
||||||
|
return value & 0x78FB;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _gbpSioStart(struct GBASIODriver* driver) {
|
||||||
struct GBASIOPlayer* gbp = (struct GBASIOPlayer*) driver;
|
struct GBASIOPlayer* gbp = (struct GBASIOPlayer*) driver;
|
||||||
if (value & 0x0080) {
|
uint32_t rx = gbp->p->memory.io[GBA_REG(SIODATA32_LO)] | (gbp->p->memory.io[GBA_REG(SIODATA32_HI)] << 16);
|
||||||
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) {
|
||||||
if (gbp->txPosition < 12 && gbp->txPosition > 0) {
|
// TODO: Check expected
|
||||||
// TODO: Check expected
|
} else if (gbp->txPosition >= 12) {
|
||||||
} else if (gbp->txPosition >= 12) {
|
// 0x00 = Stop
|
||||||
uint32_t mask = 0x33;
|
// 0x11 = Hard Stop
|
||||||
// 0x00 = Stop
|
// 0x22 = Start
|
||||||
// 0x11 = Hard Stop
|
if (gbp->p->rumble) {
|
||||||
// 0x22 = Start
|
int32_t currentTime = mTimingCurrentTime(&gbp->p->timing);
|
||||||
if (gbp->p->rumble) {
|
gbp->p->rumble->setRumble(gbp->p->rumble, (rx & 0x33) == 0x22, currentTime - gbp->p->lastRumble);
|
||||||
int32_t currentTime = mTimingCurrentTime(&gbp->p->timing);
|
gbp->p->lastRumble = currentTime;
|
||||||
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;
|
return true;
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _gbpSioHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode) {
|
static bool _gbpSioHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode) {
|
||||||
|
@ -141,9 +133,8 @@ static int _gbpSioConnectedDevices(struct GBASIODriver* driver) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
uint32_t _gbpSioFinishNormal32(struct GBASIODriver* driver) {
|
||||||
UNUSED(timing);
|
struct GBASIOPlayer* gbp = (struct GBASIOPlayer*) driver;
|
||||||
struct GBASIOPlayer* gbp = user;
|
|
||||||
uint32_t tx = 0;
|
uint32_t tx = 0;
|
||||||
int txPosition = gbp->txPosition;
|
int txPosition = gbp->txPosition;
|
||||||
if (txPosition > 16) {
|
if (txPosition > 16) {
|
||||||
|
@ -154,5 +145,5 @@ void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLat
|
||||||
}
|
}
|
||||||
tx = _gbpTxData[txPosition];
|
tx = _gbpTxData[txPosition];
|
||||||
++gbp->txPosition;
|
++gbp->txPosition;
|
||||||
GBASIONormal32FinishTransfer(gbp->d.p, tx, cyclesLate);
|
return tx;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ static bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver);
|
||||||
static bool GBASIOLockstepNodeHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode);
|
static bool GBASIOLockstepNodeHandlesMode(struct GBASIODriver* driver, enum GBASIOMode mode);
|
||||||
static int GBASIOLockstepNodeConnectedDevices(struct GBASIODriver* driver);
|
static int GBASIOLockstepNodeConnectedDevices(struct GBASIODriver* driver);
|
||||||
static int GBASIOLockstepNodeDeviceId(struct GBASIODriver* driver);
|
static int GBASIOLockstepNodeDeviceId(struct GBASIODriver* driver);
|
||||||
|
static bool GBASIOLockstepNodeStart(struct GBASIODriver* driver);
|
||||||
static uint16_t GBASIOLockstepNodeMultiWriteSIOCNT(struct GBASIODriver* driver, uint16_t value);
|
static uint16_t GBASIOLockstepNodeMultiWriteSIOCNT(struct GBASIODriver* driver, uint16_t value);
|
||||||
static uint16_t GBASIOLockstepNodeNormalWriteSIOCNT(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 _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* driver, uint32_t cyclesLate);
|
||||||
|
@ -37,16 +38,16 @@ void GBASIOLockstepInit(struct GBASIOLockstep* lockstep) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBASIOLockstepNodeCreate(struct GBASIOLockstepNode* node) {
|
void GBASIOLockstepNodeCreate(struct GBASIOLockstepNode* node) {
|
||||||
|
memset(&node->d, 0, sizeof(node->d));
|
||||||
node->d.init = GBASIOLockstepNodeInit;
|
node->d.init = GBASIOLockstepNodeInit;
|
||||||
node->d.deinit = GBASIOLockstepNodeDeinit;
|
node->d.deinit = GBASIOLockstepNodeDeinit;
|
||||||
node->d.load = GBASIOLockstepNodeLoad;
|
node->d.load = GBASIOLockstepNodeLoad;
|
||||||
node->d.unload = GBASIOLockstepNodeUnload;
|
node->d.unload = GBASIOLockstepNodeUnload;
|
||||||
node->d.setMode = NULL;
|
|
||||||
node->d.handlesMode = GBASIOLockstepNodeHandlesMode;
|
node->d.handlesMode = GBASIOLockstepNodeHandlesMode;
|
||||||
node->d.connectedDevices = GBASIOLockstepNodeConnectedDevices;
|
node->d.connectedDevices = GBASIOLockstepNodeConnectedDevices;
|
||||||
node->d.deviceId = GBASIOLockstepNodeDeviceId;
|
node->d.deviceId = GBASIOLockstepNodeDeviceId;
|
||||||
|
node->d.start = GBASIOLockstepNodeStart;
|
||||||
node->d.writeSIOCNT = NULL;
|
node->d.writeSIOCNT = NULL;
|
||||||
node->d.writeRCNT = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GBASIOLockstepAttachNode(struct GBASIOLockstep* lockstep, struct GBASIOLockstepNode* node) {
|
bool GBASIOLockstepAttachNode(struct GBASIOLockstep* lockstep, struct GBASIOLockstepNode* node) {
|
||||||
|
@ -224,6 +225,11 @@ static int GBASIOLockstepNodeDeviceId(struct GBASIODriver* driver) {
|
||||||
return node->id;
|
return node->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool GBASIOLockstepNodeStart(struct GBASIODriver* driver) {
|
||||||
|
UNUSED(driver);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static uint16_t GBASIOLockstepNodeMultiWriteSIOCNT(struct GBASIODriver* driver, uint16_t value) {
|
static uint16_t GBASIOLockstepNodeMultiWriteSIOCNT(struct GBASIODriver* driver, uint16_t value) {
|
||||||
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
|
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
|
||||||
|
|
||||||
|
@ -319,10 +325,6 @@ static int32_t _masterUpdate(struct GBASIOLockstepNode* node) {
|
||||||
switch (node->mode) {
|
switch (node->mode) {
|
||||||
case GBA_SIO_MULTI:
|
case GBA_SIO_MULTI:
|
||||||
node->p->multiRecv[0] = node->d.p->p->memory.io[GBA_REG(SIOMLT_SEND)];
|
node->p->multiRecv[0] = node->d.p->p->memory.io[GBA_REG(SIOMLT_SEND)];
|
||||||
node->d.p->p->memory.io[GBA_REG(SIOMULTI0)] = 0xFFFF;
|
|
||||||
node->d.p->p->memory.io[GBA_REG(SIOMULTI1)] = 0xFFFF;
|
|
||||||
node->d.p->p->memory.io[GBA_REG(SIOMULTI2)] = 0xFFFF;
|
|
||||||
node->d.p->p->memory.io[GBA_REG(SIOMULTI3)] = 0xFFFF;
|
|
||||||
node->p->multiRecv[1] = 0xFFFF;
|
node->p->multiRecv[1] = 0xFFFF;
|
||||||
node->p->multiRecv[2] = 0xFFFF;
|
node->p->multiRecv[2] = 0xFFFF;
|
||||||
node->p->multiRecv[3] = 0xFFFF;
|
node->p->multiRecv[3] = 0xFFFF;
|
||||||
|
|
Loading…
Reference in New Issue