A32 global exlcusive monitor

This commit is contained in:
MerryMage 2020-06-16 15:46:47 +01:00
parent 58abdcce5b
commit 2c1a4843ad
12 changed files with 260 additions and 56 deletions

View file

@ -16,6 +16,7 @@ namespace A32 {
using VAddr = std::uint32_t;
class Coprocessor;
class ExclusiveMonitor;
enum class Exception {
/// An UndefinedFault occured due to executing instruction with an unallocated encoding
@ -62,6 +63,12 @@ struct UserCallbacks {
virtual void MemoryWrite32(VAddr vaddr, std::uint32_t value) = 0;
virtual void MemoryWrite64(VAddr vaddr, std::uint64_t value) = 0;
// Writes through these callbacks may not be aligned.
virtual bool MemoryWriteExclusive8(VAddr /*vaddr*/, std::uint8_t /*value*/, std::uint8_t /*expected*/) { return false; }
virtual bool MemoryWriteExclusive16(VAddr /*vaddr*/, std::uint16_t /*value*/, std::uint16_t /*expected*/) { return false; }
virtual bool MemoryWriteExclusive32(VAddr /*vaddr*/, std::uint32_t /*value*/, std::uint32_t /*expected*/) { return false; }
virtual bool MemoryWriteExclusive64(VAddr /*vaddr*/, std::uint64_t /*value*/, std::uint64_t /*expected*/) { return false; }
// If this callback returns true, the JIT will assume MemoryRead* callbacks will always
// return the same value at any point in time for this vaddr. The JIT may use this information
// in optimizations.
@ -86,6 +93,9 @@ struct UserCallbacks {
struct UserConfig {
UserCallbacks* callbacks;
size_t processor_id = 0;
ExclusiveMonitor* global_monitor = nullptr;
/// When set to false, this disables all optimizations than can't otherwise be disabled
/// by setting other configuration options. This includes:
/// - IR optimizations

View file

@ -0,0 +1,81 @@
/* 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