Merge A32 and A64 exclusive monitors
This commit is contained in:
parent
4b371c0445
commit
9f3277540a
10 changed files with 15 additions and 159 deletions
|
@ -10,13 +10,16 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
class ExclusiveMonitor;
|
||||||
|
} // namespace Dynarmic
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace A32 {
|
namespace A32 {
|
||||||
|
|
||||||
using VAddr = std::uint32_t;
|
using VAddr = std::uint32_t;
|
||||||
|
|
||||||
class Coprocessor;
|
class Coprocessor;
|
||||||
class ExclusiveMonitor;
|
|
||||||
|
|
||||||
enum class Exception {
|
enum class Exception {
|
||||||
/// An UndefinedFault occured due to executing instruction with an unallocated encoding
|
/// An UndefinedFault occured due to executing instruction with an unallocated encoding
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2018 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <array>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
|
||||||
namespace A32 {
|
|
||||||
|
|
||||||
using VAddr = std::uint32_t;
|
|
||||||
|
|
||||||
class ExclusiveMonitor {
|
|
||||||
public:
|
|
||||||
/// @param processor_count Maximum number of processors using this global
|
|
||||||
/// exclusive monitor. Each processor must have a
|
|
||||||
/// unique id.
|
|
||||||
explicit ExclusiveMonitor(size_t processor_count);
|
|
||||||
|
|
||||||
size_t GetProcessorCount() const;
|
|
||||||
|
|
||||||
/// Marks a region containing [address, address+size) to be exclusive to
|
|
||||||
/// processor processor_id.
|
|
||||||
template <typename T, typename Function>
|
|
||||||
T ReadAndMark(size_t processor_id, VAddr address, Function op) {
|
|
||||||
static_assert(std::is_trivially_copyable_v<T>);
|
|
||||||
const VAddr masked_address = address;
|
|
||||||
|
|
||||||
Lock();
|
|
||||||
exclusive_addresses[processor_id] = masked_address;
|
|
||||||
const T value = op();
|
|
||||||
std::memcpy(&exclusive_values[processor_id], &value, sizeof(T));
|
|
||||||
Unlock();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks to see if processor processor_id has exclusive access to the
|
|
||||||
/// specified region. If it does, executes the operation then clears
|
|
||||||
/// the exclusive state for processors if their exclusive region(s)
|
|
||||||
/// contain [address, address+size).
|
|
||||||
template <typename T, typename Function>
|
|
||||||
bool DoExclusiveOperation(size_t processor_id, VAddr address, Function op) {
|
|
||||||
static_assert(std::is_trivially_copyable_v<T>);
|
|
||||||
if (!CheckAndClear(processor_id, address)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
T saved_value;
|
|
||||||
std::memcpy(&saved_value, &exclusive_values[processor_id], sizeof(T));
|
|
||||||
const bool result = op(saved_value);
|
|
||||||
|
|
||||||
Unlock();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unmark everything.
|
|
||||||
void Clear();
|
|
||||||
/// Unmark processor id
|
|
||||||
void ClearProcessor(size_t processor_id);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool CheckAndClear(size_t processor_id, VAddr address);
|
|
||||||
|
|
||||||
void Lock();
|
|
||||||
void Unlock();
|
|
||||||
|
|
||||||
static constexpr VAddr INVALID_EXCLUSIVE_ADDRESS = 0xDEADDEAD;
|
|
||||||
std::atomic_flag is_locked;
|
|
||||||
std::vector<VAddr> exclusive_addresses;
|
|
||||||
std::vector<std::uint64_t> exclusive_values;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace A32
|
|
||||||
} // namespace Dynarmic
|
|
|
@ -10,6 +10,10 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
class ExclusiveMonitor;
|
||||||
|
} // namespace Dynarmic
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace A64 {
|
namespace A64 {
|
||||||
|
|
||||||
|
@ -114,8 +118,6 @@ struct UserCallbacks {
|
||||||
virtual std::uint64_t GetCNTPCT() = 0;
|
virtual std::uint64_t GetCNTPCT() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExclusiveMonitor;
|
|
||||||
|
|
||||||
struct UserConfig {
|
struct UserConfig {
|
||||||
UserCallbacks* callbacks;
|
UserCallbacks* callbacks;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace A64 {
|
|
||||||
|
|
||||||
using VAddr = std::uint64_t;
|
using VAddr = std::uint64_t;
|
||||||
using Vector = std::array<std::uint64_t, 2>;
|
using Vector = std::array<std::uint64_t, 2>;
|
||||||
|
@ -79,5 +78,4 @@ private:
|
||||||
std::vector<Vector> exclusive_values;
|
std::vector<Vector> exclusive_values;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace A64
|
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -6,7 +6,7 @@ add_library(dynarmic
|
||||||
../include/dynarmic/A32/disassembler.h
|
../include/dynarmic/A32/disassembler.h
|
||||||
../include/dynarmic/A64/a64.h
|
../include/dynarmic/A64/a64.h
|
||||||
../include/dynarmic/A64/config.h
|
../include/dynarmic/A64/config.h
|
||||||
../include/dynarmic/A64/exclusive_monitor.h
|
../include/dynarmic/exclusive_monitor.h
|
||||||
common/assert.cpp
|
common/assert.cpp
|
||||||
common/assert.h
|
common/assert.h
|
||||||
common/bit_util.h
|
common/bit_util.h
|
||||||
|
@ -259,6 +259,7 @@ if (ARCHITECTURE_x86_64)
|
||||||
backend/x64/emit_x64_vector_floating_point.cpp
|
backend/x64/emit_x64_vector_floating_point.cpp
|
||||||
backend/x64/emit_x64_vector_saturation.cpp
|
backend/x64/emit_x64_vector_saturation.cpp
|
||||||
backend/x64/exception_handler.h
|
backend/x64/exception_handler.h
|
||||||
|
backend/x64/exclusive_monitor.cpp
|
||||||
backend/x64/hostloc.cpp
|
backend/x64/hostloc.cpp
|
||||||
backend/x64/hostloc.h
|
backend/x64/hostloc.h
|
||||||
backend/x64/jitstate_info.h
|
backend/x64/jitstate_info.h
|
||||||
|
@ -273,7 +274,6 @@ if (ARCHITECTURE_x86_64)
|
||||||
target_sources(dynarmic PRIVATE
|
target_sources(dynarmic PRIVATE
|
||||||
backend/x64/a32_emit_x64.cpp
|
backend/x64/a32_emit_x64.cpp
|
||||||
backend/x64/a32_emit_x64.h
|
backend/x64/a32_emit_x64.h
|
||||||
backend/x64/a32_exclusive_monitor.cpp
|
|
||||||
backend/x64/a32_interface.cpp
|
backend/x64/a32_interface.cpp
|
||||||
backend/x64/a32_jitstate.cpp
|
backend/x64/a32_jitstate.cpp
|
||||||
backend/x64/a32_jitstate.h
|
backend/x64/a32_jitstate.h
|
||||||
|
@ -284,7 +284,6 @@ if (ARCHITECTURE_x86_64)
|
||||||
target_sources(dynarmic PRIVATE
|
target_sources(dynarmic PRIVATE
|
||||||
backend/x64/a64_emit_x64.cpp
|
backend/x64/a64_emit_x64.cpp
|
||||||
backend/x64/a64_emit_x64.h
|
backend/x64/a64_emit_x64.h
|
||||||
backend/x64/a64_exclusive_monitor.cpp
|
|
||||||
backend/x64/a64_interface.cpp
|
backend/x64/a64_interface.cpp
|
||||||
backend/x64/a64_jitstate.cpp
|
backend/x64/a64_jitstate.cpp
|
||||||
backend/x64/a64_jitstate.h
|
backend/x64/a64_jitstate.h
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include <mp/traits/integer_of_size.h>
|
#include <mp/traits/integer_of_size.h>
|
||||||
|
|
||||||
#include <dynarmic/A32/coprocessor.h>
|
#include <dynarmic/A32/coprocessor.h>
|
||||||
#include <dynarmic/A32/exclusive_monitor.h>
|
#include <dynarmic/exclusive_monitor.h>
|
||||||
|
|
||||||
#include "backend/x64/a32_emit_x64.h"
|
#include "backend/x64/a32_emit_x64.h"
|
||||||
#include "backend/x64/a32_jitstate.h"
|
#include "backend/x64/a32_jitstate.h"
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2018 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <dynarmic/A32/exclusive_monitor.h>
|
|
||||||
#include "common/assert.h"
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
|
||||||
namespace A32 {
|
|
||||||
|
|
||||||
ExclusiveMonitor::ExclusiveMonitor(size_t processor_count) :
|
|
||||||
exclusive_addresses(processor_count, INVALID_EXCLUSIVE_ADDRESS), exclusive_values(processor_count) {
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ExclusiveMonitor::GetProcessorCount() const {
|
|
||||||
return exclusive_addresses.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::Lock() {
|
|
||||||
while (is_locked.test_and_set(std::memory_order_acquire)) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::Unlock() {
|
|
||||||
is_locked.clear(std::memory_order_release);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ExclusiveMonitor::CheckAndClear(size_t processor_id, VAddr address) {
|
|
||||||
const VAddr masked_address = address;
|
|
||||||
|
|
||||||
Lock();
|
|
||||||
if (exclusive_addresses[processor_id] != masked_address) {
|
|
||||||
Unlock();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (VAddr& other_address : exclusive_addresses) {
|
|
||||||
if (other_address == masked_address) {
|
|
||||||
other_address = INVALID_EXCLUSIVE_ADDRESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::Clear() {
|
|
||||||
Lock();
|
|
||||||
std::fill(exclusive_addresses.begin(), exclusive_addresses.end(), INVALID_EXCLUSIVE_ADDRESS);
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::ClearProcessor(size_t processor_id) {
|
|
||||||
Lock();
|
|
||||||
exclusive_addresses[processor_id] = INVALID_EXCLUSIVE_ADDRESS;
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace A32
|
|
||||||
} // namespace Dynarmic
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <fmt/ostream.h>
|
#include <fmt/ostream.h>
|
||||||
#include <mp/traits/integer_of_size.h>
|
#include <mp/traits/integer_of_size.h>
|
||||||
|
|
||||||
#include <dynarmic/A64/exclusive_monitor.h>
|
#include <dynarmic/exclusive_monitor.h>
|
||||||
|
|
||||||
#include "backend/x64/a64_emit_x64.h"
|
#include "backend/x64/a64_emit_x64.h"
|
||||||
#include "backend/x64/a64_jitstate.h"
|
#include "backend/x64/a64_jitstate.h"
|
||||||
|
|
|
@ -5,11 +5,10 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <dynarmic/A64/exclusive_monitor.h>
|
#include <dynarmic/exclusive_monitor.h>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace A64 {
|
|
||||||
|
|
||||||
ExclusiveMonitor::ExclusiveMonitor(size_t processor_count) :
|
ExclusiveMonitor::ExclusiveMonitor(size_t processor_count) :
|
||||||
exclusive_addresses(processor_count, INVALID_EXCLUSIVE_ADDRESS), exclusive_values(processor_count) {
|
exclusive_addresses(processor_count, INVALID_EXCLUSIVE_ADDRESS), exclusive_values(processor_count) {
|
||||||
|
@ -57,6 +56,4 @@ void ExclusiveMonitor::ClearProcessor(size_t processor_id) {
|
||||||
Unlock();
|
Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace A64
|
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include <catch.hpp>
|
#include <catch.hpp>
|
||||||
|
|
||||||
#include <dynarmic/A64/exclusive_monitor.h>
|
#include <dynarmic/exclusive_monitor.h>
|
||||||
|
|
||||||
#include "common/fp/fpsr.h"
|
#include "common/fp/fpsr.h"
|
||||||
#include "testenv.h"
|
#include "testenv.h"
|
||||||
|
@ -281,7 +281,7 @@ TEST_CASE("A64: FABD", "[a64]") {
|
||||||
|
|
||||||
TEST_CASE("A64: 128-bit exclusive read/write", "[a64]") {
|
TEST_CASE("A64: 128-bit exclusive read/write", "[a64]") {
|
||||||
A64TestEnv env;
|
A64TestEnv env;
|
||||||
Dynarmic::A64::ExclusiveMonitor monitor{1};
|
Dynarmic::ExclusiveMonitor monitor{1};
|
||||||
|
|
||||||
Dynarmic::A64::UserConfig conf;
|
Dynarmic::A64::UserConfig conf;
|
||||||
conf.callbacks = &env;
|
conf.callbacks = &env;
|
||||||
|
|
Loading…
Reference in a new issue