mirror of
https://github.com/citra-emu/citra.git
synced 2024-12-19 15:21:05 +00:00
Merge pull request #1300 from Subv/arbitrateaddress
SVC: Fixed ArbitrateAddress to behave as it does on hardware.
This commit is contained in:
commit
73740d74ed
@ -45,30 +45,32 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
|
|||||||
|
|
||||||
// Wait current thread (acquire the arbiter)...
|
// Wait current thread (acquire the arbiter)...
|
||||||
case ArbitrationType::WaitIfLessThan:
|
case ArbitrationType::WaitIfLessThan:
|
||||||
if ((s32)Memory::Read32(address) <= value) {
|
if ((s32)Memory::Read32(address) < value) {
|
||||||
Kernel::WaitCurrentThread_ArbitrateAddress(address);
|
Kernel::WaitCurrentThread_ArbitrateAddress(address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ArbitrationType::WaitIfLessThanWithTimeout:
|
case ArbitrationType::WaitIfLessThanWithTimeout:
|
||||||
if ((s32)Memory::Read32(address) <= value) {
|
if ((s32)Memory::Read32(address) < value) {
|
||||||
Kernel::WaitCurrentThread_ArbitrateAddress(address);
|
Kernel::WaitCurrentThread_ArbitrateAddress(address);
|
||||||
GetCurrentThread()->WakeAfterDelay(nanoseconds);
|
GetCurrentThread()->WakeAfterDelay(nanoseconds);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ArbitrationType::DecrementAndWaitIfLessThan:
|
case ArbitrationType::DecrementAndWaitIfLessThan:
|
||||||
{
|
{
|
||||||
s32 memory_value = Memory::Read32(address) - 1;
|
s32 memory_value = Memory::Read32(address);
|
||||||
Memory::Write32(address, memory_value);
|
if (memory_value < value) {
|
||||||
if (memory_value <= value) {
|
// Only change the memory value if the thread should wait
|
||||||
|
Memory::Write32(address, (s32)memory_value - 1);
|
||||||
Kernel::WaitCurrentThread_ArbitrateAddress(address);
|
Kernel::WaitCurrentThread_ArbitrateAddress(address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout:
|
case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout:
|
||||||
{
|
{
|
||||||
s32 memory_value = Memory::Read32(address) - 1;
|
s32 memory_value = Memory::Read32(address);
|
||||||
Memory::Write32(address, memory_value);
|
if (memory_value < value) {
|
||||||
if (memory_value <= value) {
|
// Only change the memory value if the thread should wait
|
||||||
|
Memory::Write32(address, (s32)memory_value - 1);
|
||||||
Kernel::WaitCurrentThread_ArbitrateAddress(address);
|
Kernel::WaitCurrentThread_ArbitrateAddress(address);
|
||||||
GetCurrentThread()->WakeAfterDelay(nanoseconds);
|
GetCurrentThread()->WakeAfterDelay(nanoseconds);
|
||||||
}
|
}
|
||||||
@ -82,6 +84,13 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
|
|||||||
|
|
||||||
HLE::Reschedule(__func__);
|
HLE::Reschedule(__func__);
|
||||||
|
|
||||||
|
// The calls that use a timeout seem to always return a Timeout error even if they did not put the thread to sleep
|
||||||
|
if (type == ArbitrationType::WaitIfLessThanWithTimeout ||
|
||||||
|
type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) {
|
||||||
|
|
||||||
|
return ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
|
||||||
|
ErrorSummary::StatusChanged, ErrorLevel::Info);
|
||||||
|
}
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
|
|||||||
|
|
||||||
thread->waitsynch_waited = false;
|
thread->waitsynch_waited = false;
|
||||||
|
|
||||||
if (thread->status == THREADSTATUS_WAIT_SYNCH) {
|
if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) {
|
||||||
thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
|
thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
|
||||||
ErrorSummary::StatusChanged, ErrorLevel::Info));
|
ErrorSummary::StatusChanged, ErrorLevel::Info));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user