diff options
| author | 2016-06-18 01:08:22 -0400 | |
|---|---|---|
| committer | 2016-06-18 01:08:22 -0400 | |
| commit | 8f86cc4df96c9a5bcac19130c800cc3cfe9b600a (patch) | |
| tree | 2270c49d792b157a654a216ab16682589b575486 | |
| parent | Merge pull request #1917 from lioncash/ci (diff) | |
| parent | Thread: update timeout when rerunning WaitSynch (diff) | |
| download | yuzu-8f86cc4df96c9a5bcac19130c800cc3cfe9b600a.tar.gz yuzu-8f86cc4df96c9a5bcac19130c800cc3cfe9b600a.tar.xz yuzu-8f86cc4df96c9a5bcac19130c800cc3cfe9b600a.zip | |
Merge pull request #1877 from wwylele/wait-fix-timeout
Thread: update timeout when reruning WaitSynch
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 3f6bec5fa..492c821e3 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -182,6 +182,48 @@ static void PriorityBoostStarvedThreads() { | |||
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | /** | 184 | /** |
| 185 | * Gets the registers for timeout parameter of the next WaitSynchronization call. | ||
| 186 | * @param thread a pointer to the thread that is ready to call WaitSynchronization | ||
| 187 | * @returns a tuple of two register pointers to low and high part of the timeout parameter | ||
| 188 | */ | ||
| 189 | static std::tuple<u32*, u32*> GetWaitSynchTimeoutParameterRegister(Thread* thread) { | ||
| 190 | bool thumb_mode = (thread->context.cpsr & TBIT) != 0; | ||
| 191 | u16 thumb_inst = Memory::Read16(thread->context.pc & 0xFFFFFFFE); | ||
| 192 | u32 inst = Memory::Read32(thread->context.pc & 0xFFFFFFFC) & 0x0FFFFFFF; | ||
| 193 | |||
| 194 | if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) { | ||
| 195 | // svc #0x24 (WaitSynchronization1) | ||
| 196 | return std::make_tuple(&thread->context.cpu_registers[2], &thread->context.cpu_registers[3]); | ||
| 197 | } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) { | ||
| 198 | // svc #0x25 (WaitSynchronizationN) | ||
| 199 | return std::make_tuple(&thread->context.cpu_registers[0], &thread->context.cpu_registers[4]); | ||
| 200 | } | ||
| 201 | |||
| 202 | UNREACHABLE(); | ||
| 203 | } | ||
| 204 | |||
| 205 | /** | ||
| 206 | * Updates the WaitSynchronization timeout paramter according to the difference | ||
| 207 | * between ticks of the last WaitSynchronization call and the incoming one. | ||
| 208 | * @param timeout_low a pointer to the register for the low part of the timeout parameter | ||
| 209 | * @param timeout_high a pointer to the register for the high part of the timeout parameter | ||
| 210 | * @param last_tick tick of the last WaitSynchronization call | ||
| 211 | */ | ||
| 212 | static void UpdateTimeoutParameter(u32* timeout_low, u32* timeout_high, u64 last_tick) { | ||
| 213 | s64 timeout = ((s64)*timeout_high << 32) | *timeout_low; | ||
| 214 | |||
| 215 | if (timeout != -1) { | ||
| 216 | timeout -= cyclesToUs(CoreTiming::GetTicks() - last_tick) * 1000; // in nanoseconds | ||
| 217 | |||
| 218 | if (timeout < 0) | ||
| 219 | timeout = 0; | ||
| 220 | |||
| 221 | *timeout_low = timeout & 0xFFFFFFFF; | ||
| 222 | *timeout_high = timeout >> 32; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | /** | ||
| 185 | * Switches the CPU's active thread context to that of the specified thread | 227 | * Switches the CPU's active thread context to that of the specified thread |
| 186 | * @param new_thread The thread to switch to | 228 | * @param new_thread The thread to switch to |
| 187 | */ | 229 | */ |
| @@ -219,6 +261,13 @@ static void SwitchContext(Thread* new_thread) { | |||
| 219 | 261 | ||
| 220 | // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM | 262 | // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM |
| 221 | new_thread->context.pc -= thumb_mode ? 2 : 4; | 263 | new_thread->context.pc -= thumb_mode ? 2 : 4; |
| 264 | |||
| 265 | // Get the register for timeout parameter | ||
| 266 | u32* timeout_low, *timeout_high; | ||
| 267 | std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread); | ||
| 268 | |||
| 269 | // Update the timeout parameter | ||
| 270 | UpdateTimeoutParameter(timeout_low, timeout_high, new_thread->last_running_ticks); | ||
| 222 | } | 271 | } |
| 223 | 272 | ||
| 224 | // Clean up the thread's wait_objects, they'll be restored if needed during | 273 | // Clean up the thread's wait_objects, they'll be restored if needed during |