summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/HW/WII_IPC.cpp8
-rw-r--r--Source/Core/Core/IOS/Device.cpp12
-rw-r--r--Source/Core/Core/IOS/IOS.cpp17
3 files changed, 28 insertions, 9 deletions
diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp
index 1e190f9ac0..ca5b15d7bf 100644
--- a/Source/Core/Core/HW/WII_IPC.cpp
+++ b/Source/Core/Core/HW/WII_IPC.cpp
@@ -213,7 +213,9 @@ void GenerateAck(u32 _Address)
ctrl.Y2 = 1;
DEBUG_LOG(WII_IPC, "GenerateAck: %08x | %08x [R:%i A:%i E:%i]", ppc_msg, _Address, ctrl.Y1,
ctrl.Y2, ctrl.X1);
- CoreTiming::ScheduleEvent(1000, updateInterrupts, 0);
+ // Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire
+ // after Y2 is seen in the control register.
+ CoreTiming::ScheduleEvent(100 * SystemTimers::TIMER_RATIO, updateInterrupts);
}
void GenerateReply(u32 _Address)
@@ -222,7 +224,9 @@ void GenerateReply(u32 _Address)
ctrl.Y1 = 1;
DEBUG_LOG(WII_IPC, "GenerateReply: %08x | %08x [R:%i A:%i E:%i]", ppc_msg, _Address, ctrl.Y1,
ctrl.Y2, ctrl.X1);
- UpdateInterrupts();
+ // Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire
+ // after Y1 is seen in the control register.
+ CoreTiming::ScheduleEvent(100 * SystemTimers::TIMER_RATIO, updateInterrupts);
}
bool IsReady()
diff --git a/Source/Core/Core/IOS/Device.cpp b/Source/Core/Core/IOS/Device.cpp
index b0301205aa..d14c8cf06a 100644
--- a/Source/Core/Core/IOS/Device.cpp
+++ b/Source/Core/Core/IOS/Device.cpp
@@ -184,10 +184,18 @@ IPCCommandResult Device::Unsupported(const Request& request)
return GetDefaultReply(IPC_EINVAL);
}
-// Returns an IPCCommandResult for a reply that takes 25 us (based on ES::GetTicketViews)
+// Returns an IPCCommandResult for a reply with an average reply time for devices
+// Please avoid using this function if more accurate timings are known.
IPCCommandResult Device::GetDefaultReply(const s32 return_value)
{
- return {return_value, true, SystemTimers::GetTicksPerSecond() / 40000};
+ // Based on a hardware test, a device takes at least ~2700 ticks to reply to an IPC request.
+ // Depending on how much work a command performs, this can take much longer (10000+)
+ // especially if the NAND filesystem is accessed.
+ //
+ // Because we currently don't emulate timing very accurately, we should not return
+ // the minimum possible reply time (~960 ticks from the kernel or ~2700 from devices)
+ // but an average time, otherwise we are going to be much too fast in most cases.
+ return {return_value, true, 4000 * SystemTimers::TIMER_RATIO};
}
// Returns an IPCCommandResult with no reply. Useful for async commands that will generate a reply
diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp
index 975bdd8268..dda0ac955f 100644
--- a/Source/Core/Core/IOS/IOS.cpp
+++ b/Source/Core/Core/IOS/IOS.cpp
@@ -475,7 +475,7 @@ IPCCommandResult Kernel::OpenDevice(OpenRequest& request)
if (new_fd < 0 || new_fd >= IPC_MAX_FDS)
{
ERROR_LOG(IOS, "Couldn't get a free fd, too many open files");
- return Device::Device::GetDefaultReply(FS_EFDEXHAUSTED);
+ return IPCCommandResult{FS_EFDEXHAUSTED, true, 5000 * SystemTimers::TIMER_RATIO};
}
request.fd = new_fd;
@@ -497,7 +497,7 @@ IPCCommandResult Kernel::OpenDevice(OpenRequest& request)
if (!device)
{
ERROR_LOG(IOS, "Unknown device: %s", request.path.c_str());
- return Device::Device::GetDefaultReply(IPC_ENOENT);
+ return {IPC_ENOENT, true, 3700 * SystemTimers::TIMER_RATIO};
}
IPCCommandResult result = device->Open(request);
@@ -511,6 +511,9 @@ IPCCommandResult Kernel::OpenDevice(OpenRequest& request)
IPCCommandResult Kernel::HandleIPCCommand(const Request& request)
{
+ if (request.command < IPC_CMD_OPEN || request.command > IPC_CMD_IOCTLV)
+ return IPCCommandResult{IPC_EINVAL, true, 978 * SystemTimers::TIMER_RATIO};
+
if (request.command == IPC_CMD_OPEN)
{
OpenRequest open_request{request.address};
@@ -519,7 +522,7 @@ IPCCommandResult Kernel::HandleIPCCommand(const Request& request)
const auto device = (request.fd < IPC_MAX_FDS) ? m_fdmap[request.fd] : nullptr;
if (!device)
- return Device::Device::GetDefaultReply(IPC_EINVAL);
+ return IPCCommandResult{IPC_EINVAL, true, 550 * SystemTimers::TIMER_RATIO};
IPCCommandResult ret;
u64 wall_time_before = Common::Timer::GetTimeUs();
@@ -547,7 +550,7 @@ IPCCommandResult Kernel::HandleIPCCommand(const Request& request)
break;
default:
ASSERT_MSG(IOS, false, "Unexpected command: %x", request.command);
- ret = Device::Device::GetDefaultReply(IPC_EINVAL);
+ ret = IPCCommandResult{IPC_EINVAL, true, 978 * SystemTimers::TIMER_RATIO};
break;
}
@@ -582,7 +585,11 @@ void Kernel::ExecuteIPCCommand(const u32 address)
// Happens AS SOON AS IPC gets a new pointer!
void Kernel::EnqueueIPCRequest(u32 address)
{
- CoreTiming::ScheduleEvent(1000, s_event_enqueue, address | ENQUEUE_REQUEST_FLAG);
+ // Based on hardware tests, IOS takes between 5µs and 10µs to acknowledge an IPC request.
+ // Console 1: 456 TB ticks before ACK
+ // Console 2: 658 TB ticks before ACK
+ CoreTiming::ScheduleEvent(500 * SystemTimers::TIMER_RATIO, s_event_enqueue,
+ address | ENQUEUE_REQUEST_FLAG);
}
// Called to send a reply to an IOS syscall