diff --git a/CHANGES b/CHANGES index b184ec92e..ed885288f 100644 --- a/CHANGES +++ b/CHANGES @@ -47,6 +47,7 @@ Bugfixes: - PSP2: Fix issues causing poor audio - Wii: Fix screen tear when unpausing - GBA: Fix some GBA ROM misdetection (fixes mgba.io/i/978) + - GBA Hardware: RTC accuracy improvements Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/src/gba/hardware.c b/src/gba/hardware.c index f252afd96..15b0f56f7 100644 --- a/src/gba/hardware.c +++ b/src/gba/hardware.c @@ -67,7 +67,7 @@ void GBAHardwareInit(struct GBACartridgeHardware* hw, uint16_t* base) { void GBAHardwareClear(struct GBACartridgeHardware* hw) { hw->devices = HW_NONE | (hw->devices & HW_GB_PLAYER_DETECTION); - hw->direction = GPIO_WRITE_ONLY; + hw->readWrite = GPIO_WRITE_ONLY; hw->pinState = 0; hw->direction = 0; @@ -83,7 +83,7 @@ void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uin switch (address) { case GPIO_REG_DATA: hw->pinState &= ~hw->direction; - hw->pinState |= value; + hw->pinState |= value & hw->direction; _readPins(hw); break; case GPIO_REG_DIRECTION: @@ -96,13 +96,13 @@ void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uin mLOG(GBA_HW, WARN, "Invalid GPIO address"); } if (hw->readWrite) { - uint16_t old; - LOAD_16(old, 0, hw->gpioBase); - old &= ~hw->direction; - old |= hw->pinState; - STORE_16(old, 0, hw->gpioBase); + STORE_16(hw->pinState, 0, hw->gpioBase); + STORE_16(hw->direction, 2, hw->gpioBase); + STORE_16(hw->readWrite, 4, hw->gpioBase); } else { hw->gpioBase[0] = 0; + hw->gpioBase[1] = 0; + hw->gpioBase[2] = 0; } } @@ -167,11 +167,13 @@ void _rtcReadPins(struct GBACartridgeHardware* hw) { if ((hw->pinState & 5) == 1) { hw->rtc.transferStep = 1; } + _outputPins(hw, 1); break; case 1: if ((hw->pinState & 5) == 5) { hw->rtc.transferStep = 2; } + _outputPins(hw, 5); break; case 2: if (!(hw->pinState & 1)) { @@ -179,11 +181,7 @@ void _rtcReadPins(struct GBACartridgeHardware* hw) { hw->rtc.bits |= ((hw->pinState & 2) >> 1) << hw->rtc.bitsRead; } else { if (hw->pinState & 4) { - // GPIO direction should always != reading - if (hw->direction & 2) { - if (RTCCommandDataIsReading(hw->rtc.command)) { - mLOG(GBA_HW, GAME_ERROR, "Attempting to write to RTC while in read mode"); - } + if (!RTCCommandDataIsReading(hw->rtc.command)) { ++hw->rtc.bitsRead; if (hw->rtc.bitsRead == 8) { _rtcProcessByte(hw); @@ -195,7 +193,7 @@ void _rtcReadPins(struct GBACartridgeHardware* hw) { --hw->rtc.bytesRemaining; if (hw->rtc.bytesRemaining <= 0) { hw->rtc.commandActive = 0; - hw->rtc.command = RTCCommandDataClearReading(hw->rtc.command); + hw->rtc.command = 0; } hw->rtc.bitsRead = 0; } @@ -204,8 +202,9 @@ void _rtcReadPins(struct GBACartridgeHardware* hw) { hw->rtc.bitsRead = 0; hw->rtc.bytesRemaining = 0; hw->rtc.commandActive = 0; - hw->rtc.command = RTCCommandDataClearReading(hw->rtc.command); + hw->rtc.command = 0; hw->rtc.transferStep = 0; + _outputPins(hw, 1); } } break; @@ -256,12 +255,16 @@ void _rtcProcessByte(struct GBACartridgeHardware* hw) { hw->rtc.bitsRead = 0; if (!hw->rtc.bytesRemaining) { hw->rtc.commandActive = 0; - hw->rtc.command = RTCCommandDataClearReading(hw->rtc.command); + hw->rtc.command = 0; } } unsigned _rtcOutput(struct GBACartridgeHardware* hw) { uint8_t outputByte = 0; + if (!hw->rtc.commandActive) { + mLOG(GBA_HW, GAME_ERROR, "Attempting to use RTC without an active command"); + return 0; + } switch (RTCCommandDataGetCommand(hw->rtc.command)) { case RTC_CONTROL: outputByte = hw->rtc.control;