mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-28 01:39:05 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cddadf3b6c | |||
| ef42d03bec | |||
| 14a3799a03 | |||
| e780b8f8d3 |
+36
-48
@@ -26,15 +26,42 @@ CpuManager::~CpuManager() = default;
|
|||||||
void CpuManager::Initialize() {
|
void CpuManager::Initialize() {
|
||||||
num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
|
num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
|
||||||
gpu_barrier = std::make_unique<Common::Barrier>(num_cores + 1);
|
gpu_barrier = std::make_unique<Common::Barrier>(num_cores + 1);
|
||||||
for (std::size_t core = 0; core < num_cores; core++)
|
for (std::size_t core = 0; core < num_cores; core++) {
|
||||||
core_data[core].host_thread = std::jthread([this, core](std::stop_token token) { RunThread(token, core); });
|
core_data[core].host_thread = std::jthread([this, core](std::stop_token token) {
|
||||||
|
// Initialization
|
||||||
|
system.RegisterCoreThread(core);
|
||||||
|
Common::SetCurrentThreadName(("CPUCore_" + std::to_string(core)).c_str());
|
||||||
|
Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
// Aimed specifically for Snapdragon 8 Elite devices
|
||||||
|
// This kills performance on desktop, but boosts perf for UMA devices
|
||||||
|
// like the S8E. Mediatek and Mali likely won't suffer.
|
||||||
|
Common::PinCurrentThreadToPerformanceCore(core);
|
||||||
|
#endif
|
||||||
|
auto& data = core_data[core];
|
||||||
|
data.host_context = Common::Fiber::ThreadToFiber();
|
||||||
|
// Running
|
||||||
|
if (gpu_barrier->Sync(token)) {
|
||||||
|
if (!is_async_gpu && !is_multicore) {
|
||||||
|
system.GPU().ObtainContext();
|
||||||
|
}
|
||||||
|
auto& kernel = system.Kernel();
|
||||||
|
auto& scheduler = *kernel.CurrentScheduler();
|
||||||
|
auto* thread = scheduler.GetSchedulerCurrentThread();
|
||||||
|
Kernel::SetCurrentThread(kernel, thread);
|
||||||
|
Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext());
|
||||||
|
}
|
||||||
|
// Cleanup
|
||||||
|
data.host_context->Exit();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CpuManager::Shutdown() {
|
void CpuManager::Shutdown() {
|
||||||
for (std::size_t core = 0; core < num_cores; core++) {
|
for (auto it = core_data.begin(); it != core_data.end(); ++it) {
|
||||||
if (core_data[core].host_thread.joinable()) {
|
if (it->host_thread.joinable()) {
|
||||||
core_data[core].host_thread.request_stop();
|
it->host_thread.request_stop();
|
||||||
core_data[core].host_thread.join();
|
it->host_thread.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,12 +104,10 @@ void CpuManager::MultiCoreRunGuestThread() {
|
|||||||
kernel.CurrentScheduler()->OnThreadStart();
|
kernel.CurrentScheduler()->OnThreadStart();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto* physical_core = &kernel.CurrentPhysicalCore();
|
auto& physical_core = kernel.CurrentPhysicalCore();
|
||||||
while (!physical_core->IsInterrupted()) {
|
while (!physical_core.IsInterrupted()) {
|
||||||
physical_core->RunThread(thread);
|
physical_core.RunThread(thread);
|
||||||
physical_core = &kernel.CurrentPhysicalCore();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleInterrupt();
|
HandleInterrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,41 +208,4 @@ void CpuManager::ShutdownThread() {
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CpuManager::RunThread(std::stop_token token, std::size_t core) {
|
|
||||||
/// Initialization
|
|
||||||
system.RegisterCoreThread(core);
|
|
||||||
std::string name = is_multicore ? ("CPUCore_" + std::to_string(core)) : std::string{"CPUThread"};
|
|
||||||
Common::SetCurrentThreadName(name.c_str());
|
|
||||||
Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
|
|
||||||
#ifdef __ANDROID__
|
|
||||||
// Aimed specifically for Snapdragon 8 Elite devices
|
|
||||||
// This kills performance on desktop, but boosts perf for UMA devices
|
|
||||||
// like the S8E. Mediatek and Mali likely won't suffer.
|
|
||||||
Common::PinCurrentThreadToPerformanceCore(core);
|
|
||||||
#endif
|
|
||||||
auto& data = core_data[core];
|
|
||||||
data.host_context = Common::Fiber::ThreadToFiber();
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
SCOPE_EXIT {
|
|
||||||
data.host_context->Exit();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Running
|
|
||||||
if (!gpu_barrier->Sync(token)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_async_gpu && !is_multicore) {
|
|
||||||
system.GPU().ObtainContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& kernel = system.Kernel();
|
|
||||||
auto& scheduler = *kernel.CurrentScheduler();
|
|
||||||
auto* thread = scheduler.GetSchedulerCurrentThread();
|
|
||||||
Kernel::SetCurrentThread(kernel, thread);
|
|
||||||
|
|
||||||
Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -84,7 +87,6 @@ private:
|
|||||||
void GuestActivate();
|
void GuestActivate();
|
||||||
void HandleInterrupt();
|
void HandleInterrupt();
|
||||||
void ShutdownThread();
|
void ShutdownThread();
|
||||||
void RunThread(std::stop_token stop_token, std::size_t core);
|
|
||||||
|
|
||||||
struct CoreData {
|
struct CoreData {
|
||||||
std::shared_ptr<Common::Fiber> host_context;
|
std::shared_ptr<Common::Fiber> host_context;
|
||||||
|
|||||||
@@ -170,9 +170,6 @@ struct KernelCore::Impl {
|
|||||||
schedulers[core_id].reset();
|
schedulers[core_id].reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
|
|
||||||
next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
|
|
||||||
|
|
||||||
// Close kernel objects that were not freed on shutdown
|
// Close kernel objects that were not freed on shutdown
|
||||||
{
|
{
|
||||||
std::scoped_lock lk{registered_in_use_objects_lock};
|
std::scoped_lock lk{registered_in_use_objects_lock};
|
||||||
@@ -355,22 +352,6 @@ struct KernelCore::Impl {
|
|||||||
application_process->Open();
|
application_process->Open();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the host thread ID for the caller.
|
|
||||||
u32 SetHostThreadId(std::size_t core_id) {
|
|
||||||
// This should only be called during core init.
|
|
||||||
ASSERT(tls_data.host_thread_id == UINT8_MAX);
|
|
||||||
|
|
||||||
// The first four slots are reserved for CPU core threads
|
|
||||||
ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
|
|
||||||
tls_data.host_thread_id = u8(core_id);
|
|
||||||
return tls_data.host_thread_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the host thread ID for the caller
|
|
||||||
u32 GetHostThreadId() const {
|
|
||||||
return tls_data.host_thread_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
|
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
|
||||||
KThread* GetHostDummyThread(KThread* existing_thread) {
|
KThread* GetHostDummyThread(KThread* existing_thread) {
|
||||||
if (tls_data.thread == nullptr) {
|
if (tls_data.thread == nullptr) {
|
||||||
@@ -386,9 +367,12 @@ struct KernelCore::Impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a CPU core thread by allocating a host thread ID for it
|
/// Registers a CPU core thread by allocating a host thread ID for it
|
||||||
void RegisterCoreThread(std::size_t core_id) {
|
void RegisterCoreThread(std::size_t core_id) noexcept {
|
||||||
|
// This should only be called during core init.
|
||||||
|
ASSERT(tls_data.host_thread_id == UINT8_MAX);
|
||||||
|
// The first four slots are reserved for CPU core threads
|
||||||
ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
|
ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
|
||||||
const auto this_id = SetHostThreadId(core_id);
|
const auto this_id = tls_data.host_thread_id = u8(core_id);
|
||||||
if (!is_multicore)
|
if (!is_multicore)
|
||||||
single_core_thread_id = this_id;
|
single_core_thread_id = this_id;
|
||||||
}
|
}
|
||||||
@@ -398,8 +382,8 @@ struct KernelCore::Impl {
|
|||||||
(void)GetHostDummyThread(existing_thread);
|
(void)GetHostDummyThread(existing_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] u32 GetCurrentHostThreadID() {
|
[[nodiscard]] inline u32 GetCurrentHostThreadID() noexcept {
|
||||||
auto const this_id = GetHostThreadId();
|
auto const this_id = tls_data.host_thread_id;
|
||||||
if (!is_multicore && single_core_thread_id == this_id)
|
if (!is_multicore && single_core_thread_id == this_id)
|
||||||
return u32(system.GetCpuManager().CurrentCore());
|
return u32(system.GetCpuManager().CurrentCore());
|
||||||
return this_id;
|
return this_id;
|
||||||
@@ -794,9 +778,6 @@ struct KernelCore::Impl {
|
|||||||
|
|
||||||
std::array<std::optional<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
|
std::array<std::optional<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
|
||||||
|
|
||||||
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
|
|
||||||
std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES};
|
|
||||||
|
|
||||||
// Kernel memory management
|
// Kernel memory management
|
||||||
std::optional<KMemoryManager> memory_manager;
|
std::optional<KMemoryManager> memory_manager;
|
||||||
|
|
||||||
@@ -930,11 +911,7 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t KernelCore::CurrentPhysicalCoreIndex() const {
|
size_t KernelCore::CurrentPhysicalCoreIndex() const {
|
||||||
const u32 core_id = impl->GetCurrentHostThreadID();
|
return impl->GetCurrentHostThreadID();
|
||||||
if (core_id >= Core::Hardware::NUM_CPU_CORES) {
|
|
||||||
return Core::Hardware::NUM_CPU_CORES - 1;
|
|
||||||
}
|
|
||||||
return core_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() {
|
Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
@@ -119,10 +119,9 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
|
|||||||
|
|
||||||
// Since scheduling may occur here, we cannot use any cached
|
// Since scheduling may occur here, we cannot use any cached
|
||||||
// state after returning from calls we make.
|
// state after returning from calls we make.
|
||||||
|
|
||||||
// Notify the debugger and go to sleep if a breakpoint was hit,
|
|
||||||
// or if the thread is unable to continue for any reason.
|
|
||||||
if (breakpoint || (prefetch_abort && may_abort)) {
|
if (breakpoint || (prefetch_abort && may_abort)) {
|
||||||
|
// Notify the debugger and go to sleep if a breakpoint was hit,
|
||||||
|
// or if the thread is unable to continue for any reason.
|
||||||
if (breakpoint) {
|
if (breakpoint) {
|
||||||
interface->RewindBreakpointInstruction();
|
interface->RewindBreakpointInstruction();
|
||||||
}
|
}
|
||||||
@@ -133,26 +132,19 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
|
|||||||
}
|
}
|
||||||
thread->RequestSuspend(SuspendType::Debug);
|
thread->RequestSuspend(SuspendType::Debug);
|
||||||
return;
|
return;
|
||||||
}
|
} else if (data_abort) {
|
||||||
|
// Notify the debugger and go to sleep on data abort.
|
||||||
// Notify the debugger and go to sleep on data abort.
|
|
||||||
if (data_abort) {
|
|
||||||
if (system.DebuggerEnabled()) {
|
if (system.DebuggerEnabled()) {
|
||||||
system.GetDebugger().NotifyThreadWatchpoint(thread, *interface->HaltedWatchpoint());
|
system.GetDebugger().NotifyThreadWatchpoint(thread, *interface->HaltedWatchpoint());
|
||||||
}
|
}
|
||||||
thread->RequestSuspend(SuspendType::Debug);
|
thread->RequestSuspend(SuspendType::Debug);
|
||||||
return;
|
return;
|
||||||
}
|
} else if (supervisor_call) {
|
||||||
|
// Handle system calls: Perform call.
|
||||||
// Handle system calls.
|
|
||||||
if (supervisor_call) {
|
|
||||||
// Perform call.
|
|
||||||
Svc::Call(system, interface->GetSvcNumber());
|
Svc::Call(system, interface->GetSvcNumber());
|
||||||
return;
|
return;
|
||||||
}
|
} else if (interrupt || m_is_single_core) {
|
||||||
|
// Handle external interrupt sources.
|
||||||
// Handle external interrupt sources.
|
|
||||||
if (interrupt || m_is_single_core) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,16 +152,14 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
|
|||||||
|
|
||||||
void PhysicalCore::LoadContext(const KThread* thread) {
|
void PhysicalCore::LoadContext(const KThread* thread) {
|
||||||
auto* const process = thread->GetOwnerProcess();
|
auto* const process = thread->GetOwnerProcess();
|
||||||
if (!process) {
|
if (process) {
|
||||||
// Kernel threads do not run on emulated CPU cores.
|
// Kernel threads do not run on emulated CPU cores.
|
||||||
return;
|
auto* interface = process->GetArmInterface(m_core_index);
|
||||||
}
|
if (interface) {
|
||||||
|
interface->SetContext(thread->GetContext());
|
||||||
auto* interface = process->GetArmInterface(m_core_index);
|
interface->SetTpidrroEl0(GetInteger(thread->GetTlsAddress()));
|
||||||
if (interface) {
|
interface->SetWatchpointArray(&process->GetWatchpoints());
|
||||||
interface->SetContext(thread->GetContext());
|
}
|
||||||
interface->SetTpidrroEl0(GetInteger(thread->GetTlsAddress()));
|
|
||||||
interface->SetWatchpointArray(&process->GetWatchpoints());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,14 +169,12 @@ void PhysicalCore::LoadSvcArguments(const KProcess& process, std::span<const uin
|
|||||||
|
|
||||||
void PhysicalCore::SaveContext(KThread* thread) const {
|
void PhysicalCore::SaveContext(KThread* thread) const {
|
||||||
auto* const process = thread->GetOwnerProcess();
|
auto* const process = thread->GetOwnerProcess();
|
||||||
if (!process) {
|
if (process) {
|
||||||
// Kernel threads do not run on emulated CPU cores.
|
// Kernel threads do not run on emulated CPU cores.
|
||||||
return;
|
auto* interface = process->GetArmInterface(m_core_index);
|
||||||
}
|
if (interface) {
|
||||||
|
interface->GetContext(thread->GetContext());
|
||||||
auto* interface = process->GetArmInterface(m_core_index);
|
}
|
||||||
if (interface) {
|
|
||||||
interface->GetContext(thread->GetContext());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,13 +194,11 @@ void PhysicalCore::CloneFpuStatus(KThread* dst) const {
|
|||||||
|
|
||||||
void PhysicalCore::LogBacktrace() {
|
void PhysicalCore::LogBacktrace() {
|
||||||
auto* process = GetCurrentProcessPointer(m_kernel);
|
auto* process = GetCurrentProcessPointer(m_kernel);
|
||||||
if (!process) {
|
if (process) {
|
||||||
return;
|
auto* interface = process->GetArmInterface(m_core_index);
|
||||||
}
|
if (interface) {
|
||||||
|
interface->LogBacktrace(process);
|
||||||
auto* interface = process->GetArmInterface(m_core_index);
|
}
|
||||||
if (interface) {
|
|
||||||
interface->LogBacktrace(process);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +207,7 @@ void PhysicalCore::Idle() {
|
|||||||
m_on_interrupt.wait(lk, [this] { return m_is_interrupted; });
|
m_on_interrupt.wait(lk, [this] { return m_is_interrupted; });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicalCore::IsInterrupted() const {
|
[[noinline]] bool PhysicalCore::IsInterrupted() const {
|
||||||
return m_is_interrupted;
|
return m_is_interrupted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,12 +226,10 @@ void PhysicalCore::Interrupt() {
|
|||||||
m_on_interrupt.notify_one();
|
m_on_interrupt.notify_one();
|
||||||
|
|
||||||
// If there is no thread running, we are done.
|
// If there is no thread running, we are done.
|
||||||
if (arm_interface == nullptr) {
|
if (arm_interface != nullptr) {
|
||||||
return;
|
// Interrupt the CPU.
|
||||||
|
arm_interface->SignalInterrupt(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interrupt the CPU.
|
|
||||||
arm_interface->SignalInterrupt(thread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicalCore::ClearInterrupt() {
|
void PhysicalCore::ClearInterrupt() {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -32,45 +32,31 @@ struct Jit::Impl final {
|
|||||||
, core(conf) {}
|
, core(conf) {}
|
||||||
|
|
||||||
HaltReason Run() {
|
HaltReason Run() {
|
||||||
ASSERT(!jit_interface->is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&halt_reason)));
|
PerformRequestedCacheInvalidation(HaltReason(Atomic::Load(&halt_reason)));
|
||||||
|
is_executing = true;
|
||||||
jit_interface->is_executing = true;
|
|
||||||
SCOPE_EXIT {
|
|
||||||
jit_interface->is_executing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
HaltReason hr = core.Run(current_address_space, current_state, &halt_reason);
|
HaltReason hr = core.Run(current_address_space, current_state, &halt_reason);
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation(hr);
|
PerformRequestedCacheInvalidation(hr);
|
||||||
|
is_executing = false;
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HaltReason Step() {
|
HaltReason Step() {
|
||||||
ASSERT(!jit_interface->is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&halt_reason)));
|
PerformRequestedCacheInvalidation(HaltReason(Atomic::Load(&halt_reason)));
|
||||||
|
is_executing = true;
|
||||||
jit_interface->is_executing = true;
|
|
||||||
SCOPE_EXIT {
|
|
||||||
jit_interface->is_executing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
HaltReason hr = core.Step(current_address_space, current_state, &halt_reason);
|
HaltReason hr = core.Step(current_address_space, current_state, &halt_reason);
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation(hr);
|
PerformRequestedCacheInvalidation(hr);
|
||||||
|
is_executing = false;
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearCache() {
|
void ClearCache() {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalidate_entire_cache = true;
|
invalidate_entire_cache = true;
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvalidateCacheRange(std::uint32_t start_address, std::size_t length) {
|
void InvalidateCacheRange(std::uint32_t start_address, std::size_t length) {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalid_cache_ranges.add(boost::icl::discrete_interval<u32>::closed(start_address, static_cast<u32>(start_address + length - 1)));
|
invalid_cache_ranges.add(boost::icl::discrete_interval<u32>::closed(start_address, static_cast<u32>(start_address + length - 1)));
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
@@ -80,12 +66,12 @@ struct Jit::Impl final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HaltExecution(HaltReason hr) {
|
void HaltExecution(HaltReason hr) {
|
||||||
Atomic::Or(&halt_reason, static_cast<u32>(hr));
|
Atomic::Or(&halt_reason, u32(hr));
|
||||||
Atomic::Barrier();
|
Atomic::Barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearHalt(HaltReason hr) {
|
void ClearHalt(HaltReason hr) {
|
||||||
Atomic::And(&halt_reason, ~static_cast<u32>(hr));
|
Atomic::And(&halt_reason, ~u32(hr));
|
||||||
Atomic::Barrier();
|
Atomic::Barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,21 +118,15 @@ struct Jit::Impl final {
|
|||||||
private:
|
private:
|
||||||
void PerformRequestedCacheInvalidation(HaltReason hr) {
|
void PerformRequestedCacheInvalidation(HaltReason hr) {
|
||||||
if (Has(hr, HaltReason::CacheInvalidation)) {
|
if (Has(hr, HaltReason::CacheInvalidation)) {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
|
|
||||||
ClearHalt(HaltReason::CacheInvalidation);
|
ClearHalt(HaltReason::CacheInvalidation);
|
||||||
|
|
||||||
if (invalidate_entire_cache) {
|
if (invalidate_entire_cache) {
|
||||||
current_address_space.ClearCache();
|
current_address_space.ClearCache();
|
||||||
|
|
||||||
invalidate_entire_cache = false;
|
invalidate_entire_cache = false;
|
||||||
invalid_cache_ranges.clear();
|
invalid_cache_ranges.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!invalid_cache_ranges.empty()) {
|
if (!invalid_cache_ranges.empty()) {
|
||||||
current_address_space.InvalidateCacheRanges(invalid_cache_ranges);
|
current_address_space.InvalidateCacheRanges(invalid_cache_ranges);
|
||||||
|
|
||||||
invalid_cache_ranges.clear();
|
invalid_cache_ranges.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -160,10 +140,9 @@ private:
|
|||||||
A32Core core;
|
A32Core core;
|
||||||
|
|
||||||
volatile u32 halt_reason = 0;
|
volatile u32 halt_reason = 0;
|
||||||
|
|
||||||
std::mutex invalidation_mutex;
|
|
||||||
boost::icl::interval_set<u32> invalid_cache_ranges;
|
boost::icl::interval_set<u32> invalid_cache_ranges;
|
||||||
bool invalidate_entire_cache = false;
|
bool invalidate_entire_cache = false;
|
||||||
|
bool is_executing = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Jit::Jit(UserConfig conf)
|
Jit::Jit(UserConfig conf)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -27,50 +27,37 @@ using namespace Backend::Arm64;
|
|||||||
|
|
||||||
struct Jit::Impl final {
|
struct Jit::Impl final {
|
||||||
Impl(Jit*, A64::UserConfig conf)
|
Impl(Jit*, A64::UserConfig conf)
|
||||||
: conf(conf)
|
: conf(conf)
|
||||||
, current_address_space(conf)
|
, current_address_space(conf)
|
||||||
, core(conf) {}
|
, core(conf)
|
||||||
|
{}
|
||||||
|
|
||||||
HaltReason Run() {
|
HaltReason Run() {
|
||||||
ASSERT(!is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&halt_reason)));
|
|
||||||
|
|
||||||
is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT {
|
PerformRequestedCacheInvalidation(HaltReason(Atomic::Load(&halt_reason)));
|
||||||
is_executing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
HaltReason hr = core.Run(current_address_space, current_state, &halt_reason);
|
HaltReason hr = core.Run(current_address_space, current_state, &halt_reason);
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation(hr);
|
PerformRequestedCacheInvalidation(hr);
|
||||||
|
is_executing = false;
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HaltReason Step() {
|
HaltReason Step() {
|
||||||
ASSERT(!is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&halt_reason)));
|
|
||||||
|
|
||||||
is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT {
|
PerformRequestedCacheInvalidation(HaltReason(Atomic::Load(&halt_reason)));
|
||||||
is_executing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
HaltReason hr = core.Step(current_address_space, current_state, &halt_reason);
|
HaltReason hr = core.Step(current_address_space, current_state, &halt_reason);
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation(hr);
|
PerformRequestedCacheInvalidation(hr);
|
||||||
|
is_executing = false;
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearCache() {
|
void ClearCache() {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalidate_entire_cache = true;
|
invalidate_entire_cache = true;
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvalidateCacheRange(std::uint64_t start_address, std::size_t length) {
|
void InvalidateCacheRange(std::uint64_t start_address, std::size_t length) {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalid_cache_ranges.add(boost::icl::discrete_interval<u64>::closed(start_address, start_address + length - 1));
|
invalid_cache_ranges.add(boost::icl::discrete_interval<u64>::closed(start_address, start_address + length - 1));
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
@@ -80,11 +67,13 @@ struct Jit::Impl final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HaltExecution(HaltReason hr) {
|
void HaltExecution(HaltReason hr) {
|
||||||
Atomic::Or(&halt_reason, static_cast<u32>(hr));
|
Atomic::Or(&halt_reason, u32(hr));
|
||||||
|
Atomic::Barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearHalt(HaltReason hr) {
|
void ClearHalt(HaltReason hr) {
|
||||||
Atomic::And(&halt_reason, ~static_cast<u32>(hr));
|
Atomic::And(&halt_reason, ~u32(hr));
|
||||||
|
Atomic::Barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t PC() const {
|
std::uint64_t PC() const {
|
||||||
@@ -147,10 +136,6 @@ struct Jit::Impl final {
|
|||||||
current_state.exclusive_state = false;
|
current_state.exclusive_state = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsExecuting() const {
|
|
||||||
return is_executing;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Disassemble() const {
|
std::string Disassemble() const {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -158,21 +143,15 @@ struct Jit::Impl final {
|
|||||||
private:
|
private:
|
||||||
void PerformRequestedCacheInvalidation(HaltReason hr) {
|
void PerformRequestedCacheInvalidation(HaltReason hr) {
|
||||||
if (Has(hr, HaltReason::CacheInvalidation)) {
|
if (Has(hr, HaltReason::CacheInvalidation)) {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
|
|
||||||
ClearHalt(HaltReason::CacheInvalidation);
|
ClearHalt(HaltReason::CacheInvalidation);
|
||||||
|
|
||||||
if (invalidate_entire_cache) {
|
if (invalidate_entire_cache) {
|
||||||
current_address_space.ClearCache();
|
current_address_space.ClearCache();
|
||||||
|
|
||||||
invalidate_entire_cache = false;
|
invalidate_entire_cache = false;
|
||||||
invalid_cache_ranges.clear();
|
invalid_cache_ranges.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!invalid_cache_ranges.empty()) {
|
if (!invalid_cache_ranges.empty()) {
|
||||||
current_address_space.InvalidateCacheRanges(invalid_cache_ranges);
|
current_address_space.InvalidateCacheRanges(invalid_cache_ranges);
|
||||||
|
|
||||||
invalid_cache_ranges.clear();
|
invalid_cache_ranges.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -185,8 +164,6 @@ private:
|
|||||||
A64Core core;
|
A64Core core;
|
||||||
|
|
||||||
volatile u32 halt_reason = 0;
|
volatile u32 halt_reason = 0;
|
||||||
|
|
||||||
std::mutex invalidation_mutex;
|
|
||||||
boost::icl::interval_set<u64> invalid_cache_ranges;
|
boost::icl::interval_set<u64> invalid_cache_ranges;
|
||||||
bool invalidate_entire_cache = false;
|
bool invalidate_entire_cache = false;
|
||||||
bool is_executing = false;
|
bool is_executing = false;
|
||||||
@@ -307,10 +284,6 @@ void Jit::ClearExclusiveState() {
|
|||||||
impl->ClearExclusiveState();
|
impl->ClearExclusiveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Jit::IsExecuting() const {
|
|
||||||
return impl->IsExecuting();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Jit::Disassemble() const {
|
std::string Jit::Disassemble() const {
|
||||||
return impl->Disassemble();
|
return impl->Disassemble();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -32,41 +32,29 @@ struct Jit::Impl final {
|
|||||||
, core(conf) {}
|
, core(conf) {}
|
||||||
|
|
||||||
HaltReason Run() {
|
HaltReason Run() {
|
||||||
ASSERT(!jit_interface->is_executing);
|
ASSERT(!is_executing);
|
||||||
jit_interface->is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT {
|
|
||||||
jit_interface->is_executing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
HaltReason hr = core.Run(current_address_space, current_state, &halt_reason);
|
HaltReason hr = core.Run(current_address_space, current_state, &halt_reason);
|
||||||
|
|
||||||
RequestCacheInvalidation();
|
RequestCacheInvalidation();
|
||||||
|
is_executing = false;
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HaltReason Step() {
|
HaltReason Step() {
|
||||||
ASSERT(!jit_interface->is_executing);
|
ASSERT(!is_executing);
|
||||||
jit_interface->is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT {
|
|
||||||
jit_interface->is_executing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
|
|
||||||
RequestCacheInvalidation();
|
RequestCacheInvalidation();
|
||||||
|
is_executing = false;
|
||||||
return HaltReason{};
|
return HaltReason{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearCache() {
|
void ClearCache() {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalidate_entire_cache = true;
|
invalidate_entire_cache = true;
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvalidateCacheRange(u32 start_address, size_t length) {
|
void InvalidateCacheRange(u32 start_address, size_t length) {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalid_cache_ranges.add(boost::icl::discrete_interval<u32>::closed(start_address, static_cast<u32>(start_address + length - 1)));
|
invalid_cache_ranges.add(boost::icl::discrete_interval<u32>::closed(start_address, static_cast<u32>(start_address + length - 1)));
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
@@ -132,12 +120,10 @@ private:
|
|||||||
A32JitState current_state{};
|
A32JitState current_state{};
|
||||||
A32AddressSpace current_address_space;
|
A32AddressSpace current_address_space;
|
||||||
A32Core core;
|
A32Core core;
|
||||||
|
|
||||||
volatile u32 halt_reason = 0;
|
volatile u32 halt_reason = 0;
|
||||||
|
|
||||||
std::mutex invalidation_mutex;
|
|
||||||
boost::icl::interval_set<u32> invalid_cache_ranges;
|
boost::icl::interval_set<u32> invalid_cache_ranges;
|
||||||
bool invalidate_entire_cache = false;
|
bool invalidate_entire_cache = false;
|
||||||
|
bool is_executing = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Jit::Jit(UserConfig conf)
|
Jit::Jit(UserConfig conf)
|
||||||
|
|||||||
@@ -75,14 +75,9 @@ struct Jit::Impl {
|
|||||||
~Impl() = default;
|
~Impl() = default;
|
||||||
|
|
||||||
HaltReason Run() {
|
HaltReason Run() {
|
||||||
ASSERT(!jit_interface->is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&jit_state.halt_reason)));
|
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&jit_state.halt_reason)));
|
||||||
|
is_executing = true;
|
||||||
jit_interface->is_executing = true;
|
|
||||||
SCOPE_EXIT {
|
|
||||||
jit_interface->is_executing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const CodePtr current_codeptr = [this] {
|
const CodePtr current_codeptr = [this] {
|
||||||
// RSB optimization
|
// RSB optimization
|
||||||
const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A32JitState::RSBPtrMask;
|
const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A32JitState::RSBPtrMask;
|
||||||
@@ -93,53 +88,45 @@ struct Jit::Impl {
|
|||||||
|
|
||||||
return GetCurrentBlock();
|
return GetCurrentBlock();
|
||||||
}();
|
}();
|
||||||
|
|
||||||
const HaltReason hr = block_of_code.RunCode(&jit_state, current_codeptr);
|
const HaltReason hr = block_of_code.RunCode(&jit_state, current_codeptr);
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation(hr);
|
PerformRequestedCacheInvalidation(hr);
|
||||||
|
is_executing = false;
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HaltReason Step() {
|
HaltReason Step() {
|
||||||
ASSERT(!jit_interface->is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&jit_state.halt_reason)));
|
PerformRequestedCacheInvalidation(HaltReason(Atomic::Load(&jit_state.halt_reason)));
|
||||||
|
is_executing = true;
|
||||||
jit_interface->is_executing = true;
|
|
||||||
SCOPE_EXIT {
|
|
||||||
jit_interface->is_executing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const HaltReason hr = block_of_code.StepCode(&jit_state, GetCurrentSingleStep());
|
const HaltReason hr = block_of_code.StepCode(&jit_state, GetCurrentSingleStep());
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation(hr);
|
PerformRequestedCacheInvalidation(hr);
|
||||||
|
is_executing = false;
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearCache() {
|
void ClearCache() {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalidate_entire_cache = true;
|
invalidate_entire_cache = true;
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvalidateCacheRange(std::uint32_t start_address, std::size_t length) {
|
void InvalidateCacheRange(std::uint32_t start_address, std::size_t length) {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
invalid_cache_ranges.add(boost::icl::discrete_interval<u32>::closed(start_address, u32(start_address + length - 1)));
|
||||||
invalid_cache_ranges.add(boost::icl::discrete_interval<u32>::closed(start_address, static_cast<u32>(start_address + length - 1)));
|
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset() {
|
void Reset() {
|
||||||
ASSERT(!jit_interface->is_executing);
|
ASSERT(!is_executing);
|
||||||
jit_state = {};
|
jit_state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void HaltExecution(HaltReason hr) {
|
void HaltExecution(HaltReason hr) {
|
||||||
Atomic::Or(&jit_state.halt_reason, static_cast<u32>(hr));
|
Atomic::Or(&jit_state.halt_reason, u32(hr));
|
||||||
|
Atomic::Barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearHalt(HaltReason hr) {
|
void ClearHalt(HaltReason hr) {
|
||||||
Atomic::And(&jit_state.halt_reason, ~static_cast<u32>(hr));
|
Atomic::And(&jit_state.halt_reason, ~u32(hr));
|
||||||
|
Atomic::Barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearExclusiveState() {
|
void ClearExclusiveState() {
|
||||||
@@ -223,14 +210,10 @@ private:
|
|||||||
|
|
||||||
void PerformRequestedCacheInvalidation(HaltReason hr) {
|
void PerformRequestedCacheInvalidation(HaltReason hr) {
|
||||||
if (Has(hr, HaltReason::CacheInvalidation)) {
|
if (Has(hr, HaltReason::CacheInvalidation)) {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
|
|
||||||
ClearHalt(HaltReason::CacheInvalidation);
|
ClearHalt(HaltReason::CacheInvalidation);
|
||||||
|
|
||||||
if (!invalidate_entire_cache && invalid_cache_ranges.empty()) {
|
if (!invalidate_entire_cache && invalid_cache_ranges.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
jit_state.ResetRSB();
|
jit_state.ResetRSB();
|
||||||
if (invalidate_entire_cache) {
|
if (invalidate_entire_cache) {
|
||||||
block_of_code.ClearCache();
|
block_of_code.ClearCache();
|
||||||
@@ -251,11 +234,10 @@ private:
|
|||||||
// Keep it here, you don't wanna mess with the fuckery that's initializer lists
|
// Keep it here, you don't wanna mess with the fuckery that's initializer lists
|
||||||
const A32::UserConfig conf;
|
const A32::UserConfig conf;
|
||||||
Jit* jit_interface;
|
Jit* jit_interface;
|
||||||
|
|
||||||
// Requests made during execution to invalidate the cache are queued up here.
|
// Requests made during execution to invalidate the cache are queued up here.
|
||||||
bool invalidate_entire_cache = false;
|
|
||||||
boost::icl::interval_set<u32> invalid_cache_ranges;
|
boost::icl::interval_set<u32> invalid_cache_ranges;
|
||||||
std::mutex invalidation_mutex;
|
bool invalidate_entire_cache = false;
|
||||||
|
bool is_executing = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Jit::Jit(UserConfig conf)
|
Jit::Jit(UserConfig conf)
|
||||||
|
|||||||
@@ -75,14 +75,8 @@ public:
|
|||||||
HaltReason Run() {
|
HaltReason Run() {
|
||||||
ASSERT(!is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&jit_state.halt_reason)));
|
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&jit_state.halt_reason)));
|
||||||
|
|
||||||
is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT {
|
|
||||||
this->is_executing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Check code alignment
|
// TODO: Check code alignment
|
||||||
|
|
||||||
const CodePtr current_code_ptr = [this] {
|
const CodePtr current_code_ptr = [this] {
|
||||||
// RSB optimization
|
// RSB optimization
|
||||||
const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A64JitState::RSBPtrMask;
|
const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A64JitState::RSBPtrMask;
|
||||||
@@ -94,37 +88,28 @@ public:
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
const HaltReason hr = block_of_code.RunCode(&jit_state, current_code_ptr);
|
const HaltReason hr = block_of_code.RunCode(&jit_state, current_code_ptr);
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation(hr);
|
PerformRequestedCacheInvalidation(hr);
|
||||||
|
is_executing = false;
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HaltReason Step() {
|
HaltReason Step() {
|
||||||
ASSERT(!is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&jit_state.halt_reason)));
|
PerformRequestedCacheInvalidation(HaltReason(Atomic::Load(&jit_state.halt_reason)));
|
||||||
|
|
||||||
is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT {
|
|
||||||
this->is_executing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const HaltReason hr = block_of_code.StepCode(&jit_state, GetCurrentSingleStep());
|
const HaltReason hr = block_of_code.StepCode(&jit_state, GetCurrentSingleStep());
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation(hr);
|
PerformRequestedCacheInvalidation(hr);
|
||||||
|
is_executing = false;
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearCache() {
|
void ClearCache() {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalidate_entire_cache = true;
|
invalidate_entire_cache = true;
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvalidateCacheRange(u64 start_address, size_t length) {
|
void InvalidateCacheRange(u64 start_address, size_t length) {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
const auto end_address = u64(start_address + length - 1);
|
||||||
const auto end_address = static_cast<u64>(start_address + length - 1);
|
|
||||||
const auto range = boost::icl::discrete_interval<u64>::closed(start_address, end_address);
|
const auto range = boost::icl::discrete_interval<u64>::closed(start_address, end_address);
|
||||||
invalid_cache_ranges.add(range);
|
invalid_cache_ranges.add(range);
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
@@ -136,11 +121,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HaltExecution(HaltReason hr) {
|
void HaltExecution(HaltReason hr) {
|
||||||
Atomic::Or(&jit_state.halt_reason, static_cast<u32>(hr));
|
Atomic::Or(&jit_state.halt_reason, u32(hr));
|
||||||
|
Atomic::Barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearHalt(HaltReason hr) {
|
void ClearHalt(HaltReason hr) {
|
||||||
Atomic::And(&jit_state.halt_reason, ~static_cast<u32>(hr));
|
Atomic::And(&jit_state.halt_reason, ~u32(hr));
|
||||||
|
Atomic::Barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetSP() const {
|
u64 GetSP() const {
|
||||||
@@ -228,10 +215,6 @@ public:
|
|||||||
jit_state.exclusive_state = 0;
|
jit_state.exclusive_state = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsExecuting() const {
|
|
||||||
return is_executing;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Disassemble() const {
|
std::string Disassemble() const {
|
||||||
const size_t size = reinterpret_cast<const char*>(block_of_code.getCurr()) - reinterpret_cast<const char*>(block_of_code.GetCodeBegin());
|
const size_t size = reinterpret_cast<const char*>(block_of_code.getCurr()) - reinterpret_cast<const char*>(block_of_code.GetCodeBegin());
|
||||||
auto const* p = reinterpret_cast<const char*>(block_of_code.GetCodeBegin());
|
auto const* p = reinterpret_cast<const char*>(block_of_code.GetCodeBegin());
|
||||||
@@ -280,14 +263,10 @@ private:
|
|||||||
|
|
||||||
void PerformRequestedCacheInvalidation(HaltReason hr) {
|
void PerformRequestedCacheInvalidation(HaltReason hr) {
|
||||||
if (Has(hr, HaltReason::CacheInvalidation)) {
|
if (Has(hr, HaltReason::CacheInvalidation)) {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
|
|
||||||
ClearHalt(HaltReason::CacheInvalidation);
|
ClearHalt(HaltReason::CacheInvalidation);
|
||||||
|
|
||||||
if (!invalidate_entire_cache && invalid_cache_ranges.empty()) {
|
if (!invalidate_entire_cache && invalid_cache_ranges.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
jit_state.ResetRSB();
|
jit_state.ResetRSB();
|
||||||
if (invalidate_entire_cache) {
|
if (invalidate_entire_cache) {
|
||||||
block_of_code.ClearCache();
|
block_of_code.ClearCache();
|
||||||
@@ -306,10 +285,9 @@ private:
|
|||||||
BlockOfCode block_of_code;
|
BlockOfCode block_of_code;
|
||||||
A64EmitX64 emitter;
|
A64EmitX64 emitter;
|
||||||
Optimization::PolyfillOptions polyfill_options;
|
Optimization::PolyfillOptions polyfill_options;
|
||||||
bool is_executing = false;
|
|
||||||
bool invalidate_entire_cache = false;
|
|
||||||
boost::icl::interval_set<u64> invalid_cache_ranges;
|
boost::icl::interval_set<u64> invalid_cache_ranges;
|
||||||
std::mutex invalidation_mutex;
|
bool invalidate_entire_cache = false;
|
||||||
|
bool is_executing = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Jit::Jit(UserConfig conf)
|
Jit::Jit(UserConfig conf)
|
||||||
@@ -421,10 +399,6 @@ void Jit::ClearExclusiveState() {
|
|||||||
impl->ClearExclusiveState();
|
impl->ClearExclusiveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Jit::IsExecuting() const {
|
|
||||||
return impl->IsExecuting();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Jit::Disassemble() const {
|
std::string Jit::Disassemble() const {
|
||||||
return impl->Disassemble();
|
return impl->Disassemble();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -84,21 +84,11 @@ public:
|
|||||||
/// Clears exclusive state for this core.
|
/// Clears exclusive state for this core.
|
||||||
void ClearExclusiveState();
|
void ClearExclusiveState();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if Jit::Run was called but hasn't returned yet.
|
|
||||||
* i.e.: We're in a callback.
|
|
||||||
*/
|
|
||||||
bool IsExecuting() const {
|
|
||||||
return is_executing;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Disassemble the instructions following the current pc and return
|
/// @brief Disassemble the instructions following the current pc and return
|
||||||
/// the resulting instructions as a vector of their string representations.
|
/// the resulting instructions as a vector of their string representations.
|
||||||
std::string Disassemble() const;
|
std::string Disassemble() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_executing = false;
|
|
||||||
|
|
||||||
struct Impl;
|
struct Impl;
|
||||||
std::unique_ptr<Impl> impl;
|
std::unique_ptr<Impl> impl;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -116,12 +116,6 @@ public:
|
|||||||
/// Clears exclusive state for this core.
|
/// Clears exclusive state for this core.
|
||||||
void ClearExclusiveState();
|
void ClearExclusiveState();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if Jit::Run was called but hasn't returned yet.
|
|
||||||
* i.e.: We're in a callback.
|
|
||||||
*/
|
|
||||||
bool IsExecuting() const;
|
|
||||||
|
|
||||||
/// @brief Disassemble the instructions following the current pc and return
|
/// @brief Disassemble the instructions following the current pc and return
|
||||||
/// the resulting instructions as a vector of their string representations.
|
/// the resulting instructions as a vector of their string representations.
|
||||||
std::string Disassemble() const;
|
std::string Disassemble() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user