Skip to content

Commit

Permalink
Merge pull request #1739 from JosJuice/wii-di-timing
Browse files Browse the repository at this point in the history
Accurate loading times for Wii games
  • Loading branch information
skidau committed Jan 2, 2015
2 parents 7dc6484 + 34a37cc commit 598dc03
Show file tree
Hide file tree
Showing 25 changed files with 267 additions and 310 deletions.
1 change: 1 addition & 0 deletions Source/Core/Core/HW/DVDInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,7 @@ DVDCommandResult ExecuteCommand(u32 command_0, u32 command_1, u32 command_2,

// 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.
// (Might not be true anymore since the other speeds were completely redone in December 2014)
result.ticks_until_completion = SystemTimers::GetTicksPerSecond() / 146;
break;

Expand Down
62 changes: 24 additions & 38 deletions Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ void DoState(PointerWrap &p)

void ExecuteCommand(u32 _Address)
{
bool CmdSuccess = false;
IPCCommandResult result = IPC_NO_REPLY;

IPCCommandType Command = static_cast<IPCCommandType>(Memory::Read_U32(_Address));
volatile s32 DeviceID = Memory::Read_U32(_Address + 8);
Expand Down Expand Up @@ -379,7 +379,7 @@ void ExecuteCommand(u32 _Address)
{
es_inuse[j] = true;
g_FdMap[DeviceID] = es_handles[j];
CmdSuccess = es_handles[j]->Open(_Address, Mode);
result = es_handles[j]->Open(_Address, Mode);
Memory::Write_U32(DeviceID, _Address+4);
break;
}
Expand All @@ -388,7 +388,7 @@ void ExecuteCommand(u32 _Address)
if (j == ES_MAX_COUNT)
{
Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4);
CmdSuccess = true;
result = IPC_DEFAULT_REPLY;
}
}
else if (DeviceName.find("/dev/") == 0)
Expand All @@ -397,7 +397,7 @@ void ExecuteCommand(u32 _Address)
if (pDevice)
{
g_FdMap[DeviceID] = pDevice;
CmdSuccess = pDevice->Open(_Address, Mode);
result = pDevice->Open(_Address, Mode);
INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
Memory::Write_U32(DeviceID, _Address+4);
Expand All @@ -406,13 +406,13 @@ void ExecuteCommand(u32 _Address)
{
WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
Memory::Write_U32(FS_ENOENT, _Address+4);
CmdSuccess = true;
result = IPC_DEFAULT_REPLY;
}
}
else
{
pDevice = CreateFileIO(DeviceID, DeviceName);
CmdSuccess = pDevice->Open(_Address, Mode);
result = pDevice->Open(_Address, Mode);

INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
Expand All @@ -430,15 +430,15 @@ void ExecuteCommand(u32 _Address)
else
{
Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4);
CmdSuccess = true;
result = IPC_DEFAULT_REPLY;
}
break;
}
case IPC_CMD_CLOSE:
{
if (pDevice)
{
CmdSuccess = pDevice->Close(_Address);
result = pDevice->Close(_Address);

for (u32 j=0; j<ES_MAX_COUNT; j++)
{
Expand All @@ -460,62 +460,62 @@ void ExecuteCommand(u32 _Address)
else
{
Memory::Write_U32(FS_EINVAL, _Address + 4);
CmdSuccess = true;
result = IPC_DEFAULT_REPLY;
}
break;
}
case IPC_CMD_READ:
{
if (pDevice)
{
CmdSuccess = pDevice->Read(_Address);
result = pDevice->Read(_Address);
}
else
{
Memory::Write_U32(FS_EINVAL, _Address + 4);
CmdSuccess = true;
result = IPC_DEFAULT_REPLY;
}
break;
}
case IPC_CMD_WRITE:
{
if (pDevice)
{
CmdSuccess = pDevice->Write(_Address);
result = pDevice->Write(_Address);
}
else
{
Memory::Write_U32(FS_EINVAL, _Address + 4);
CmdSuccess = true;
result = IPC_DEFAULT_REPLY;
}
break;
}
case IPC_CMD_SEEK:
{
if (pDevice)
{
CmdSuccess = pDevice->Seek(_Address);
result = pDevice->Seek(_Address);
}
else
{
Memory::Write_U32(FS_EINVAL, _Address + 4);
CmdSuccess = true;
result = IPC_DEFAULT_REPLY;
}
break;
}
case IPC_CMD_IOCTL:
{
if (pDevice)
{
CmdSuccess = pDevice->IOCtl(_Address);
result = pDevice->IOCtl(_Address);
}
break;
}
case IPC_CMD_IOCTLV:
{
if (pDevice)
{
CmdSuccess = pDevice->IOCtlV(_Address);
result = pDevice->IOCtlV(_Address);
}
break;
}
Expand All @@ -526,34 +526,20 @@ void ExecuteCommand(u32 _Address)
}
}

// Ensure replies happen in order
const s64 ticks_until_last_reply = last_reply_time - CoreTiming::GetTicks();
if (ticks_until_last_reply > 0)
result.reply_delay_ticks += ticks_until_last_reply;
last_reply_time = CoreTiming::GetTicks() + result.reply_delay_ticks;

if (CmdSuccess)
if (result.send_reply)
{
// The original hardware overwrites the command type with the async reply type.
Memory::Write_U32(IPC_REP_ASYNC, _Address);
// IOS also seems to write back the command that was responded to in the FD field.
Memory::Write_U32(Command, _Address + 8);

// Ensure replies happen in order, fairly ugly
// Without this, tons of games fail now that DI commands have different reply delays
int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;
if (!reply_delay)
{
int delay_us = 250;
reply_delay = SystemTimers::GetTicksPerSecond() / 1000000 * delay_us;
}

const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks();

if (ticks_til_last_reply > 0)
{
reply_delay = (int)ticks_til_last_reply;
}

last_reply_time = CoreTiming::GetTicks() + reply_delay;

// Generate a reply to the IPC command
EnqueueReply(_Address, reply_delay);
EnqueueReply(_Address, (int)result.reply_delay_ticks);
}
}

Expand Down
12 changes: 12 additions & 0 deletions Source/Core/Core/IPC_HLE/WII_IPC_HLE.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@

#include "Common/CommonTypes.h"

#include "Core/HW/SystemTimers.h"

class IWII_IPC_HLE_Device;
class PointerWrap;

struct IPCCommandResult
{
bool send_reply;
u64 reply_delay_ticks;
};

enum IPCCommandType : u32
{
IPC_CMD_OPEN = 1,
Expand All @@ -26,6 +34,10 @@ enum IPCCommandType : u32
IPC_REP_ASYNC = 8
};

static const u32 IPC_DEFAULT_DELAY = SystemTimers::GetTicksPerSecond() / 4000; // 250 us
static const IPCCommandResult IPC_NO_REPLY = { false, 0 };
static const IPCCommandResult IPC_DEFAULT_REPLY = { true, IPC_DEFAULT_DELAY };

namespace WII_IPC_HLE_Interface
{

Expand Down
41 changes: 20 additions & 21 deletions Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Common/StringUtil.h"

#include "Core/HW/Memmap.h"
#include "Core/IPC_HLE/WII_IPC_HLE.h"

#define FS_SUCCESS (u32)0 // Success
#define FS_EACCES (u32)-1 // Permission denied
Expand Down Expand Up @@ -119,39 +120,37 @@ class IWII_IPC_HLE_Device
const std::string& GetDeviceName() const { return m_Name; }
u32 GetDeviceID() const { return m_DeviceID; }

virtual bool Open(u32 _CommandAddress, u32 _Mode)
virtual IPCCommandResult Open(u32 _CommandAddress, u32 _Mode)
{
(void)_Mode;
WARN_LOG(WII_IPC_HLE, "%s does not support Open()", m_Name.c_str());
Memory::Write_U32(FS_ENOENT, _CommandAddress + 4);
m_Active = true;
return true;
return IPC_DEFAULT_REPLY;
}

virtual bool Close(u32 _CommandAddress, bool _bForce = false)
virtual IPCCommandResult Close(u32 _CommandAddress, bool _bForce = false)
{
WARN_LOG(WII_IPC_HLE, "%s does not support Close()", m_Name.c_str());
if (!_bForce)
Memory::Write_U32(FS_EINVAL, _CommandAddress + 4);
m_Active = false;
return true;
return IPC_DEFAULT_REPLY;
}

#define UNIMPLEMENTED_CMD(cmd) WARN_LOG(WII_IPC_HLE, "%s does not support "#cmd"()", m_Name.c_str()); return true;
virtual bool Seek (u32) { UNIMPLEMENTED_CMD(Seek) }
virtual bool Read (u32) { UNIMPLEMENTED_CMD(Read) }
virtual bool Write (u32) { UNIMPLEMENTED_CMD(Write) }
virtual bool IOCtl (u32) { UNIMPLEMENTED_CMD(IOCtl) }
virtual bool IOCtlV (u32) { UNIMPLEMENTED_CMD(IOCtlV) }
#define UNIMPLEMENTED_CMD(cmd) WARN_LOG(WII_IPC_HLE, "%s does not support "#cmd"()", m_Name.c_str()); return IPC_DEFAULT_REPLY;
virtual IPCCommandResult Seek(u32) { UNIMPLEMENTED_CMD(Seek) }
virtual IPCCommandResult Read(u32) { UNIMPLEMENTED_CMD(Read) }
virtual IPCCommandResult Write(u32) { UNIMPLEMENTED_CMD(Write) }
virtual IPCCommandResult IOCtl(u32) { UNIMPLEMENTED_CMD(IOCtl) }
virtual IPCCommandResult IOCtlV(u32) { UNIMPLEMENTED_CMD(IOCtlV) }
#undef UNIMPLEMENTED_CMD

virtual int GetCmdDelay(u32) { return 0; }

virtual u32 Update() { return 0; }

virtual bool IsHardware() { return m_Hardware; }
virtual bool IsOpened() { return m_Active; }
public:

std::string m_Name;
protected:

Expand Down Expand Up @@ -223,33 +222,33 @@ class CWII_IPC_HLE_Device_stub : public IWII_IPC_HLE_Device
{
}

bool Open(u32 CommandAddress, u32 Mode) override
IPCCommandResult Open(u32 CommandAddress, u32 Mode) override
{
(void)Mode;
WARN_LOG(WII_IPC_HLE, "%s faking Open()", m_Name.c_str());
Memory::Write_U32(GetDeviceID(), CommandAddress + 4);
m_Active = true;
return true;
return IPC_DEFAULT_REPLY;
}
bool Close(u32 CommandAddress, bool bForce = false) override
IPCCommandResult Close(u32 CommandAddress, bool bForce = false) override
{
WARN_LOG(WII_IPC_HLE, "%s faking Close()", m_Name.c_str());
if (!bForce)
Memory::Write_U32(FS_SUCCESS, CommandAddress + 4);
m_Active = false;
return true;
return IPC_DEFAULT_REPLY;
}

bool IOCtl(u32 CommandAddress) override
IPCCommandResult IOCtl(u32 CommandAddress) override
{
WARN_LOG(WII_IPC_HLE, "%s faking IOCtl()", m_Name.c_str());
Memory::Write_U32(FS_SUCCESS, CommandAddress + 4);
return true;
return IPC_DEFAULT_REPLY;
}
bool IOCtlV(u32 CommandAddress) override
IPCCommandResult IOCtlV(u32 CommandAddress) override
{
WARN_LOG(WII_IPC_HLE, "%s faking IOCtlV()", m_Name.c_str());
Memory::Write_U32(FS_SUCCESS, CommandAddress + 4);
return true;
return IPC_DEFAULT_REPLY;
}
};
Loading

0 comments on commit 598dc03

Please sign in to comment.