From bc16a1bfe33e26f9d781bf5de01fe94cc5293689 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 3 Apr 2021 01:18:23 -0700 Subject: [PATCH] GBA Cart: Refactor hardware.c into cart/gpio.c etc --- .../internal/gba/{hardware.h => cart/gpio.h} | 71 +------- include/mgba/internal/gba/{ => cart}/matrix.h | 0 include/mgba/internal/gba/{ => cart}/vfame.h | 0 include/mgba/internal/gba/memory.h | 6 +- include/mgba/internal/gba/sio.h | 5 +- include/mgba/internal/gba/sio/gbp.h | 37 ++++ src/gba/CMakeLists.txt | 11 +- src/gba/{ => cart}/ereader.c | 2 +- src/gba/{hardware.c => cart/gpio.c} | 164 ++---------------- src/gba/{ => cart}/matrix.c | 2 +- src/gba/{ => cart}/vfame.c | 2 +- src/gba/gba.c | 4 +- src/gba/overrides.c | 2 +- src/gba/sio.c | 7 + src/gba/sio/gbp.c | 148 ++++++++++++++++ 15 files changed, 230 insertions(+), 231 deletions(-) rename include/mgba/internal/gba/{hardware.h => cart/gpio.h} (63%) rename include/mgba/internal/gba/{ => cart}/matrix.h (100%) rename include/mgba/internal/gba/{ => cart}/vfame.h (100%) create mode 100644 include/mgba/internal/gba/sio/gbp.h rename src/gba/{ => cart}/ereader.c (99%) rename src/gba/{hardware.c => cart/gpio.c} (73%) rename src/gba/{ => cart}/matrix.c (98%) rename src/gba/{ => cart}/vfame.c (99%) create mode 100644 src/gba/sio/gbp.c diff --git a/include/mgba/internal/gba/hardware.h b/include/mgba/internal/gba/cart/gpio.h similarity index 63% rename from include/mgba/internal/gba/hardware.h rename to include/mgba/internal/gba/cart/gpio.h index 88ae5c29b..93fd359bd 100644 --- a/include/mgba/internal/gba/hardware.h +++ b/include/mgba/internal/gba/cart/gpio.h @@ -13,13 +13,10 @@ CXX_GUARD_START #include #include #include +#include mLOG_DECLARE_CATEGORY(GBA_HW); -#define EREADER_DOTCODE_STRIDE 1420 -#define EREADER_DOTCODE_SIZE (EREADER_DOTCODE_STRIDE * 40) -#define EREADER_CARDS_MAX 16 - #define IS_GPIO_REGISTER(reg) ((reg) == GPIO_REG_DATA || (reg) == GPIO_REG_DIRECTION || (reg) == GPIO_REG_CONTROL) struct GBARTCGenericSource { @@ -82,57 +79,8 @@ struct GBARTC { uint8_t time[7]; }; -struct GBAGBPKeyCallback { - struct mKeyCallback d; - struct GBACartridgeHardware* p; -}; - -struct GBAGBPSIODriver { - struct GBASIODriver d; - struct GBACartridgeHardware* p; -}; - DECL_BITFIELD(GPIOPin, uint16_t); -DECL_BITFIELD(EReaderControl0, uint8_t); -DECL_BIT(EReaderControl0, Data, 0); -DECL_BIT(EReaderControl0, Clock, 1); -DECL_BIT(EReaderControl0, Direction, 2); -DECL_BIT(EReaderControl0, LedEnable, 3); -DECL_BIT(EReaderControl0, Scan, 4); -DECL_BIT(EReaderControl0, Phi, 5); -DECL_BIT(EReaderControl0, PowerEnable, 6); -DECL_BITFIELD(EReaderControl1, uint8_t); -DECL_BIT(EReaderControl1, Scanline, 1); -DECL_BIT(EReaderControl1, Unk1, 4); -DECL_BIT(EReaderControl1, Voltage, 5); - -enum EReaderStateMachine { - EREADER_SERIAL_INACTIVE = 0, - EREADER_SERIAL_STARTING, - EREADER_SERIAL_BIT_0, - EREADER_SERIAL_BIT_1, - EREADER_SERIAL_BIT_2, - EREADER_SERIAL_BIT_3, - EREADER_SERIAL_BIT_4, - EREADER_SERIAL_BIT_5, - EREADER_SERIAL_BIT_6, - EREADER_SERIAL_BIT_7, - EREADER_SERIAL_END_BIT, -}; - -enum EReaderCommand { - EREADER_COMMAND_IDLE = 0, // TODO: Verify on hardware - EREADER_COMMAND_WRITE_DATA = 1, - EREADER_COMMAND_SET_INDEX = 0x22, - EREADER_COMMAND_READ_DATA = 0x23, -}; - -struct EReaderCard { - void* data; - size_t size; -}; - struct GBACartridgeHardware { struct GBA* p; uint32_t devices; @@ -155,12 +103,6 @@ struct GBACartridgeHardware { uint16_t tiltY; int tiltState; - unsigned gbpInputsPosted; - int gbpTxPosition; - struct mTimingEvent gbpNextEvent; - struct GBAGBPKeyCallback gbpCallback; - struct GBAGBPSIODriver gbpDriver; - uint16_t eReaderData[44]; uint8_t eReaderSerial[92]; uint16_t eReaderRegisterUnk; @@ -193,17 +135,6 @@ void GBAHardwareGPIOWrite(struct GBACartridgeHardware* gpio, uint32_t address, u void GBAHardwareTiltWrite(struct GBACartridgeHardware* gpio, uint32_t address, uint8_t value); uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* gpio, uint32_t address); -struct GBAVideo; -void GBAHardwarePlayerUpdate(struct GBA* gba); -bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video); - -void GBAHardwareInitEReader(struct GBACartridgeHardware* hw); -void GBAHardwareEReaderWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value); -void GBAHardwareEReaderWriteFlash(struct GBACartridgeHardware* hw, uint32_t address, uint8_t value); -uint16_t GBAHardwareEReaderRead(struct GBACartridgeHardware* hw, uint32_t address); -uint8_t GBAHardwareEReaderReadFlash(struct GBACartridgeHardware* hw, uint32_t address); -void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, size_t size); - void GBARTCGenericSourceInit(struct GBARTCGenericSource* rtc, struct GBA* gba); struct GBASerializedState; diff --git a/include/mgba/internal/gba/matrix.h b/include/mgba/internal/gba/cart/matrix.h similarity index 100% rename from include/mgba/internal/gba/matrix.h rename to include/mgba/internal/gba/cart/matrix.h diff --git a/include/mgba/internal/gba/vfame.h b/include/mgba/internal/gba/cart/vfame.h similarity index 100% rename from include/mgba/internal/gba/vfame.h rename to include/mgba/internal/gba/cart/vfame.h diff --git a/include/mgba/internal/gba/memory.h b/include/mgba/internal/gba/memory.h index caf1d689b..fac001de4 100644 --- a/include/mgba/internal/gba/memory.h +++ b/include/mgba/internal/gba/memory.h @@ -14,10 +14,10 @@ CXX_GUARD_START #include #include -#include #include -#include -#include +#include +#include +#include enum GBAMemoryRegion { REGION_BIOS = 0x0, diff --git a/include/mgba/internal/gba/sio.h b/include/mgba/internal/gba/sio.h index 2c06af698..e0fca7812 100644 --- a/include/mgba/internal/gba/sio.h +++ b/include/mgba/internal/gba/sio.h @@ -10,8 +10,9 @@ CXX_GUARD_START -#include #include +#include +#include #define MAX_GBAS 4 @@ -69,6 +70,8 @@ struct GBASIO { uint16_t rcnt; uint16_t siocnt; + + struct GBASIOPlayer gbp; }; void GBASIOInit(struct GBASIO* sio); diff --git a/include/mgba/internal/gba/sio/gbp.h b/include/mgba/internal/gba/sio/gbp.h new file mode 100644 index 000000000..f9ab6beaf --- /dev/null +++ b/include/mgba/internal/gba/sio/gbp.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2013-2021 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_GBP_H +#define GBA_GBP_H + +#include + +CXX_GUARD_START + +struct GBASIOPlayer; +struct GBASIOPlayerKeyCallback { + struct mKeyCallback d; + struct GBASIOPlayer* p; +}; + +struct GBASIOPlayer { + struct GBASIODriver d; + struct GBA* p; + unsigned inputsPosted; + int txPosition; + struct mTimingEvent event; + struct GBASIOPlayerKeyCallback callback; +}; + +void GBASIOPlayerInit(struct GBASIOPlayer* gbp); +void GBASIOPlayerReset(struct GBASIOPlayer* gbp); + +struct GBAVideo; +void GBASIOPlayerUpdate(struct GBA* gba); +bool GBASIOPlayerCheckScreen(const struct GBAVideo* video); + +CXX_GUARD_END + +#endif diff --git a/src/gba/CMakeLists.txt b/src/gba/CMakeLists.txt index ba9c298dc..4bf354f3a 100644 --- a/src/gba/CMakeLists.txt +++ b/src/gba/CMakeLists.txt @@ -3,19 +3,20 @@ set(SOURCE_FILES ../gb/audio.c audio.c bios.c + cart/ereader.c + cart/gpio.c + cart/matrix.c + cart/vfame.c cheats.c cheats/codebreaker.c cheats/gameshark.c cheats/parv3.c core.c dma.c - ereader.c gba.c - hardware.c hle-bios.c input.c io.c - matrix.c memory.c overrides.c renderers/cache-set.c @@ -29,13 +30,13 @@ set(SOURCE_FILES serialize.c sharkport.c sio.c + sio/gbp.c + sio/joybus.c timer.c - vfame.c video.c) set(SIO_FILES sio/dolphin.c - sio/joybus.c sio/lockstep.c) set(EXTRA_FILES diff --git a/src/gba/ereader.c b/src/gba/cart/ereader.c similarity index 99% rename from src/gba/ereader.c rename to src/gba/cart/ereader.c index c50ae5a97..d79bd8dbb 100644 --- a/src/gba/ereader.c +++ b/src/gba/cart/ereader.c @@ -4,7 +4,7 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include +#include #include #include diff --git a/src/gba/hardware.c b/src/gba/cart/gpio.c similarity index 73% rename from src/gba/hardware.c rename to src/gba/cart/gpio.c index 2629228af..92196b243 100644 --- a/src/gba/hardware.c +++ b/src/gba/cart/gpio.c @@ -1,9 +1,9 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2021 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include +#include #include #include @@ -33,10 +33,6 @@ static void _rumbleReadPins(struct GBACartridgeHardware* hw); static void _lightReadPins(struct GBACartridgeHardware* hw); -static uint16_t _gbpRead(struct mKeyCallback*); -static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); -static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate); - static const int RTC_BYTES[8] = { 0, // Force reset 0, // Empty @@ -53,19 +49,6 @@ void GBAHardwareInit(struct GBACartridgeHardware* hw, uint16_t* base) { hw->eReaderDots = NULL; memset(hw->eReaderCards, 0, sizeof(hw->eReaderCards)); GBAHardwareClear(hw); - - hw->gbpCallback.d.readKeys = _gbpRead; - hw->gbpCallback.p = hw; - hw->gbpDriver.d.init = 0; - hw->gbpDriver.d.deinit = 0; - hw->gbpDriver.d.load = 0; - hw->gbpDriver.d.unload = 0; - hw->gbpDriver.d.writeRegister = _gbpSioWriteRegister; - hw->gbpDriver.p = hw; - hw->gbpNextEvent.context = &hw->gbpDriver; - hw->gbpNextEvent.name = "GBA SIO Game Boy Player"; - hw->gbpNextEvent.callback = _gbpSioProcessEvents; - hw->gbpNextEvent.priority = 0x80; } void GBAHardwareClear(struct GBACartridgeHardware* hw) { @@ -87,10 +70,6 @@ void GBAHardwareClear(struct GBACartridgeHardware* hw) { hw->eReaderCards[i].data = NULL; hw->eReaderCards[i].size = 0; } - - if (hw->p->sio.drivers.normal == &hw->gbpDriver.d) { - GBASIOSetDriver(&hw->p->sio, 0, SIO_NORMAL_32); - } } void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) { @@ -504,124 +483,10 @@ uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* hw, uint32_t address) { return 0xFF; } -// == Game Boy Player - -static const uint8_t _logoPalette[] = { - 0xDF, 0xFF, 0x0C, 0x64, 0x0C, 0xE4, 0x2D, 0xE4, 0x4E, 0x64, 0x4E, 0xE4, 0x6E, 0xE4, 0xAF, 0x68, - 0xB0, 0xE8, 0xD0, 0x68, 0xF0, 0x68, 0x11, 0x69, 0x11, 0xE9, 0x32, 0x6D, 0x32, 0xED, 0x73, 0xED, - 0x93, 0x6D, 0x94, 0xED, 0xB4, 0x6D, 0xD5, 0xF1, 0xF5, 0x71, 0xF6, 0xF1, 0x16, 0x72, 0x57, 0x72, - 0x57, 0xF6, 0x78, 0x76, 0x78, 0xF6, 0x99, 0xF6, 0xB9, 0xF6, 0xD9, 0x76, 0xDA, 0xF6, 0x1B, 0x7B, - 0x1B, 0xFB, 0x3C, 0xFB, 0x5C, 0x7B, 0x7D, 0x7B, 0x7D, 0xFF, 0x9D, 0x7F, 0xBE, 0x7F, 0xFF, 0x7F, - 0x2D, 0x64, 0x8E, 0x64, 0x8F, 0xE8, 0xF1, 0xE8, 0x52, 0x6D, 0x73, 0x6D, 0xB4, 0xF1, 0x16, 0xF2, - 0x37, 0x72, 0x98, 0x76, 0xFA, 0x7A, 0xFA, 0xFA, 0x5C, 0xFB, 0xBE, 0xFF, 0xDE, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const uint32_t _logoHash = 0xEEDA6963; - -static const uint32_t _gbpTxData[] = { - 0x0000494E, 0x0000494E, - 0xB6B1494E, 0xB6B1544E, - 0xABB1544E, 0xABB14E45, - 0xB1BA4E45, 0xB1BA4F44, - 0xB0BB4F44, 0xB0BB8002, - 0x10000010, 0x20000013, - 0x30000003 -}; - -bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video) { - if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) { - return false; - } - uint32_t hash = hash32(&video->renderer->vram[0x4000], 0x4000, 0); - return hash == _logoHash; -} - -void GBAHardwarePlayerUpdate(struct GBA* gba) { - if (gba->memory.hw.devices & HW_GB_PLAYER) { - if (GBAHardwarePlayerCheckScreen(&gba->video)) { - ++gba->memory.hw.gbpInputsPosted; - gba->memory.hw.gbpInputsPosted %= 3; - gba->keyCallback = &gba->memory.hw.gbpCallback.d; - } else { - // TODO: Save and restore - gba->keyCallback = 0; - } - gba->memory.hw.gbpTxPosition = 0; - return; - } - if (gba->keyCallback) { - return; - } - if (GBAHardwarePlayerCheckScreen(&gba->video)) { - gba->memory.hw.devices |= HW_GB_PLAYER; - gba->memory.hw.gbpInputsPosted = 0; - gba->keyCallback = &gba->memory.hw.gbpCallback.d; - // TODO: Check if the SIO driver is actually used first - GBASIOSetDriver(&gba->sio, &gba->memory.hw.gbpDriver.d, SIO_NORMAL_32); - } -} - -uint16_t _gbpRead(struct mKeyCallback* callback) { - struct GBAGBPKeyCallback* gbpCallback = (struct GBAGBPKeyCallback*) callback; - if (gbpCallback->p->gbpInputsPosted == 2) { - return 0xF0; - } - return 0; -} - -uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) { - struct GBAGBPSIODriver* gbp = (struct GBAGBPSIODriver*) driver; - if (address == REG_SIOCNT) { - if (value & 0x0080) { - uint32_t rx = gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] << 16); - if (gbp->p->gbpTxPosition < 12 && gbp->p->gbpTxPosition > 0) { - // TODO: Check expected - } else if (gbp->p->gbpTxPosition >= 12) { - uint32_t mask = 0x33; - // 0x00 = Stop - // 0x11 = Hard Stop - // 0x22 = Start - if (gbp->p->p->rumble) { - gbp->p->p->rumble->setRumble(gbp->p->p->rumble, (rx & mask) == 0x22); - } - } - mTimingDeschedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent); - mTimingSchedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent, 2048); - } - value &= 0x78FB; - } - return value; -} - -void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) { - UNUSED(timing); - UNUSED(cyclesLate); - struct GBAGBPSIODriver* gbp = user; - uint32_t tx = 0; - int txPosition = gbp->p->gbpTxPosition; - if (txPosition > 16) { - gbp->p->gbpTxPosition = 0; - txPosition = 0; - } else if (txPosition > 12) { - txPosition = 12; - } - tx = _gbpTxData[txPosition]; - ++gbp->p->gbpTxPosition; - gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] = tx; - gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16; - if (GBASIONormalIsIrq(gbp->d.p->siocnt)) { - GBARaiseIRQ(gbp->p->p, IRQ_SIO, cyclesLate); - } - gbp->d.p->siocnt = GBASIONormalClearStart(gbp->d.p->siocnt); - gbp->p->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080; -} - // == Serialization void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) { GBASerializedHWFlags1 flags1 = 0; - GBASerializedHWFlags2 flags2 = 0; flags1 = GBASerializedHWFlags1SetReadWrite(flags1, hw->readWrite); STORE_16(hw->pinState, 0, &state->hw.pinState); STORE_16(hw->direction, 0, &state->hw.pinDirection); @@ -640,14 +505,19 @@ void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASeria flags1 = GBASerializedHWFlags1SetGyroEdge(flags1, hw->gyroEdge); STORE_16(hw->tiltX, 0, &state->hw.tiltSampleX); STORE_16(hw->tiltY, 0, &state->hw.tiltSampleY); - flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState); - flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter); state->hw.lightSample = hw->lightSample; flags1 = GBASerializedHWFlags1SetLightEdge(flags1, hw->lightEdge); - flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->gbpInputsPosted); - flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->gbpTxPosition); - STORE_32(hw->gbpNextEvent.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent); STORE_16(flags1, 0, &state->hw.flags1); + + GBASerializedHWFlags2 flags2 = 0; + flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState); + flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter); + + // GBP stuff is only here for legacy reasons + flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->p->sio.gbp.inputsPosted); + flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->p->sio.gbp.txPosition); + STORE_32(hw->p->sio.gbp.event.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent); + state->hw.flags2 = flags2; } @@ -676,15 +546,17 @@ void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASer hw->lightCounter = GBASerializedHWFlags1GetLightCounter(flags1); hw->lightSample = state->hw.lightSample; hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1); - hw->gbpInputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2); - hw->gbpTxPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2); + + // GBP stuff is only here for legacy reasons + hw->p->sio.gbp.inputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2); + hw->p->sio.gbp.txPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2); uint32_t when; LOAD_32(when, 0, &state->hw.gbpNextEvent); if (hw->devices & HW_GB_PLAYER) { - GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32); + GBASIOSetDriver(&hw->p->sio, &hw->p->sio.gbp.d, SIO_NORMAL_32); if (hw->p->memory.io[REG_SIOCNT >> 1] & 0x0080) { - mTimingSchedule(&hw->p->timing, &hw->gbpNextEvent, when); + mTimingSchedule(&hw->p->timing, &hw->p->sio.gbp.event, when); } } } diff --git a/src/gba/matrix.c b/src/gba/cart/matrix.c similarity index 98% rename from src/gba/matrix.c rename to src/gba/cart/matrix.c index fb72e052f..c594d66b9 100644 --- a/src/gba/matrix.c +++ b/src/gba/cart/matrix.c @@ -3,7 +3,7 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include +#include #include #include diff --git a/src/gba/vfame.c b/src/gba/cart/vfame.c similarity index 99% rename from src/gba/vfame.c rename to src/gba/cart/vfame.c index 0ac834cc9..57b6d903b 100644 --- a/src/gba/vfame.c +++ b/src/gba/cart/vfame.c @@ -3,7 +3,7 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include +#include #include #include diff --git a/src/gba/gba.c b/src/gba/gba.c index a328b55da..7e9d3d47a 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -219,7 +219,7 @@ void GBAReset(struct ARMCore* cpu) { // GB Player SIO control should not be engaged before detection, even if we already know it's GBP gba->memory.hw.devices &= ~HW_GB_PLAYER; - if (gba->sio.drivers.normal == &gba->memory.hw.gbpDriver.d) { + if (gba->sio.drivers.normal == &gba->sio.gbp.d) { GBASIOSetDriver(&gba->sio, NULL, SIO_NORMAL_32); } @@ -855,7 +855,7 @@ void GBAFrameEnded(struct GBA* gba) { } if (gba->memory.hw.devices & (HW_GB_PLAYER | HW_GB_PLAYER_DETECTION)) { - GBAHardwarePlayerUpdate(gba); + GBASIOPlayerUpdate(gba); } size_t c; diff --git a/src/gba/overrides.c b/src/gba/overrides.c index a84ccd2de..86446fbab 100644 --- a/src/gba/overrides.c +++ b/src/gba/overrides.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include diff --git a/src/gba/sio.c b/src/gba/sio.c index bf85f510f..8feaeb624 100644 --- a/src/gba/sio.c +++ b/src/gba/sio.c @@ -7,6 +7,7 @@ #include #include +#include mLOG_DEFINE_CATEGORY(GBA_SIO, "GBA Serial I/O", "gba.sio"); @@ -76,6 +77,10 @@ void GBASIOInit(struct GBASIO* sio) { sio->drivers.multiplayer = 0; sio->drivers.joybus = 0; sio->activeDriver = 0; + + sio->gbp.p = sio->p; + GBASIOPlayerInit(&sio->gbp); + GBASIOReset(sio); } @@ -103,6 +108,8 @@ void GBASIOReset(struct GBASIO* sio) { sio->mode = -1; sio->activeDriver = NULL; _switchMode(sio); + + GBASIOPlayerReset(&sio->gbp); } void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) { diff --git a/src/gba/sio/gbp.c b/src/gba/sio/gbp.c new file mode 100644 index 000000000..8ffafd1c8 --- /dev/null +++ b/src/gba/sio/gbp.c @@ -0,0 +1,148 @@ +/* Copyright (c) 2013-2021 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include + +#include +#include +#include +#include +#include +#include + +static uint16_t _gbpRead(struct mKeyCallback*); +static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); +static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate); + +static const uint8_t _logoPalette[] = { + 0xDF, 0xFF, 0x0C, 0x64, 0x0C, 0xE4, 0x2D, 0xE4, 0x4E, 0x64, 0x4E, 0xE4, 0x6E, 0xE4, 0xAF, 0x68, + 0xB0, 0xE8, 0xD0, 0x68, 0xF0, 0x68, 0x11, 0x69, 0x11, 0xE9, 0x32, 0x6D, 0x32, 0xED, 0x73, 0xED, + 0x93, 0x6D, 0x94, 0xED, 0xB4, 0x6D, 0xD5, 0xF1, 0xF5, 0x71, 0xF6, 0xF1, 0x16, 0x72, 0x57, 0x72, + 0x57, 0xF6, 0x78, 0x76, 0x78, 0xF6, 0x99, 0xF6, 0xB9, 0xF6, 0xD9, 0x76, 0xDA, 0xF6, 0x1B, 0x7B, + 0x1B, 0xFB, 0x3C, 0xFB, 0x5C, 0x7B, 0x7D, 0x7B, 0x7D, 0xFF, 0x9D, 0x7F, 0xBE, 0x7F, 0xFF, 0x7F, + 0x2D, 0x64, 0x8E, 0x64, 0x8F, 0xE8, 0xF1, 0xE8, 0x52, 0x6D, 0x73, 0x6D, 0xB4, 0xF1, 0x16, 0xF2, + 0x37, 0x72, 0x98, 0x76, 0xFA, 0x7A, 0xFA, 0xFA, 0x5C, 0xFB, 0xBE, 0xFF, 0xDE, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const uint32_t _logoHash = 0xEEDA6963; + +static const uint32_t _gbpTxData[] = { + 0x0000494E, 0x0000494E, + 0xB6B1494E, 0xB6B1544E, + 0xABB1544E, 0xABB14E45, + 0xB1BA4E45, 0xB1BA4F44, + 0xB0BB4F44, 0xB0BB8002, + 0x10000010, 0x20000013, + 0x30000003 +}; + +void GBASIOPlayerInit(struct GBASIOPlayer* gbp) { + gbp->callback.d.readKeys = _gbpRead; + gbp->callback.p = gbp; + gbp->d.init = 0; + gbp->d.deinit = 0; + gbp->d.load = 0; + gbp->d.unload = 0; + gbp->d.writeRegister = _gbpSioWriteRegister; + 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) { + if (gbp->p->sio.drivers.normal == &gbp->d) { + GBASIOSetDriver(&gbp->p->sio, NULL, SIO_NORMAL_32); + } +} + +bool GBASIOPlayerCheckScreen(const struct GBAVideo* video) { + if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) { + return false; + } + uint32_t hash = hash32(&video->renderer->vram[0x4000], 0x4000, 0); + return hash == _logoHash; +} + +void GBASIOPlayerUpdate(struct GBA* gba) { + if (gba->memory.hw.devices & HW_GB_PLAYER) { + if (GBASIOPlayerCheckScreen(&gba->video)) { + ++gba->sio.gbp.inputsPosted; + gba->sio.gbp.inputsPosted %= 3; + gba->keyCallback = &gba->sio.gbp.callback.d; + } else { + // TODO: Save and restore + gba->keyCallback = 0; + } + gba->sio.gbp.txPosition = 0; + return; + } + if (gba->keyCallback) { + return; + } + if (GBASIOPlayerCheckScreen(&gba->video)) { + gba->memory.hw.devices |= HW_GB_PLAYER; + gba->sio.gbp.inputsPosted = 0; + gba->keyCallback = &gba->sio.gbp.callback.d; + // TODO: Check if the SIO driver is actually used first + GBASIOSetDriver(&gba->sio, &gba->sio.gbp.d, SIO_NORMAL_32); + } +} + +uint16_t _gbpRead(struct mKeyCallback* callback) { + struct GBASIOPlayerKeyCallback* gbpCallback = (struct GBASIOPlayerKeyCallback*) callback; + if (gbpCallback->p->inputsPosted == 2) { + return 0xF0; + } + return 0; +} + +uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) { + struct GBASIOPlayer* gbp = (struct GBASIOPlayer*) driver; + if (address == REG_SIOCNT) { + if (value & 0x0080) { + uint32_t rx = gbp->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->memory.io[REG_SIODATA32_HI >> 1] << 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) { + gbp->p->rumble->setRumble(gbp->p->rumble, (rx & mask) == 0x22); + } + } + mTimingDeschedule(&gbp->p->timing, &gbp->event); + mTimingSchedule(&gbp->p->timing, &gbp->event, 2048); + } + value &= 0x78FB; + } + return value; +} + +void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) { + UNUSED(timing); + UNUSED(cyclesLate); + struct GBASIOPlayer* gbp = user; + uint32_t tx = 0; + int txPosition = gbp->txPosition; + if (txPosition > 16) { + gbp->txPosition = 0; + txPosition = 0; + } else if (txPosition > 12) { + txPosition = 12; + } + tx = _gbpTxData[txPosition]; + ++gbp->txPosition; + gbp->p->memory.io[REG_SIODATA32_LO >> 1] = tx; + gbp->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16; + if (GBASIONormalIsIrq(gbp->d.p->siocnt)) { + GBARaiseIRQ(gbp->p, IRQ_SIO, cyclesLate); + } + gbp->d.p->siocnt = GBASIONormalClearStart(gbp->d.p->siocnt); + gbp->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080; +}