Core: Port Exclusive memory impl from yuzu
core\arm\dynarmic\arm_dynarmic.cpp: fix build core\arm\dynarmic\arm_dynarmic.cpp: Fixes CPP 20master
parent
98d3b9c776
commit
fbe06234b1
@ -0,0 +1,166 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
#include <intrin.h>
|
||||||
|
#else
|
||||||
|
#include <cstring>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||||
|
const u8 result =
|
||||||
|
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
|
||||||
|
return result == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||||
|
const u16 result =
|
||||||
|
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
|
||||||
|
return result == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||||
|
const u32 result =
|
||||||
|
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
|
||||||
|
return result == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||||
|
const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer),
|
||||||
|
value, expected);
|
||||||
|
return result == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||||
|
return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
|
||||||
|
value[0],
|
||||||
|
reinterpret_cast<__int64*>(expected.data())) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected,
|
||||||
|
u8& actual) {
|
||||||
|
actual =
|
||||||
|
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected,
|
||||||
|
u16& actual) {
|
||||||
|
actual =
|
||||||
|
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected,
|
||||||
|
u32& actual) {
|
||||||
|
actual =
|
||||||
|
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected,
|
||||||
|
u64& actual) {
|
||||||
|
actual = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer), value,
|
||||||
|
expected);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected,
|
||||||
|
u128& actual) {
|
||||||
|
const bool result =
|
||||||
|
_InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
|
||||||
|
value[0], reinterpret_cast<__int64*>(expected.data())) != 0;
|
||||||
|
actual = expected;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) {
|
||||||
|
u128 result{};
|
||||||
|
_InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), result[1],
|
||||||
|
result[0], reinterpret_cast<__int64*>(result.data()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||||
|
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||||
|
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||||
|
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||||
|
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||||
|
unsigned __int128 value_a;
|
||||||
|
unsigned __int128 expected_a;
|
||||||
|
std::memcpy(&value_a, value.data(), sizeof(u128));
|
||||||
|
std::memcpy(&expected_a, expected.data(), sizeof(u128));
|
||||||
|
return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected,
|
||||||
|
u8& actual) {
|
||||||
|
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected,
|
||||||
|
u16& actual) {
|
||||||
|
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected,
|
||||||
|
u32& actual) {
|
||||||
|
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected,
|
||||||
|
u64& actual) {
|
||||||
|
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||||
|
return actual == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected,
|
||||||
|
u128& actual) {
|
||||||
|
unsigned __int128 value_a;
|
||||||
|
unsigned __int128 expected_a;
|
||||||
|
unsigned __int128 actual_a;
|
||||||
|
std::memcpy(&value_a, value.data(), sizeof(u128));
|
||||||
|
std::memcpy(&expected_a, expected.data(), sizeof(u128));
|
||||||
|
actual_a = __sync_val_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
|
||||||
|
std::memcpy(actual.data(), &actual_a, sizeof(u128));
|
||||||
|
return actual_a == expected_a;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) {
|
||||||
|
unsigned __int128 zeros_a = 0;
|
||||||
|
unsigned __int128 result_a =
|
||||||
|
__sync_val_compare_and_swap((unsigned __int128*)pointer, zeros_a, zeros_a);
|
||||||
|
|
||||||
|
u128 result;
|
||||||
|
std::memcpy(result.data(), &result_a, sizeof(u128));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Common
|
@ -0,0 +1,58 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
|
||||||
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::MemorySystem& memory_, std::size_t core_count_)
|
||||||
|
: monitor{core_count_}, memory{memory_} {}
|
||||||
|
|
||||||
|
DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
|
||||||
|
|
||||||
|
u8 DynarmicExclusiveMonitor::ExclusiveRead8(std::size_t core_index, VAddr addr) {
|
||||||
|
return monitor.ReadAndMark<u8>(core_index, addr, [&]() -> u8 { return memory.Read8(addr); });
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 DynarmicExclusiveMonitor::ExclusiveRead16(std::size_t core_index, VAddr addr) {
|
||||||
|
return monitor.ReadAndMark<u16>(core_index, addr, [&]() -> u16 { return memory.Read16(addr); });
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 DynarmicExclusiveMonitor::ExclusiveRead32(std::size_t core_index, VAddr addr) {
|
||||||
|
return monitor.ReadAndMark<u32>(core_index, addr, [&]() -> u32 { return memory.Read32(addr); });
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 DynarmicExclusiveMonitor::ExclusiveRead64(std::size_t core_index, VAddr addr) {
|
||||||
|
return monitor.ReadAndMark<u64>(core_index, addr, [&]() -> u64 { return memory.Read64(addr); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynarmicExclusiveMonitor::ClearExclusive(std::size_t core_index) {
|
||||||
|
monitor.ClearProcessor(core_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
|
||||||
|
return monitor.DoExclusiveOperation<u8>(core_index, vaddr, [&](u8 expected) -> bool {
|
||||||
|
return memory.WriteExclusive8(vaddr, value, expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) {
|
||||||
|
return monitor.DoExclusiveOperation<u16>(core_index, vaddr, [&](u16 expected) -> bool {
|
||||||
|
return memory.WriteExclusive16(vaddr, value, expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) {
|
||||||
|
return monitor.DoExclusiveOperation<u32>(core_index, vaddr, [&](u32 expected) -> bool {
|
||||||
|
return memory.WriteExclusive32(vaddr, value, expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) {
|
||||||
|
return monitor.DoExclusiveOperation<u64>(core_index, vaddr, [&](u64 expected) -> bool {
|
||||||
|
return memory.WriteExclusive64(vaddr, value, expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core
|
@ -0,0 +1,40 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <dynarmic/interface/exclusive_monitor.h>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||||
|
#include "core/arm/exclusive_monitor.h"
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
|
||||||
|
public:
|
||||||
|
explicit DynarmicExclusiveMonitor( Memory::MemorySystem& memory_, std::size_t core_count_);
|
||||||
|
~DynarmicExclusiveMonitor() override;
|
||||||
|
|
||||||
|
u8 ExclusiveRead8(std::size_t core_index, VAddr addr) override;
|
||||||
|
u16 ExclusiveRead16(std::size_t core_index, VAddr addr) override;
|
||||||
|
u32 ExclusiveRead32(std::size_t core_index, VAddr addr) override;
|
||||||
|
u64 ExclusiveRead64(std::size_t core_index, VAddr addr) override;
|
||||||
|
void ClearExclusive(std::size_t core_index) override;
|
||||||
|
|
||||||
|
bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) override;
|
||||||
|
bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) override;
|
||||||
|
bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) override;
|
||||||
|
bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ::ARM_Dynarmic;
|
||||||
|
Dynarmic::ExclusiveMonitor monitor;
|
||||||
|
Memory::MemorySystem& memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core
|
@ -0,0 +1,26 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||||
|
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
|
||||||
|
#endif
|
||||||
|
#include "core/arm/exclusive_monitor.h"
|
||||||
|
#include "core/memory.h"
|
||||||
|
#include "core/settings.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
ExclusiveMonitor::~ExclusiveMonitor() = default;
|
||||||
|
|
||||||
|
std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::MemorySystem& memory,
|
||||||
|
std::size_t num_cores) {
|
||||||
|
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||||
|
if (Settings::values.use_cpu_jit) {
|
||||||
|
return std::make_unique<Core::DynarmicExclusiveMonitor>(memory, num_cores);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// TODO(merry): Passthrough exclusive monitor
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core
|
@ -0,0 +1,35 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
class ExclusiveMonitor {
|
||||||
|
public:
|
||||||
|
virtual ~ExclusiveMonitor();
|
||||||
|
|
||||||
|
virtual u8 ExclusiveRead8(std::size_t core_index, VAddr addr) = 0;
|
||||||
|
virtual u16 ExclusiveRead16(std::size_t core_index, VAddr addr) = 0;
|
||||||
|
virtual u32 ExclusiveRead32(std::size_t core_index, VAddr addr) = 0;
|
||||||
|
virtual u64 ExclusiveRead64(std::size_t core_index, VAddr addr) = 0;
|
||||||
|
virtual void ClearExclusive(std::size_t core_index) = 0;
|
||||||
|
|
||||||
|
virtual bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) = 0;
|
||||||
|
virtual bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) = 0;
|
||||||
|
virtual bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) = 0;
|
||||||
|
virtual bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::MemorySystem& memory,
|
||||||
|
std::size_t num_cores);
|
||||||
|
|
||||||
|
} // namespace Core
|
Loading…
Reference in New Issue