yuzu-emu
/
yuzu-android
Archived
1
0
Fork 0

core: Implement separate A32/A64 ARM interfaces.

This commit is contained in:
bunnei 2020-03-01 23:46:10 -05:00
parent 6fc485a607
commit c083ea7d78
21 changed files with 454 additions and 122 deletions

View File

@ -595,8 +595,10 @@ endif()
if (ARCHITECTURE_x86_64) if (ARCHITECTURE_x86_64)
target_sources(core PRIVATE target_sources(core PRIVATE
arm/dynarmic/arm_dynarmic.cpp arm/dynarmic/arm_dynarmic_32.cpp
arm/dynarmic/arm_dynarmic.h arm/dynarmic/arm_dynarmic_32.h
arm/dynarmic/arm_dynarmic_64.cpp
arm/dynarmic/arm_dynarmic_64.h
arm/dynarmic/arm_dynarmic_cp15.cpp arm/dynarmic/arm_dynarmic_cp15.cpp
arm/dynarmic/arm_dynarmic_cp15.h arm/dynarmic/arm_dynarmic_cp15.h
) )

View File

@ -25,7 +25,20 @@ public:
explicit ARM_Interface(System& system_) : system{system_} {} explicit ARM_Interface(System& system_) : system{system_} {}
virtual ~ARM_Interface() = default; virtual ~ARM_Interface() = default;
struct ThreadContext { struct ThreadContext32 {
std::array<u32, 16> cpu_registers;
u32 cpsr;
std::array<u8, 4> padding;
std::array<u64, 32> fprs;
u32 fpscr;
u32 fpexc;
u32 tpidr;
};
// Internally within the kernel, it expects the AArch32 version of the
// thread context to be 344 bytes in size.
static_assert(sizeof(ThreadContext32) == 0x158);
struct ThreadContext64 {
std::array<u64, 31> cpu_registers; std::array<u64, 31> cpu_registers;
u64 sp; u64 sp;
u64 pc; u64 pc;
@ -38,7 +51,7 @@ public:
}; };
// Internally within the kernel, it expects the AArch64 version of the // Internally within the kernel, it expects the AArch64 version of the
// thread context to be 800 bytes in size. // thread context to be 800 bytes in size.
static_assert(sizeof(ThreadContext) == 0x320); static_assert(sizeof(ThreadContext64) == 0x320);
/// Runs the CPU until an event happens /// Runs the CPU until an event happens
virtual void Run() = 0; virtual void Run() = 0;
@ -130,17 +143,10 @@ public:
*/ */
virtual void SetTPIDR_EL0(u64 value) = 0; virtual void SetTPIDR_EL0(u64 value) = 0;
/** virtual void SaveContext(ThreadContext32& ctx) = 0;
* Saves the current CPU context virtual void SaveContext(ThreadContext64& ctx) = 0;
* @param ctx Thread context to save virtual void LoadContext(const ThreadContext32& ctx) = 0;
*/ virtual void LoadContext(const ThreadContext64& ctx) = 0;
virtual void SaveContext(ThreadContext& ctx) = 0;
/**
* Loads a CPU context
* @param ctx Thread context to load
*/
virtual void LoadContext(const ThreadContext& ctx) = 0;
/// Clears the exclusive monitor's state. /// Clears the exclusive monitor's state.
virtual void ClearExclusiveState() = 0; virtual void ClearExclusiveState() = 0;

View File

@ -0,0 +1,208 @@
// Copyright 2020 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cinttypes>
#include <memory>
#include <dynarmic/A32/a32.h>
#include <dynarmic/A32/config.h>
#include <dynarmic/A32/context.h>
#include "common/microprofile.h"
#include "core/arm/dynarmic/arm_dynarmic_32.h"
#include "core/arm/dynarmic/arm_dynarmic_64.h"
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
#include "core/core.h"
#include "core/core_manager.h"
#include "core/core_timing.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
namespace Core {
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public:
explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent) : parent(parent) {}
u8 MemoryRead8(u32 vaddr) override {
return parent.system.Memory().Read8(vaddr);
}
u16 MemoryRead16(u32 vaddr) override {
return parent.system.Memory().Read16(vaddr);
}
u32 MemoryRead32(u32 vaddr) override {
return parent.system.Memory().Read32(vaddr);
}
u64 MemoryRead64(u32 vaddr) override {
return parent.system.Memory().Read64(vaddr);
}
void MemoryWrite8(u32 vaddr, u8 value) override {
parent.system.Memory().Write8(vaddr, value);
}
void MemoryWrite16(u32 vaddr, u16 value) override {
parent.system.Memory().Write16(vaddr, value);
}
void MemoryWrite32(u32 vaddr, u32 value) override {
parent.system.Memory().Write32(vaddr, value);
}
void MemoryWrite64(u32 vaddr, u64 value) override {
parent.system.Memory().Write64(vaddr, value);
}
void InterpreterFallback(u32 pc, std::size_t num_instructions) override {
UNIMPLEMENTED();
}
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
switch (exception) {
case Dynarmic::A32::Exception::UndefinedInstruction:
case Dynarmic::A32::Exception::UnpredictableInstruction:
break;
case Dynarmic::A32::Exception::Breakpoint:
break;
}
LOG_CRITICAL(HW_GPU, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
UNIMPLEMENTED();
}
void CallSVC(u32 swi) override {
Kernel::CallSVC(parent.system, swi);
}
void AddTicks(u64 ticks) override {
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
// rough approximation of the amount of executed ticks in the system, it may be thrown off
// if not all cores are doing a similar amount of work. Instead of doing this, we should
// device a way so that timing is consistent across all cores without increasing the ticks 4
// times.
u64 amortized_ticks = (ticks - num_interpreted_instructions) / Core::NUM_CPU_CORES;
// Always execute at least one tick.
amortized_ticks = std::max<u64>(amortized_ticks, 1);
parent.system.CoreTiming().AddTicks(amortized_ticks);
num_interpreted_instructions = 0;
}
u64 GetTicksRemaining() override {
return std::max(parent.system.CoreTiming().GetDowncount(), {});
}
ARM_Dynarmic_32& parent;
std::size_t num_interpreted_instructions{};
u64 tpidrro_el0{};
u64 tpidr_el0{};
};
std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table,
std::size_t address_space_bits) const {
Dynarmic::A32::UserConfig config;
config.callbacks = cb.get();
// TODO(bunnei): Implement page table for 32-bit
// config.page_table = &page_table.pointers;
config.coprocessors[15] = std::make_shared<DynarmicCP15>((u32*)&CP15_regs[0]);
config.define_unpredictable_behaviour = true;
return std::make_unique<Dynarmic::A32::Jit>(config);
}
MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_32, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64));
void ARM_Dynarmic_32::Run() {
MICROPROFILE_SCOPE(ARM_Jit_Dynarmic_32);
jit->Run();
}
void ARM_Dynarmic_32::Step() {
cb->InterpreterFallback(jit->Regs()[15], 1);
}
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, ExclusiveMonitor& exclusive_monitor,
std::size_t core_index)
: ARM_Interface{system},
cb(std::make_unique<DynarmicCallbacks32>(*this)), core_index{core_index},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
ARM_Dynarmic_32::~ARM_Dynarmic_32() = default;
void ARM_Dynarmic_32::SetPC(u64 pc) {
jit->Regs()[15] = static_cast<u32>(pc);
}
u64 ARM_Dynarmic_32::GetPC() const {
return jit->Regs()[15];
}
u64 ARM_Dynarmic_32::GetReg(int index) const {
return jit->Regs()[index];
}
void ARM_Dynarmic_32::SetReg(int index, u64 value) {
jit->Regs()[index] = static_cast<u32>(value);
}
u128 ARM_Dynarmic_32::GetVectorReg(int index) const {
return {};
}
void ARM_Dynarmic_32::SetVectorReg(int index, u128 value) {}
u32 ARM_Dynarmic_32::GetPSTATE() const {
return jit->Cpsr();
}
void ARM_Dynarmic_32::SetPSTATE(u32 cpsr) {
jit->SetCpsr(cpsr);
}
u64 ARM_Dynarmic_32::GetTlsAddress() const {
return CP15_regs[static_cast<std::size_t>(CP15Register::CP15_THREAD_URO)];
}
void ARM_Dynarmic_32::SetTlsAddress(VAddr address) {
CP15_regs[static_cast<std::size_t>(CP15Register::CP15_THREAD_URO)] = static_cast<u32>(address);
}
u64 ARM_Dynarmic_32::GetTPIDR_EL0() const {
return cb->tpidr_el0;
}
void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) {
cb->tpidr_el0 = value;
}
void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
Dynarmic::A32::Context context;
jit->SaveContext(context);
ctx.cpu_registers = context.Regs();
ctx.cpsr = context.Cpsr();
}
void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
Dynarmic::A32::Context context;
context.Regs() = ctx.cpu_registers;
context.SetCpsr(ctx.cpsr);
jit->LoadContext(context);
}
void ARM_Dynarmic_32::PrepareReschedule() {
jit->HaltExecution();
}
void ARM_Dynarmic_32::ClearInstructionCache() {
jit->ClearCache();
}
void ARM_Dynarmic_32::ClearExclusiveState() {}
void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
std::size_t new_address_space_size_in_bits) {
auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
auto iter = jit_cache.find(key);
if (iter != jit_cache.end()) {
jit = iter->second;
return;
}
jit = MakeJit(page_table, new_address_space_size_in_bits);
jit_cache.emplace(key, jit);
}
} // namespace Core

View File

@ -0,0 +1,77 @@
// Copyright 2020 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <unordered_map>
#include <dynarmic/A32/a32.h>
#include <dynarmic/A64/a64.h>
#include <dynarmic/A64/exclusive_monitor.h>
#include "common/common_types.h"
#include "common/hash.h"
#include "core/arm/arm_interface.h"
#include "core/arm/exclusive_monitor.h"
namespace Memory {
class Memory;
}
namespace Core {
class DynarmicCallbacks32;
class DynarmicExclusiveMonitor;
class System;
class ARM_Dynarmic_32 final : public ARM_Interface {
public:
ARM_Dynarmic_32(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ARM_Dynarmic_32() override;
void SetPC(u64 pc) override;
u64 GetPC() const override;
u64 GetReg(int index) const override;
void SetReg(int index, u64 value) override;
u128 GetVectorReg(int index) const override;
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
void Run() override;
void Step() override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
void SaveContext(ThreadContext32& ctx) override;
void SaveContext(ThreadContext64& ctx) override {}
void LoadContext(const ThreadContext32& ctx) override;
void LoadContext(const ThreadContext64& ctx) override {}
void PrepareReschedule() override;
void ClearExclusiveState() override;
void ClearInstructionCache() override;
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;
private:
std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable& page_table,
std::size_t address_space_bits) const;
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
using JitCacheType =
std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A32::Jit>, Common::PairHash>;
friend class DynarmicCallbacks32;
std::unique_ptr<DynarmicCallbacks32> cb;
JitCacheType jit_cache;
std::shared_ptr<Dynarmic::A32::Jit> jit;
std::size_t core_index;
DynarmicExclusiveMonitor& exclusive_monitor;
std::array<u32, 84> CP15_regs{};
};
} // namespace Core

View File

@ -8,7 +8,7 @@
#include <dynarmic/A64/config.h> #include <dynarmic/A64/config.h>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "core/arm/dynarmic/arm_dynarmic.h" #include "core/arm/dynarmic/arm_dynarmic_64.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_manager.h" #include "core/core_manager.h"
#include "core/core_timing.h" #include "core/core_timing.h"
@ -25,9 +25,9 @@ namespace Core {
using Vector = Dynarmic::A64::Vector; using Vector = Dynarmic::A64::Vector;
class ARM_Dynarmic_Callbacks : public Dynarmic::A64::UserCallbacks { class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public: public:
explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {} explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent) : parent(parent) {}
u8 MemoryRead8(u64 vaddr) override { u8 MemoryRead8(u64 vaddr) override {
return parent.system.Memory().Read8(vaddr); return parent.system.Memory().Read8(vaddr);
@ -68,7 +68,7 @@ public:
LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc, LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc,
num_instructions, MemoryReadCode(pc)); num_instructions, MemoryReadCode(pc));
ARM_Interface::ThreadContext ctx; ARM_Interface::ThreadContext64 ctx;
parent.SaveContext(ctx); parent.SaveContext(ctx);
parent.inner_unicorn.LoadContext(ctx); parent.inner_unicorn.LoadContext(ctx);
parent.inner_unicorn.ExecuteInstructions(num_instructions); parent.inner_unicorn.ExecuteInstructions(num_instructions);
@ -90,7 +90,7 @@ public:
parent.jit->HaltExecution(); parent.jit->HaltExecution();
parent.SetPC(pc); parent.SetPC(pc);
Kernel::Thread* const thread = parent.system.CurrentScheduler().GetCurrentThread(); Kernel::Thread* const thread = parent.system.CurrentScheduler().GetCurrentThread();
parent.SaveContext(thread->GetContext()); parent.SaveContext(thread->GetContext64());
GDBStub::Break(); GDBStub::Break();
GDBStub::SendTrap(thread, 5); GDBStub::SendTrap(thread, 5);
return; return;
@ -126,13 +126,13 @@ public:
return Timing::CpuCyclesToClockCycles(parent.system.CoreTiming().GetTicks()); return Timing::CpuCyclesToClockCycles(parent.system.CoreTiming().GetTicks());
} }
ARM_Dynarmic& parent; ARM_Dynarmic_64& parent;
std::size_t num_interpreted_instructions = 0; std::size_t num_interpreted_instructions = 0;
u64 tpidrro_el0 = 0; u64 tpidrro_el0 = 0;
u64 tpidr_el0 = 0; u64 tpidr_el0 = 0;
}; };
std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit(Common::PageTable& page_table, std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table,
std::size_t address_space_bits) const { std::size_t address_space_bits) const {
Dynarmic::A64::UserConfig config; Dynarmic::A64::UserConfig config;
@ -162,76 +162,76 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit(Common::PageTable& pag
return std::make_shared<Dynarmic::A64::Jit>(config); return std::make_shared<Dynarmic::A64::Jit>(config);
} }
MICROPROFILE_DEFINE(ARM_Jit_Dynarmic, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)); MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_64, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64));
void ARM_Dynarmic::Run() { void ARM_Dynarmic_64::Run() {
MICROPROFILE_SCOPE(ARM_Jit_Dynarmic); MICROPROFILE_SCOPE(ARM_Jit_Dynarmic_64);
jit->Run(); jit->Run();
} }
void ARM_Dynarmic::Step() { void ARM_Dynarmic_64::Step() {
cb->InterpreterFallback(jit->GetPC(), 1); cb->InterpreterFallback(jit->GetPC(), 1);
} }
ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, ExclusiveMonitor& exclusive_monitor,
std::size_t core_index) std::size_t core_index)
: ARM_Interface{system}, : ARM_Interface{system},
cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system}, cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system},
core_index{core_index}, exclusive_monitor{ core_index{core_index}, exclusive_monitor{
dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
ARM_Dynarmic::~ARM_Dynarmic() = default; ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
void ARM_Dynarmic::SetPC(u64 pc) { void ARM_Dynarmic_64::SetPC(u64 pc) {
jit->SetPC(pc); jit->SetPC(pc);
} }
u64 ARM_Dynarmic::GetPC() const { u64 ARM_Dynarmic_64::GetPC() const {
return jit->GetPC(); return jit->GetPC();
} }
u64 ARM_Dynarmic::GetReg(int index) const { u64 ARM_Dynarmic_64::GetReg(int index) const {
return jit->GetRegister(index); return jit->GetRegister(index);
} }
void ARM_Dynarmic::SetReg(int index, u64 value) { void ARM_Dynarmic_64::SetReg(int index, u64 value) {
jit->SetRegister(index, value); jit->SetRegister(index, value);
} }
u128 ARM_Dynarmic::GetVectorReg(int index) const { u128 ARM_Dynarmic_64::GetVectorReg(int index) const {
return jit->GetVector(index); return jit->GetVector(index);
} }
void ARM_Dynarmic::SetVectorReg(int index, u128 value) { void ARM_Dynarmic_64::SetVectorReg(int index, u128 value) {
jit->SetVector(index, value); jit->SetVector(index, value);
} }
u32 ARM_Dynarmic::GetPSTATE() const { u32 ARM_Dynarmic_64::GetPSTATE() const {
return jit->GetPstate(); return jit->GetPstate();
} }
void ARM_Dynarmic::SetPSTATE(u32 pstate) { void ARM_Dynarmic_64::SetPSTATE(u32 pstate) {
jit->SetPstate(pstate); jit->SetPstate(pstate);
} }
u64 ARM_Dynarmic::GetTlsAddress() const { u64 ARM_Dynarmic_64::GetTlsAddress() const {
return cb->tpidrro_el0; return cb->tpidrro_el0;
} }
void ARM_Dynarmic::SetTlsAddress(VAddr address) { void ARM_Dynarmic_64::SetTlsAddress(VAddr address) {
cb->tpidrro_el0 = address; cb->tpidrro_el0 = address;
} }
u64 ARM_Dynarmic::GetTPIDR_EL0() const { u64 ARM_Dynarmic_64::GetTPIDR_EL0() const {
return cb->tpidr_el0; return cb->tpidr_el0;
} }
void ARM_Dynarmic::SetTPIDR_EL0(u64 value) { void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) {
cb->tpidr_el0 = value; cb->tpidr_el0 = value;
} }
void ARM_Dynarmic::SaveContext(ThreadContext& ctx) { void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
ctx.cpu_registers = jit->GetRegisters(); ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP(); ctx.sp = jit->GetSP();
ctx.pc = jit->GetPC(); ctx.pc = jit->GetPC();
@ -242,7 +242,7 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) {
ctx.tpidr = cb->tpidr_el0; ctx.tpidr = cb->tpidr_el0;
} }
void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
jit->SetRegisters(ctx.cpu_registers); jit->SetRegisters(ctx.cpu_registers);
jit->SetSP(ctx.sp); jit->SetSP(ctx.sp);
jit->SetPC(ctx.pc); jit->SetPC(ctx.pc);
@ -253,19 +253,19 @@ void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) {
SetTPIDR_EL0(ctx.tpidr); SetTPIDR_EL0(ctx.tpidr);
} }
void ARM_Dynarmic::PrepareReschedule() { void ARM_Dynarmic_64::PrepareReschedule() {
jit->HaltExecution(); jit->HaltExecution();
} }
void ARM_Dynarmic::ClearInstructionCache() { void ARM_Dynarmic_64::ClearInstructionCache() {
jit->ClearCache(); jit->ClearCache();
} }
void ARM_Dynarmic::ClearExclusiveState() { void ARM_Dynarmic_64::ClearExclusiveState() {
jit->ClearExclusiveState(); jit->ClearExclusiveState();
} }
void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table, void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
std::size_t new_address_space_size_in_bits) { std::size_t new_address_space_size_in_bits) {
auto key = std::make_pair(&page_table, new_address_space_size_in_bits); auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
auto iter = jit_cache.find(key); auto iter = jit_cache.find(key);
@ -277,8 +277,8 @@ void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table,
jit_cache.emplace(key, jit); jit_cache.emplace(key, jit);
} }
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count) DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count)
: monitor(core_count), memory{memory_} {} : monitor(core_count), memory{memory} {}
DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;

View File

@ -21,18 +21,14 @@ class Memory;
namespace Core { namespace Core {
class ARM_Dynarmic_Callbacks; class DynarmicCallbacks64;
class DynarmicExclusiveMonitor; class DynarmicExclusiveMonitor;
class System; class System;
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; class ARM_Dynarmic_64 final : public ARM_Interface {
using JitCacheType =
std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A64::Jit>, Common::PairHash>;
class ARM_Dynarmic final : public ARM_Interface {
public: public:
ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index); ARM_Dynarmic_64(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ARM_Dynarmic() override; ~ARM_Dynarmic_64() override;
void SetPC(u64 pc) override; void SetPC(u64 pc) override;
u64 GetPC() const override; u64 GetPC() const override;
@ -49,8 +45,10 @@ public:
void SetTPIDR_EL0(u64 value) override; void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override; u64 GetTPIDR_EL0() const override;
void SaveContext(ThreadContext& ctx) override; void SaveContext(ThreadContext32& ctx) override {}
void LoadContext(const ThreadContext& ctx) override; void SaveContext(ThreadContext64& ctx) override;
void LoadContext(const ThreadContext32& ctx) override {}
void LoadContext(const ThreadContext64& ctx) override;
void PrepareReschedule() override; void PrepareReschedule() override;
void ClearExclusiveState() override; void ClearExclusiveState() override;
@ -63,8 +61,12 @@ private:
std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable& page_table, std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable& page_table,
std::size_t address_space_bits) const; std::size_t address_space_bits) const;
friend class ARM_Dynarmic_Callbacks; using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
std::unique_ptr<ARM_Dynarmic_Callbacks> cb; using JitCacheType =
std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A64::Jit>, Common::PairHash>;
friend class DynarmicCallbacks64;
std::unique_ptr<DynarmicCallbacks64> cb;
JitCacheType jit_cache; JitCacheType jit_cache;
std::shared_ptr<Dynarmic::A64::Jit> jit; std::shared_ptr<Dynarmic::A64::Jit> jit;
ARM_Unicorn inner_unicorn; ARM_Unicorn inner_unicorn;
@ -75,7 +77,7 @@ private:
class DynarmicExclusiveMonitor final : public ExclusiveMonitor { class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
public: public:
explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count); explicit DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count);
~DynarmicExclusiveMonitor() override; ~DynarmicExclusiveMonitor() override;
void SetExclusive(std::size_t core_index, VAddr addr) override; void SetExclusive(std::size_t core_index, VAddr addr) override;
@ -88,7 +90,7 @@ public:
bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) override; bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) override;
private: private:
friend class ARM_Dynarmic; friend class ARM_Dynarmic_64;
Dynarmic::A64::ExclusiveMonitor monitor; Dynarmic::A64::ExclusiveMonitor monitor;
Memory::Memory& memory; Memory::Memory& memory;
}; };

View File

@ -3,7 +3,7 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#ifdef ARCHITECTURE_x86_64 #ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic.h" #include "core/arm/dynarmic/arm_dynarmic_64.h"
#endif #endif
#include "core/arm/exclusive_monitor.h" #include "core/arm/exclusive_monitor.h"
#include "core/memory.h" #include "core/memory.h"

View File

@ -53,7 +53,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
void* user_data) { void* user_data) {
auto* const system = static_cast<System*>(user_data); auto* const system = static_cast<System*>(user_data);
ARM_Interface::ThreadContext ctx{}; ARM_Interface::ThreadContext64 ctx{};
system->CurrentArmInterface().SaveContext(ctx); system->CurrentArmInterface().SaveContext(ctx);
ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr, ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr,
ctx.pc, ctx.cpu_registers[30]); ctx.pc, ctx.cpu_registers[30]);
@ -179,7 +179,7 @@ void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) {
} }
Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread(); Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread();
SaveContext(thread->GetContext()); SaveContext(thread->GetContext64());
if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) { if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) {
last_bkpt_hit = false; last_bkpt_hit = false;
GDBStub::Break(); GDBStub::Break();
@ -188,7 +188,7 @@ void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) {
} }
} }
void ARM_Unicorn::SaveContext(ThreadContext& ctx) { void ARM_Unicorn::SaveContext(ThreadContext64& ctx) {
int uregs[32]; int uregs[32];
void* tregs[32]; void* tregs[32];
@ -215,7 +215,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) {
CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32)); CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32));
} }
void ARM_Unicorn::LoadContext(const ThreadContext& ctx) { void ARM_Unicorn::LoadContext(const ThreadContext64& ctx) {
int uregs[32]; int uregs[32];
void* tregs[32]; void* tregs[32];

View File

@ -30,8 +30,6 @@ public:
void SetTlsAddress(VAddr address) override; void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override; void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override; u64 GetTPIDR_EL0() const override;
void SaveContext(ThreadContext& ctx) override;
void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override; void PrepareReschedule() override;
void ClearExclusiveState() override; void ClearExclusiveState() override;
void ExecuteInstructions(std::size_t num_instructions); void ExecuteInstructions(std::size_t num_instructions);
@ -41,6 +39,11 @@ public:
void PageTableChanged(Common::PageTable&, std::size_t) override {} void PageTableChanged(Common::PageTable&, std::size_t) override {}
void RecordBreak(GDBStub::BreakpointAddress bkpt); void RecordBreak(GDBStub::BreakpointAddress bkpt);
void SaveContext(ThreadContext32& ctx) override {}
void SaveContext(ThreadContext64& ctx) override;
void LoadContext(const ThreadContext32& ctx) override {}
void LoadContext(const ThreadContext64& ctx) override;
private: private:
static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data); static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);

View File

@ -6,9 +6,6 @@
#include <mutex> #include <mutex>
#include "common/logging/log.h" #include "common/logging/log.h"
#ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic.h"
#endif
#include "core/arm/exclusive_monitor.h" #include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h" #include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h" #include "core/core.h"

View File

@ -217,7 +217,7 @@ static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) {
return 0; return 0;
} }
const auto& thread_context = thread->GetContext(); const auto& thread_context = thread->GetContext64();
if (id < SP_REGISTER) { if (id < SP_REGISTER) {
return thread_context.cpu_registers[id]; return thread_context.cpu_registers[id];
@ -239,7 +239,7 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
return; return;
} }
auto& thread_context = thread->GetContext(); auto& thread_context = thread->GetContext64();
if (id < SP_REGISTER) { if (id < SP_REGISTER) {
thread_context.cpu_registers[id] = val; thread_context.cpu_registers[id] = val;
@ -259,7 +259,7 @@ static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) {
return u128{0}; return u128{0};
} }
auto& thread_context = thread->GetContext(); auto& thread_context = thread->GetContext64();
if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
return thread_context.vector_registers[id - UC_ARM64_REG_Q0]; return thread_context.vector_registers[id - UC_ARM64_REG_Q0];
@ -275,7 +275,7 @@ static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr)
return; return;
} }
auto& thread_context = thread->GetContext(); auto& thread_context = thread->GetContext64();
if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val; thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val;
@ -916,7 +916,7 @@ static void WriteRegister() {
// Update ARM context, skipping scheduler - no running threads at this point // Update ARM context, skipping scheduler - no running threads at this point
Core::System::GetInstance() Core::System::GetInstance()
.ArmInterface(current_core) .ArmInterface(current_core)
.LoadContext(current_thread->GetContext()); .LoadContext(current_thread->GetContext64());
SendReply("OK"); SendReply("OK");
} }
@ -947,7 +947,7 @@ static void WriteRegisters() {
// Update ARM context, skipping scheduler - no running threads at this point // Update ARM context, skipping scheduler - no running threads at this point
Core::System::GetInstance() Core::System::GetInstance()
.ArmInterface(current_core) .ArmInterface(current_core)
.LoadContext(current_thread->GetContext()); .LoadContext(current_thread->GetContext64());
SendReply("OK"); SendReply("OK");
} }
@ -1019,7 +1019,7 @@ static void Step() {
// Update ARM context, skipping scheduler - no running threads at this point // Update ARM context, skipping scheduler - no running threads at this point
Core::System::GetInstance() Core::System::GetInstance()
.ArmInterface(current_core) .ArmInterface(current_core)
.LoadContext(current_thread->GetContext()); .LoadContext(current_thread->GetContext64());
} }
step_loop = true; step_loop = true;
halt_loop = true; halt_loop = true;

View File

@ -186,6 +186,10 @@ struct KernelCore::Impl {
return; return;
} }
for (auto& core : cores) {
core.SetIs64Bit(process->Is64BitProcess());
}
system.Memory().SetCurrentPageTable(*process); system.Memory().SetCurrentPageTable(*process);
} }

View File

@ -5,7 +5,8 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#ifdef ARCHITECTURE_x86_64 #ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic.h" #include "core/arm/dynarmic/arm_dynarmic_32.h"
#include "core/arm/dynarmic/arm_dynarmic_64.h"
#endif #endif
#include "core/arm/exclusive_monitor.h" #include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h" #include "core/arm/unicorn/arm_unicorn.h"
@ -20,13 +21,17 @@ PhysicalCore::PhysicalCore(Core::System& system, std::size_t id,
Core::ExclusiveMonitor& exclusive_monitor) Core::ExclusiveMonitor& exclusive_monitor)
: core_index{id} { : core_index{id} {
#ifdef ARCHITECTURE_x86_64 #ifdef ARCHITECTURE_x86_64
arm_interface = std::make_unique<Core::ARM_Dynarmic>(system, exclusive_monitor, core_index); arm_interface_32 =
std::make_unique<Core::ARM_Dynarmic_32>(system, exclusive_monitor, core_index);
arm_interface_64 =
std::make_unique<Core::ARM_Dynarmic_64>(system, exclusive_monitor, core_index);
#else #else
arm_interface = std::make_shared<Core::ARM_Unicorn>(system); arm_interface = std::make_shared<Core::ARM_Unicorn>(system);
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif #endif
scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface, core_index); scheduler = std::make_unique<Kernel::Scheduler>(system, core_index);
} }
PhysicalCore::~PhysicalCore() = default; PhysicalCore::~PhysicalCore() = default;
@ -48,4 +53,12 @@ void PhysicalCore::Shutdown() {
scheduler->Shutdown(); scheduler->Shutdown();
} }
void PhysicalCore::SetIs64Bit(bool is_64_bit) {
if (is_64_bit) {
arm_interface = arm_interface_64.get();
} else {
arm_interface = arm_interface_32.get();
}
}
} // namespace Kernel } // namespace Kernel

View File

@ -68,10 +68,14 @@ public:
return *scheduler; return *scheduler;
} }
void SetIs64Bit(bool is_64_bit);
private: private:
std::size_t core_index; std::size_t core_index;
std::unique_ptr<Core::ARM_Interface> arm_interface; std::unique_ptr<Core::ARM_Interface> arm_interface_32;
std::unique_ptr<Core::ARM_Interface> arm_interface_64;
std::unique_ptr<Kernel::Scheduler> scheduler; std::unique_ptr<Kernel::Scheduler> scheduler;
Core::ARM_Interface* arm_interface{};
}; };
} // namespace Kernel } // namespace Kernel

View File

@ -42,7 +42,8 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) {
// Register 1 must be a handle to the main thread // Register 1 must be a handle to the main thread
const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
thread->GetContext().cpu_registers[1] = thread_handle; thread->GetContext32().cpu_registers[1] = thread_handle;
thread->GetContext64().cpu_registers[1] = thread_handle;
// Threads by default are dormant, wake up the main thread so it runs when the scheduler fires // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires
thread->ResumeFromWait(); thread->ResumeFromWait();

View File

@ -383,8 +383,8 @@ void GlobalScheduler::Unlock() {
// TODO(Blinkhawk): Setup the interrupts and change context on current core. // TODO(Blinkhawk): Setup the interrupts and change context on current core.
} }
Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id) Scheduler::Scheduler(Core::System& system, std::size_t core_id)
: system(system), cpu_core(cpu_core), core_id(core_id) {} : system{system}, core_id{core_id} {}
Scheduler::~Scheduler() = default; Scheduler::~Scheduler() = default;
@ -422,9 +422,10 @@ void Scheduler::UnloadThread() {
// Save context for previous thread // Save context for previous thread
if (previous_thread) { if (previous_thread) {
cpu_core.SaveContext(previous_thread->GetContext()); system.ArmInterface(core_id).SaveContext(previous_thread->GetContext32());
system.ArmInterface(core_id).SaveContext(previous_thread->GetContext64());
// Save the TPIDR_EL0 system register in case it was modified. // Save the TPIDR_EL0 system register in case it was modified.
previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); previous_thread->SetTPIDR_EL0(system.ArmInterface(core_id).GetTPIDR_EL0());
if (previous_thread->GetStatus() == ThreadStatus::Running) { if (previous_thread->GetStatus() == ThreadStatus::Running) {
// This is only the case when a reschedule is triggered without the current thread // This is only the case when a reschedule is triggered without the current thread
@ -451,9 +452,10 @@ void Scheduler::SwitchContext() {
// Save context for previous thread // Save context for previous thread
if (previous_thread) { if (previous_thread) {
cpu_core.SaveContext(previous_thread->GetContext()); system.ArmInterface(core_id).SaveContext(previous_thread->GetContext32());
system.ArmInterface(core_id).SaveContext(previous_thread->GetContext64());
// Save the TPIDR_EL0 system register in case it was modified. // Save the TPIDR_EL0 system register in case it was modified.
previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); previous_thread->SetTPIDR_EL0(system.ArmInterface(core_id).GetTPIDR_EL0());
if (previous_thread->GetStatus() == ThreadStatus::Running) { if (previous_thread->GetStatus() == ThreadStatus::Running) {
// This is only the case when a reschedule is triggered without the current thread // This is only the case when a reschedule is triggered without the current thread
@ -481,9 +483,10 @@ void Scheduler::SwitchContext() {
system.Kernel().MakeCurrentProcess(thread_owner_process); system.Kernel().MakeCurrentProcess(thread_owner_process);
} }
cpu_core.LoadContext(new_thread->GetContext()); system.ArmInterface(core_id).LoadContext(new_thread->GetContext32());
cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); system.ArmInterface(core_id).LoadContext(new_thread->GetContext64());
cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); system.ArmInterface(core_id).SetTlsAddress(new_thread->GetTLSAddress());
system.ArmInterface(core_id).SetTPIDR_EL0(new_thread->GetTPIDR_EL0());
} else { } else {
current_thread = nullptr; current_thread = nullptr;
// Note: We do not reset the current process and current page table when idling because // Note: We do not reset the current process and current page table when idling because

View File

@ -181,7 +181,7 @@ private:
class Scheduler final { class Scheduler final {
public: public:
explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id); explicit Scheduler(Core::System& system, std::size_t core_id);
~Scheduler(); ~Scheduler();
/// Returns whether there are any threads that are ready to run. /// Returns whether there are any threads that are ready to run.
@ -235,7 +235,6 @@ private:
std::shared_ptr<Thread> selected_thread = nullptr; std::shared_ptr<Thread> selected_thread = nullptr;
Core::System& system; Core::System& system;
Core::ARM_Interface& cpu_core;
u64 last_context_switch_time = 0; u64 last_context_switch_time = 0;
u64 idle_selection_count = 0; u64 idle_selection_count = 0;
const std::size_t core_id; const std::size_t core_id;

View File

@ -133,14 +133,15 @@ void Thread::CancelWait() {
ResumeFromWait(); ResumeFromWait();
} }
/** static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top,
* Resets a thread context, making it ready to be scheduled and run by the CPU u32 entry_point, u32 arg) {
* @param context Thread context to reset context = {};
* @param stack_top Address of the top of the stack context.cpu_registers[0] = arg;
* @param entry_point Address of entry point for execution context.cpu_registers[15] = entry_point;
* @param arg User argument for thread context.cpu_registers[13] = stack_top;
*/ }
static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAddr stack_top,
static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, VAddr stack_top,
VAddr entry_point, u64 arg) { VAddr entry_point, u64 arg) {
context = {}; context = {};
context.cpu_registers[0] = arg; context.cpu_registers[0] = arg;
@ -198,9 +199,9 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::strin
thread->owner_process->RegisterThread(thread.get()); thread->owner_process->RegisterThread(thread.get());
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top),
// to initialize the context static_cast<u32>(entry_point), static_cast<u32>(arg));
ResetThreadContext(thread->context, stack_top, entry_point, arg); ResetThreadContext64(thread->context_64, stack_top, entry_point, arg);
return MakeResult<std::shared_ptr<Thread>>(std::move(thread)); return MakeResult<std::shared_ptr<Thread>>(std::move(thread));
} }
@ -213,11 +214,13 @@ void Thread::SetPriority(u32 priority) {
} }
void Thread::SetWaitSynchronizationResult(ResultCode result) { void Thread::SetWaitSynchronizationResult(ResultCode result) {
context.cpu_registers[0] = result.raw; context_32.cpu_registers[0] = result.raw;
context_64.cpu_registers[0] = result.raw;
} }
void Thread::SetWaitSynchronizationOutput(s32 output) { void Thread::SetWaitSynchronizationOutput(s32 output) {
context.cpu_registers[1] = output; context_32.cpu_registers[1] = output;
context_64.cpu_registers[1] = output;
} }
s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const { s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const {

View File

@ -102,7 +102,8 @@ public:
using MutexWaitingThreads = std::vector<std::shared_ptr<Thread>>; using MutexWaitingThreads = std::vector<std::shared_ptr<Thread>>;
using ThreadContext = Core::ARM_Interface::ThreadContext; using ThreadContext32 = Core::ARM_Interface::ThreadContext32;
using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
using ThreadSynchronizationObjects = std::vector<std::shared_ptr<SynchronizationObject>>; using ThreadSynchronizationObjects = std::vector<std::shared_ptr<SynchronizationObject>>;
@ -273,12 +274,20 @@ public:
return status == ThreadStatus::WaitSynch; return status == ThreadStatus::WaitSynch;
} }
ThreadContext& GetContext() { ThreadContext32& GetContext32() {
return context; return context_32;
} }
const ThreadContext& GetContext() const { const ThreadContext32& GetContext32() const {
return context; return context_32;
}
ThreadContext64& GetContext64() {
return context_64;
}
const ThreadContext64& GetContext64() const {
return context_64;
} }
ThreadStatus GetStatus() const { ThreadStatus GetStatus() const {
@ -466,7 +475,8 @@ private:
void AdjustSchedulingOnPriority(u32 old_priority); void AdjustSchedulingOnPriority(u32 old_priority);
void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core);
Core::ARM_Interface::ThreadContext context{}; ThreadContext32 context_32{};
ThreadContext64 context_64{};
u64 thread_id = 0; u64 thread_id = 0;

View File

@ -111,7 +111,7 @@ json GetProcessorStateDataAuto(Core::System& system) {
const auto& vm_manager{process->VMManager()}; const auto& vm_manager{process->VMManager()};
auto& arm{system.CurrentArmInterface()}; auto& arm{system.CurrentArmInterface()};
Core::ARM_Interface::ThreadContext context{}; Core::ARM_Interface::ThreadContext64 context{};
arm.SaveContext(context); arm.SaveContext(context);
return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32", return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32",

View File

@ -116,7 +116,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
constexpr std::size_t BaseRegister = 29; constexpr std::size_t BaseRegister = 29;
auto& memory = Core::System::GetInstance().Memory(); auto& memory = Core::System::GetInstance().Memory();
u64 base_pointer = thread.GetContext().cpu_registers[BaseRegister]; u64 base_pointer = thread.GetContext64().cpu_registers[BaseRegister];
while (base_pointer != 0) { while (base_pointer != 0) {
const u64 lr = memory.Read64(base_pointer + sizeof(u64)); const u64 lr = memory.Read64(base_pointer + sizeof(u64));
@ -240,7 +240,7 @@ QString WaitTreeThread::GetText() const {
break; break;
} }
const auto& context = thread.GetContext(); const auto& context = thread.GetContext64();
const QString pc_info = tr(" PC = 0x%1 LR = 0x%2") const QString pc_info = tr(" PC = 0x%1 LR = 0x%2")
.arg(context.pc, 8, 16, QLatin1Char{'0'}) .arg(context.pc, 8, 16, QLatin1Char{'0'})
.arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'}); .arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'});