From fb2d34997e13327ad68b2aa7aa8dd64c20397bb1 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Tue, 12 Dec 2017 19:12:03 +0000 Subject: [PATCH] core/arm: Backend-specific context implementations --- src/citra_qt/debugger/wait_tree.cpp | 4 +- src/core/arm/arm_interface.h | 56 ++++++++++++--- src/core/arm/dynarmic/arm_dynarmic.cpp | 88 +++++++++++++++++------ src/core/arm/dynarmic/arm_dynarmic.h | 5 +- src/core/arm/dyncom/arm_dyncom.cpp | 96 ++++++++++++++++++++------ src/core/arm/dyncom/arm_dyncom.h | 5 +- src/core/hle/kernel/svc.cpp | 4 +- src/core/hle/kernel/thread.cpp | 25 ++++--- src/core/hle/kernel/thread.h | 2 +- 9 files changed, 212 insertions(+), 73 deletions(-) diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp index af0dfeca1..52493c58f 100644 --- a/src/citra_qt/debugger/wait_tree.cpp +++ b/src/citra_qt/debugger/wait_tree.cpp @@ -172,8 +172,8 @@ QString WaitTreeThread::GetText() const { break; } QString pc_info = tr(" PC = 0x%1 LR = 0x%2") - .arg(thread.context.pc, 8, 16, QLatin1Char('0')) - .arg(thread.context.lr, 8, 16, QLatin1Char('0')); + .arg(thread.context->GetProgramCounter(), 8, 16, QLatin1Char('0')) + .arg(thread.context->GetLinkRegister(), 8, 16, QLatin1Char('0')); return WaitTreeWaitObject::GetText() + pc_info + " (" + status + ") "; } diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index e43ac5429..8ac2c043d 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "common/common_types.h" #include "core/arm/skyeye_common/arm_regformat.h" #include "core/arm/skyeye_common/vfp/asm_vfp.h" @@ -14,15 +15,42 @@ class ARM_Interface : NonCopyable { public: virtual ~ARM_Interface() {} - struct ThreadContext { - u32 cpu_registers[13]; - u32 sp; - u32 lr; - u32 pc; - u32 cpsr; - u32 fpu_registers[64]; - u32 fpscr; - u32 fpexc; + class ThreadContext { + public: + virtual ~ThreadContext() = default; + + virtual void Reset() = 0; + virtual u32 GetCpuRegister(size_t index) const = 0; + virtual void SetCpuRegister(size_t index, u32 value) = 0; + virtual u32 GetCpsr() const = 0; + virtual void SetCpsr(u32 value) = 0; + virtual u32 GetFpuRegister(size_t index) const = 0; + virtual void SetFpuRegister(size_t index, u32 value) = 0; + virtual u32 GetFpscr() const = 0; + virtual void SetFpscr(u32 value) = 0; + virtual u32 GetFpexc() const = 0; + virtual void SetFpexc(u32 value) = 0; + + u32 GetStackPointer() const { + return GetCpuRegister(13); + } + void SetStackPointer(u32 value) { + return SetCpuRegister(13, value); + } + + u32 GetLinkRegister() const { + return GetCpuRegister(14); + } + void SetLinkRegister(u32 value) { + return SetCpuRegister(14, value); + } + + u32 GetProgramCounter() const { + return GetCpuRegister(15); + } + void SetProgramCounter(u32 value) { + return SetCpuRegister(15, value); + } }; /// Runs the CPU until an event happens @@ -124,17 +152,23 @@ public: */ virtual void SetCP15Register(CP15Register reg, u32 value) = 0; + /** + * Creates a CPU context + * @note The created context may only be used with this instance. + */ + virtual std::unique_ptr NewContext() const = 0; + /** * Saves the current CPU context * @param ctx Thread context to save */ - virtual void SaveContext(ThreadContext& ctx) = 0; + virtual void SaveContext(const std::unique_ptr& ctx) = 0; /** * Loads a CPU context * @param ctx Thread context to load */ - virtual void LoadContext(const ThreadContext& ctx) = 0; + virtual void LoadContext(const std::unique_ptr& ctx) = 0; /// Prepare core for thread reschedule (if needed to correctly handle state) virtual void PrepareReschedule() = 0; diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 2f42c915a..ce41bef52 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include "common/assert.h" #include "common/microprofile.h" @@ -14,6 +15,59 @@ #include "core/hle/kernel/svc.h" #include "core/memory.h" +class DynarmicThreadContext final : public ARM_Interface::ThreadContext { +public: + DynarmicThreadContext() { + Reset(); + } + ~DynarmicThreadContext() override = default; + + void Reset() override { + ctx.Regs() = {}; + ctx.SetCpsr(0); + ctx.ExtRegs() = {}; + ctx.SetFpscr(0); + fpexc = 0; + } + + u32 GetCpuRegister(size_t index) const override { + return ctx.Regs()[index]; + } + void SetCpuRegister(size_t index, u32 value) override { + ctx.Regs()[index] = value; + } + u32 GetCpsr() const override { + return ctx.Cpsr(); + } + void SetCpsr(u32 value) override { + ctx.SetCpsr(value); + } + u32 GetFpuRegister(size_t index) const override { + return ctx.ExtRegs()[index]; + } + void SetFpuRegister(size_t index, u32 value) override { + ctx.ExtRegs()[index] = value; + } + u32 GetFpscr() const override { + return ctx.Fpscr(); + } + void SetFpscr(u32 value) override { + ctx.SetFpscr(value); + } + u32 GetFpexc() const override { + return fpexc; + } + void SetFpexc(u32 value) override { + fpexc = value; + } + +private: + friend class ARM_Dynarmic; + + Dynarmic::Context ctx; + u32 fpexc; +}; + static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void* user_arg) { ARMul_State* state = static_cast(user_arg); @@ -148,30 +202,24 @@ void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) { interpreter_state->CP15[reg] = value; } -void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) { - memcpy(ctx.cpu_registers, jit->Regs().data(), sizeof(ctx.cpu_registers)); - memcpy(ctx.fpu_registers, jit->ExtRegs().data(), sizeof(ctx.fpu_registers)); - - ctx.sp = jit->Regs()[13]; - ctx.lr = jit->Regs()[14]; - ctx.pc = jit->Regs()[15]; - ctx.cpsr = jit->Cpsr(); - - ctx.fpscr = jit->Fpscr(); - ctx.fpexc = interpreter_state->VFP[VFP_FPEXC]; +std::unique_ptr ARM_Dynarmic::NewContext() const { + return std::make_unique(); } -void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) { - memcpy(jit->Regs().data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); - memcpy(jit->ExtRegs().data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); +void ARM_Dynarmic::SaveContext(const std::unique_ptr& arg) { + DynarmicThreadContext* ctx = dynamic_cast(arg.get()); + ASSERT(ctx); - jit->Regs()[13] = ctx.sp; - jit->Regs()[14] = ctx.lr; - jit->Regs()[15] = ctx.pc; - jit->SetCpsr(ctx.cpsr); + jit->SaveContext(ctx->ctx); + ctx->fpexc = interpreter_state->VFP[VFP_FPEXC]; +} - jit->SetFpscr(ctx.fpscr); - interpreter_state->VFP[VFP_FPEXC] = ctx.fpexc; +void ARM_Dynarmic::LoadContext(const std::unique_ptr& arg) { + const DynarmicThreadContext* ctx = dynamic_cast(arg.get()); + ASSERT(ctx); + + jit->LoadContext(ctx->ctx); + interpreter_state->VFP[VFP_FPEXC] = ctx->fpexc; } void ARM_Dynarmic::PrepareReschedule() { diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 011ffc54a..fa3023cb9 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -35,8 +35,9 @@ public: u32 GetCP15Register(CP15Register reg) override; void SetCP15Register(CP15Register reg, u32 value) override; - void SaveContext(ThreadContext& ctx) override; - void LoadContext(const ThreadContext& ctx) override; + std::unique_ptr NewContext() const override; + void SaveContext(const std::unique_ptr& arg) override; + void LoadContext(const std::unique_ptr& arg) override; void PrepareReschedule() override; diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 976a438ef..4643a20a7 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -12,6 +12,62 @@ #include "core/core.h" #include "core/core_timing.h" +class DynComThreadContext final : public ARM_Interface::ThreadContext { +public: + DynComThreadContext() { + Reset(); + } + ~DynComThreadContext() override = default; + + void Reset() override { + cpu_registers = {}; + cpsr = 0; + fpu_registers = {}; + fpscr = 0; + fpexc = 0; + } + + u32 GetCpuRegister(size_t index) const override { + return cpu_registers[index]; + } + void SetCpuRegister(size_t index, u32 value) override { + cpu_registers[index] = value; + } + u32 GetCpsr() const override { + return cpsr; + } + void SetCpsr(u32 value) override { + cpsr = value; + } + u32 GetFpuRegister(size_t index) const override { + return fpu_registers[index]; + } + void SetFpuRegister(size_t index, u32 value) override { + fpu_registers[index] = value; + } + u32 GetFpscr() const override { + return fpscr; + } + void SetFpscr(u32 value) override { + fpscr = value; + } + u32 GetFpexc() const override { + return fpexc; + } + void SetFpexc(u32 value) override { + fpexc = value; + } + +private: + friend class ARM_DynCom; + + std::array cpu_registers; + u32 cpsr; + std::array fpu_registers; + u32 fpscr; + u32 fpexc; +}; + ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { state = std::make_unique(initial_mode); } @@ -93,30 +149,30 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) { CoreTiming::AddTicks(ticks_executed); } -void ARM_DynCom::SaveContext(ThreadContext& ctx) { - memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers)); - memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers)); - - ctx.sp = state->Reg[13]; - ctx.lr = state->Reg[14]; - ctx.pc = state->Reg[15]; - ctx.cpsr = state->Cpsr; - - ctx.fpscr = state->VFP[VFP_FPSCR]; - ctx.fpexc = state->VFP[VFP_FPEXC]; +std::unique_ptr ARM_DynCom::NewContext() const { + return std::make_unique(); } -void ARM_DynCom::LoadContext(const ThreadContext& ctx) { - memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); - memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); +void ARM_DynCom::SaveContext(const std::unique_ptr& arg) { + DynComThreadContext* ctx = dynamic_cast(arg.get()); + ASSERT(ctx); - state->Reg[13] = ctx.sp; - state->Reg[14] = ctx.lr; - state->Reg[15] = ctx.pc; - state->Cpsr = ctx.cpsr; + ctx->cpu_registers = state->Reg; + ctx->cpsr = state->Cpsr; + ctx->fpu_registers = state->ExtReg; + ctx->fpscr = state->VFP[VFP_FPSCR]; + ctx->fpexc = state->VFP[VFP_FPEXC]; +} - state->VFP[VFP_FPSCR] = ctx.fpscr; - state->VFP[VFP_FPEXC] = ctx.fpexc; +void ARM_DynCom::LoadContext(const std::unique_ptr& arg) { + DynComThreadContext* ctx = dynamic_cast(arg.get()); + ASSERT(ctx); + + state->Reg = ctx->cpu_registers; + state->Cpsr = ctx->cpsr; + state->ExtReg = ctx->fpu_registers; + state->VFP[VFP_FPSCR] = ctx->fpscr; + state->VFP[VFP_FPEXC] = ctx->fpexc; } void ARM_DynCom::PrepareReschedule() { diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h index aa7520011..5547e0cc7 100644 --- a/src/core/arm/dyncom/arm_dyncom.h +++ b/src/core/arm/dyncom/arm_dyncom.h @@ -35,8 +35,9 @@ public: u32 GetCP15Register(CP15Register reg) override; void SetCP15Register(CP15Register reg, u32 value) override; - void SaveContext(ThreadContext& ctx) override; - void LoadContext(const ThreadContext& ctx) override; + std::unique_ptr NewContext() const override; + void SaveContext(const std::unique_ptr& arg) override; + void LoadContext(const std::unique_ptr& arg) override; void PrepareReschedule() override; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 06c905284..c529e6115 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -733,8 +733,8 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point Thread::Create(name, entry_point, priority, arg, processor_id, stack_top, g_current_process)); - thread->context.fpscr = - FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000 + thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | + FPSCR_ROUND_TOZERO); // 0x03C00000 CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(thread))); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 92eceb98f..8430f5e0d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -60,7 +60,7 @@ inline static u32 const NewThreadId() { return next_thread_id++; } -Thread::Thread() {} +Thread::Thread() : context(Core::CPU().NewContext()) {} Thread::~Thread() {} Thread* GetCurrentThread() { @@ -309,14 +309,13 @@ std::tuple GetFreeThreadLocalSlot(std::vector>& t * @param entry_point Address of entry point for execution * @param arg User argument for thread */ -static void ResetThreadContext(ARM_Interface::ThreadContext& context, u32 stack_top, - u32 entry_point, u32 arg) { - memset(&context, 0, sizeof(ARM_Interface::ThreadContext)); - - context.cpu_registers[0] = arg; - context.pc = entry_point; - context.sp = stack_top; - context.cpsr = USER32MODE | ((entry_point & 1) << 5); // Usermode and THUMB mode +static void ResetThreadContext(const std::unique_ptr& context, + u32 stack_top, u32 entry_point, u32 arg) { + context->Reset(); + context->SetCpuRegister(0, arg); + context->SetProgramCounter(entry_point); + context->SetStackPointer(stack_top); + context->SetCpsr(USER32MODE | ((entry_point & 1) << 5)); // Usermode and THUMB mode } ResultVal> Thread::Create(std::string name, VAddr entry_point, u32 priority, @@ -453,8 +452,8 @@ SharedPtr SetupMainThread(u32 entry_point, u32 priority, SharedPtr thread = std::move(thread_res).Unwrap(); - thread->context.fpscr = - FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010 + thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | + FPSCR_IXC); // 0x03C00010 // Note: The newly created thread will be run when the scheduler fires. return thread; @@ -480,11 +479,11 @@ void Reschedule() { } void Thread::SetWaitSynchronizationResult(ResultCode result) { - context.cpu_registers[0] = result.raw; + context->SetCpuRegister(0, result.raw); } void Thread::SetWaitSynchronizationOutput(s32 output) { - context.cpu_registers[1] = output; + context->SetCpuRegister(1, output); } s32 Thread::GetWaitObjectIndex(WaitObject* object) const { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 05e536086..e80b4cb5e 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -181,7 +181,7 @@ public: return status == THREADSTATUS_WAIT_SYNCH_ALL; } - ARM_Interface::ThreadContext context; + std::unique_ptr context; u32 thread_id;