commit
5fc99553d2
|
@ -1,5 +1,7 @@
|
||||||
add_library(core STATIC
|
add_library(core STATIC
|
||||||
arm/arm_interface.h
|
arm/arm_interface.h
|
||||||
|
arm/exclusive_monitor.cpp
|
||||||
|
arm/exclusive_monitor.h
|
||||||
arm/unicorn/arm_unicorn.cpp
|
arm/unicorn/arm_unicorn.cpp
|
||||||
arm/unicorn/arm_unicorn.h
|
arm/unicorn/arm_unicorn.h
|
||||||
core.cpp
|
core.cpp
|
||||||
|
|
|
@ -102,18 +102,28 @@ public:
|
||||||
u64 tpidr_el0 = 0;
|
u64 tpidr_el0 = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Dynarmic::A64::Jit> MakeJit(const std::unique_ptr<ARM_Dynarmic_Callbacks>& cb) {
|
std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() {
|
||||||
const auto page_table = Core::CurrentProcess()->vm_manager.page_table.pointers.data();
|
const auto page_table = Core::CurrentProcess()->vm_manager.page_table.pointers.data();
|
||||||
|
|
||||||
Dynarmic::A64::UserConfig config;
|
Dynarmic::A64::UserConfig config;
|
||||||
|
|
||||||
|
// Callbacks
|
||||||
config.callbacks = cb.get();
|
config.callbacks = cb.get();
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
config.page_table = reinterpret_cast<void**>(page_table);
|
||||||
|
config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS;
|
||||||
|
config.silently_mirror_page_table = false;
|
||||||
|
|
||||||
|
// Multi-process state
|
||||||
|
config.processor_id = core_index;
|
||||||
|
config.global_monitor = &exclusive_monitor->monitor;
|
||||||
|
|
||||||
|
// System registers
|
||||||
config.tpidrro_el0 = &cb->tpidrro_el0;
|
config.tpidrro_el0 = &cb->tpidrro_el0;
|
||||||
config.tpidr_el0 = &cb->tpidr_el0;
|
config.tpidr_el0 = &cb->tpidr_el0;
|
||||||
config.dczid_el0 = 4;
|
config.dczid_el0 = 4;
|
||||||
config.ctr_el0 = 0x8444c004;
|
config.ctr_el0 = 0x8444c004;
|
||||||
config.page_table = reinterpret_cast<void**>(page_table);
|
|
||||||
config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS;
|
|
||||||
config.silently_mirror_page_table = false;
|
|
||||||
|
|
||||||
return std::make_unique<Dynarmic::A64::Jit>(config);
|
return std::make_unique<Dynarmic::A64::Jit>(config);
|
||||||
}
|
}
|
||||||
|
@ -128,8 +138,11 @@ void ARM_Dynarmic::Step() {
|
||||||
cb->InterpreterFallback(jit->GetPC(), 1);
|
cb->InterpreterFallback(jit->GetPC(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ARM_Dynarmic::ARM_Dynarmic()
|
ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index)
|
||||||
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), jit(MakeJit(cb)) {
|
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)),
|
||||||
|
jit(MakeJit()), exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(
|
||||||
|
exclusive_monitor)},
|
||||||
|
core_index{core_index} {
|
||||||
ARM_Interface::ThreadContext ctx;
|
ARM_Interface::ThreadContext ctx;
|
||||||
inner_unicorn.SaveContext(ctx);
|
inner_unicorn.SaveContext(ctx);
|
||||||
LoadContext(ctx);
|
LoadContext(ctx);
|
||||||
|
@ -237,6 +250,46 @@ void ARM_Dynarmic::ClearExclusiveState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic::PageTableChanged() {
|
void ARM_Dynarmic::PageTableChanged() {
|
||||||
jit = MakeJit(cb);
|
jit = MakeJit();
|
||||||
current_page_table = Memory::GetCurrentPageTable();
|
current_page_table = Memory::GetCurrentPageTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(size_t core_count) : monitor(core_count) {}
|
||||||
|
DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
|
||||||
|
|
||||||
|
void DynarmicExclusiveMonitor::SetExclusive(size_t core_index, u64 addr) {
|
||||||
|
// Size doesn't actually matter.
|
||||||
|
monitor.Mark(core_index, addr, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynarmicExclusiveMonitor::ClearExclusive() {
|
||||||
|
monitor.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite8(size_t core_index, u64 vaddr, u8 value) {
|
||||||
|
return monitor.DoExclusiveOperation(core_index, vaddr, 1,
|
||||||
|
[&] { Memory::Write8(vaddr, value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite16(size_t core_index, u64 vaddr, u16 value) {
|
||||||
|
return monitor.DoExclusiveOperation(core_index, vaddr, 2,
|
||||||
|
[&] { Memory::Write16(vaddr, value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite32(size_t core_index, u64 vaddr, u32 value) {
|
||||||
|
return monitor.DoExclusiveOperation(core_index, vaddr, 4,
|
||||||
|
[&] { Memory::Write32(vaddr, value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite64(size_t core_index, u64 vaddr, u64 value) {
|
||||||
|
return monitor.DoExclusiveOperation(core_index, vaddr, 8,
|
||||||
|
[&] { Memory::Write64(vaddr, value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynarmicExclusiveMonitor::ExclusiveWrite128(size_t core_index, u64 vaddr,
|
||||||
|
std::array<std::uint64_t, 2> value) {
|
||||||
|
return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] {
|
||||||
|
Memory::Write64(vaddr, value[0]);
|
||||||
|
Memory::Write64(vaddr, value[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -6,15 +6,18 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <dynarmic/A64/a64.h>
|
#include <dynarmic/A64/a64.h>
|
||||||
|
#include <dynarmic/A64/exclusive_monitor.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
|
#include "core/arm/exclusive_monitor.h"
|
||||||
#include "core/arm/unicorn/arm_unicorn.h"
|
#include "core/arm/unicorn/arm_unicorn.h"
|
||||||
|
|
||||||
class ARM_Dynarmic_Callbacks;
|
class ARM_Dynarmic_Callbacks;
|
||||||
|
class DynarmicExclusiveMonitor;
|
||||||
|
|
||||||
class ARM_Dynarmic final : public ARM_Interface {
|
class ARM_Dynarmic final : public ARM_Interface {
|
||||||
public:
|
public:
|
||||||
ARM_Dynarmic();
|
ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index);
|
||||||
~ARM_Dynarmic();
|
~ARM_Dynarmic();
|
||||||
|
|
||||||
void MapBackingMemory(VAddr address, size_t size, u8* memory,
|
void MapBackingMemory(VAddr address, size_t size, u8* memory,
|
||||||
|
@ -47,10 +50,35 @@ public:
|
||||||
void PageTableChanged() override;
|
void PageTableChanged() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::unique_ptr<Dynarmic::A64::Jit> MakeJit();
|
||||||
|
|
||||||
friend class ARM_Dynarmic_Callbacks;
|
friend class ARM_Dynarmic_Callbacks;
|
||||||
std::unique_ptr<ARM_Dynarmic_Callbacks> cb;
|
std::unique_ptr<ARM_Dynarmic_Callbacks> cb;
|
||||||
std::unique_ptr<Dynarmic::A64::Jit> jit;
|
std::unique_ptr<Dynarmic::A64::Jit> jit;
|
||||||
ARM_Unicorn inner_unicorn;
|
ARM_Unicorn inner_unicorn;
|
||||||
|
|
||||||
|
size_t core_index;
|
||||||
|
std::shared_ptr<DynarmicExclusiveMonitor> exclusive_monitor;
|
||||||
|
|
||||||
Memory::PageTable* current_page_table = nullptr;
|
Memory::PageTable* current_page_table = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
|
||||||
|
public:
|
||||||
|
explicit DynarmicExclusiveMonitor(size_t core_count);
|
||||||
|
~DynarmicExclusiveMonitor();
|
||||||
|
|
||||||
|
void SetExclusive(size_t core_index, u64 addr) override;
|
||||||
|
void ClearExclusive() override;
|
||||||
|
|
||||||
|
bool ExclusiveWrite8(size_t core_index, u64 vaddr, u8 value) override;
|
||||||
|
bool ExclusiveWrite16(size_t core_index, u64 vaddr, u16 value) override;
|
||||||
|
bool ExclusiveWrite32(size_t core_index, u64 vaddr, u32 value) override;
|
||||||
|
bool ExclusiveWrite64(size_t core_index, u64 vaddr, u64 value) override;
|
||||||
|
bool ExclusiveWrite128(size_t core_index, u64 vaddr,
|
||||||
|
std::array<std::uint64_t, 2> value) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ARM_Dynarmic;
|
||||||
|
Dynarmic::A64::ExclusiveMonitor monitor;
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Copyright 2018 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/arm/exclusive_monitor.h"
|
||||||
|
|
||||||
|
ExclusiveMonitor::~ExclusiveMonitor() = default;
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2018 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
class ExclusiveMonitor {
|
||||||
|
public:
|
||||||
|
virtual ~ExclusiveMonitor();
|
||||||
|
|
||||||
|
virtual void SetExclusive(size_t core_index, u64 addr) = 0;
|
||||||
|
virtual void ClearExclusive() = 0;
|
||||||
|
|
||||||
|
virtual bool ExclusiveWrite8(size_t core_index, u64 vaddr, u8 value) = 0;
|
||||||
|
virtual bool ExclusiveWrite16(size_t core_index, u64 vaddr, u16 value) = 0;
|
||||||
|
virtual bool ExclusiveWrite32(size_t core_index, u64 vaddr, u32 value) = 0;
|
||||||
|
virtual bool ExclusiveWrite64(size_t core_index, u64 vaddr, u64 value) = 0;
|
||||||
|
virtual bool ExclusiveWrite128(size_t core_index, u64 vaddr,
|
||||||
|
std::array<std::uint64_t, 2> value) = 0;
|
||||||
|
};
|
|
@ -171,8 +171,9 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
|
||||||
current_process = Kernel::Process::Create("main");
|
current_process = Kernel::Process::Create("main");
|
||||||
|
|
||||||
cpu_barrier = std::make_shared<CpuBarrier>();
|
cpu_barrier = std::make_shared<CpuBarrier>();
|
||||||
|
cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
|
||||||
for (size_t index = 0; index < cpu_cores.size(); ++index) {
|
for (size_t index = 0; index < cpu_cores.size(); ++index) {
|
||||||
cpu_cores[index] = std::make_shared<Cpu>(cpu_barrier, index);
|
cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu_core = std::make_unique<Tegra::GPU>();
|
gpu_core = std::make_unique<Tegra::GPU>();
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/arm/exclusive_monitor.h"
|
||||||
#include "core/core_cpu.h"
|
#include "core/core_cpu.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/scheduler.h"
|
#include "core/hle/kernel/scheduler.h"
|
||||||
|
@ -114,6 +115,11 @@ public:
|
||||||
return CurrentCpuCore().ArmInterface();
|
return CurrentCpuCore().ArmInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the index of the currently running CPU core
|
||||||
|
size_t CurrentCoreIndex() {
|
||||||
|
return CurrentCpuCore().CoreIndex();
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets an ARM interface to the CPU core with the specified index
|
/// Gets an ARM interface to the CPU core with the specified index
|
||||||
ARM_Interface& ArmInterface(size_t core_index);
|
ARM_Interface& ArmInterface(size_t core_index);
|
||||||
|
|
||||||
|
@ -130,6 +136,11 @@ public:
|
||||||
return *CurrentCpuCore().Scheduler();
|
return *CurrentCpuCore().Scheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the exclusive monitor
|
||||||
|
ExclusiveMonitor& Monitor() {
|
||||||
|
return *cpu_exclusive_monitor;
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the scheduler for the CPU core with the specified index
|
/// Gets the scheduler for the CPU core with the specified index
|
||||||
const std::shared_ptr<Kernel::Scheduler>& Scheduler(size_t core_index);
|
const std::shared_ptr<Kernel::Scheduler>& Scheduler(size_t core_index);
|
||||||
|
|
||||||
|
@ -186,6 +197,7 @@ private:
|
||||||
std::unique_ptr<Tegra::GPU> gpu_core;
|
std::unique_ptr<Tegra::GPU> gpu_core;
|
||||||
std::shared_ptr<Tegra::DebugContext> debug_context;
|
std::shared_ptr<Tegra::DebugContext> debug_context;
|
||||||
Kernel::SharedPtr<Kernel::Process> current_process;
|
Kernel::SharedPtr<Kernel::Process> current_process;
|
||||||
|
std::shared_ptr<ExclusiveMonitor> cpu_exclusive_monitor;
|
||||||
std::shared_ptr<CpuBarrier> cpu_barrier;
|
std::shared_ptr<CpuBarrier> cpu_barrier;
|
||||||
std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
|
std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
|
||||||
std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
|
std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
|
||||||
|
|
|
@ -48,14 +48,15 @@ bool CpuBarrier::Rendezvous() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cpu::Cpu(std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index)
|
Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
|
||||||
|
std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index)
|
||||||
: cpu_barrier{std::move(cpu_barrier)}, core_index{core_index} {
|
: cpu_barrier{std::move(cpu_barrier)}, core_index{core_index} {
|
||||||
|
|
||||||
if (Settings::values.use_cpu_jit) {
|
if (Settings::values.use_cpu_jit) {
|
||||||
#ifdef ARCHITECTURE_x86_64
|
#ifdef ARCHITECTURE_x86_64
|
||||||
arm_interface = std::make_shared<ARM_Dynarmic>();
|
arm_interface = std::make_shared<ARM_Dynarmic>(exclusive_monitor, core_index);
|
||||||
#else
|
#else
|
||||||
cpu_core = std::make_shared<ARM_Unicorn>();
|
arm_interface = std::make_shared<ARM_Unicorn>();
|
||||||
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
|
@ -65,6 +66,18 @@ Cpu::Cpu(std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index)
|
||||||
scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get());
|
scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(size_t num_cores) {
|
||||||
|
if (Settings::values.use_cpu_jit) {
|
||||||
|
#ifdef ARCHITECTURE_x86_64
|
||||||
|
return std::make_shared<DynarmicExclusiveMonitor>(num_cores);
|
||||||
|
#else
|
||||||
|
return nullptr; // TODO(merry): Passthrough exclusive monitor
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
return nullptr; // TODO(merry): Passthrough exclusive monitor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Cpu::RunLoop(bool tight_loop) {
|
void Cpu::RunLoop(bool tight_loop) {
|
||||||
// Wait for all other CPU cores to complete the previous slice, such that they run in lock-step
|
// Wait for all other CPU cores to complete the previous slice, such that they run in lock-step
|
||||||
if (!cpu_barrier->Rendezvous()) {
|
if (!cpu_barrier->Rendezvous()) {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/arm/exclusive_monitor.h"
|
||||||
|
|
||||||
class ARM_Interface;
|
class ARM_Interface;
|
||||||
|
|
||||||
|
@ -40,7 +41,8 @@ private:
|
||||||
|
|
||||||
class Cpu {
|
class Cpu {
|
||||||
public:
|
public:
|
||||||
Cpu(std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index);
|
Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
|
||||||
|
std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index);
|
||||||
|
|
||||||
void RunLoop(bool tight_loop = true);
|
void RunLoop(bool tight_loop = true);
|
||||||
|
|
||||||
|
@ -64,6 +66,12 @@ public:
|
||||||
return core_index == 0;
|
return core_index == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CoreIndex() const {
|
||||||
|
return core_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<ExclusiveMonitor> MakeExclusiveMonitor(size_t num_cores);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Reschedule();
|
void Reschedule();
|
||||||
|
|
||||||
|
|
Reference in New Issue