From a11827cdf0ccc55b9a3f6259a27a9324e24cd018 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 8 Feb 2013 16:20:15 -0600 Subject: [PATCH] Use different reply delays for various DI commands. Fixes issue 5983. --- Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp | 16 ++++++- .../Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp | 43 +++++++++++++++++-- Source/Core/Core/Src/State.cpp | 2 +- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp index 4149931353..1fe6986179 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp @@ -84,6 +84,8 @@ static ipc_msg_queue reply_queue; // arm -> ppc static int enque_reply; +static u64 last_reply_time; + void EnqueReplyCallback(u64 userdata, int) { reply_queue.push_back(userdata); @@ -163,6 +165,7 @@ void Reset(bool _bHard) } request_queue.clear(); reply_queue.clear(); + last_reply_time = 0; } void Shutdown() @@ -246,6 +249,7 @@ void DoState(PointerWrap &p) { p.Do(request_queue); p.Do(reply_queue); + p.Do(last_reply_time); TDeviceMap::const_iterator itr; @@ -518,8 +522,18 @@ void ExecuteCommand(u32 _Address) if (CmdSuccess) { + // Ensure replies happen in order, fairly ugly + // Without this, tons of games fail now that DI commads have different reply delays + int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0; + + const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks(); + + if (ticks_til_last_reply > 0) + reply_delay = ticks_til_last_reply; + + last_reply_time = CoreTiming::GetTicks() + reply_delay; + // Generate a reply to the IPC command - int const reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0; EnqReply(_Address, reply_delay); } else diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp index 0d610edb8c..b6e3254d98 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp @@ -462,8 +462,43 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32 return 1; } -int CWII_IPC_HLE_Device_di::GetCmdDelay(u32) +int CWII_IPC_HLE_Device_di::GetCmdDelay(u32 _CommandAddress) { - // Less than ~1/150th of a second hangs Oregon Trail at "loading wheel". - return SystemTimers::GetTicksPerSecond() / 100; -} \ No newline at end of file + u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); + u32 Command = Memory::Read_U32(BufferIn) >> 24; + + // Hacks below + + switch (Command) + { + case DVDLowRead: + case DVDLowUnencryptedRead: + { + u32 const Size = Memory::Read_U32(BufferIn + 0x04); + // Delay depends on size of read, that makes sense, right? + // More than ~1150K "bytes / sec" hangs NSMBWii on boot. + // Less than ~800K "bytes / sec" hangs DKCR randomly. + return SystemTimers::GetTicksPerSecond() / 975000 * Size; + break; + } + + case DVDLowClearCoverInterrupt: + // Less than ~1/155th of a second hangs Oregon Trail at "loading wheel". + // More than ~1/140th of a second hangs Resident Evil Archives: Resident Evil Zero. + return SystemTimers::GetTicksPerSecond() / 146; + break; + +// case DVDLowAudioBufferConfig: +// case DVDLowInquiry: +// case DVDLowReadDiskID: +// case DVDLowWaitForCoverClose: +// case DVDLowGetCoverReg: +// case DVDLowGetCoverStatus: +// case DVDLowReset: +// case DVDLowClosePartition: + default: + // ranom numbers here! + return SystemTimers::GetTicksPerSecond() / 1500; + break; + } +} diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp index a9d56cc16a..200642eccb 100644 --- a/Source/Core/Core/Src/State.cpp +++ b/Source/Core/Core/Src/State.cpp @@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 11; +static const u32 STATE_VERSION = 12; struct StateHeader {