mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #3272 from MerryMage/dynarmic
core/arm: Backend-specific context implementations
This commit is contained in:
		
						commit
						dca5fd291f
					
				
					 10 changed files with 215 additions and 76 deletions
				
			
		|  | @ -5,6 +5,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <cstddef> | ||||
| #include <memory> | ||||
| #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<ThreadContext> 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<ThreadContext>& 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<ThreadContext>& ctx) = 0; | ||||
| 
 | ||||
|     /// Prepare core for thread reschedule (if needed to correctly handle state)
 | ||||
|     virtual void PrepareReschedule() = 0; | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <cstring> | ||||
| #include <dynarmic/context.h> | ||||
| #include <dynarmic/dynarmic.h> | ||||
| #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<ARMul_State*>(user_arg); | ||||
| 
 | ||||
|  | @ -30,7 +84,7 @@ static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void* user_arg) { | |||
|     state->Reg[15] &= (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC); | ||||
| 
 | ||||
|     jit->Regs() = state->Reg; | ||||
|     jit->Cpsr() = state->Cpsr; | ||||
|     jit->SetCpsr(state->Cpsr); | ||||
|     jit->ExtRegs() = state->ExtReg; | ||||
|     jit->SetFpscr(state->VFP[VFP_FPSCR]); | ||||
| } | ||||
|  | @ -137,7 +191,7 @@ u32 ARM_Dynarmic::GetCPSR() const { | |||
| } | ||||
| 
 | ||||
| void ARM_Dynarmic::SetCPSR(u32 cpsr) { | ||||
|     jit->Cpsr() = cpsr; | ||||
|     jit->SetCpsr(cpsr); | ||||
| } | ||||
| 
 | ||||
| u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) { | ||||
|  | @ -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_Interface::ThreadContext> ARM_Dynarmic::NewContext() const { | ||||
|     return std::make_unique<DynarmicThreadContext>(); | ||||
| } | ||||
| 
 | ||||
| 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<ThreadContext>& arg) { | ||||
|     DynarmicThreadContext* ctx = dynamic_cast<DynarmicThreadContext*>(arg.get()); | ||||
|     ASSERT(ctx); | ||||
| 
 | ||||
|     jit->Regs()[13] = ctx.sp; | ||||
|     jit->Regs()[14] = ctx.lr; | ||||
|     jit->Regs()[15] = ctx.pc; | ||||
|     jit->Cpsr() = 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<ThreadContext>& arg) { | ||||
|     const DynarmicThreadContext* ctx = dynamic_cast<DynarmicThreadContext*>(arg.get()); | ||||
|     ASSERT(ctx); | ||||
| 
 | ||||
|     jit->LoadContext(ctx->ctx); | ||||
|     interpreter_state->VFP[VFP_FPEXC] = ctx->fpexc; | ||||
| } | ||||
| 
 | ||||
| void ARM_Dynarmic::PrepareReschedule() { | ||||
|  |  | |||
|  | @ -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<ThreadContext> NewContext() const override; | ||||
|     void SaveContext(const std::unique_ptr<ThreadContext>& arg) override; | ||||
|     void LoadContext(const std::unique_ptr<ThreadContext>& arg) override; | ||||
| 
 | ||||
|     void PrepareReschedule() override; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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<u32, 16> cpu_registers; | ||||
|     u32 cpsr; | ||||
|     std::array<u32, 64> fpu_registers; | ||||
|     u32 fpscr; | ||||
|     u32 fpexc; | ||||
| }; | ||||
| 
 | ||||
| ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { | ||||
|     state = std::make_unique<ARMul_State>(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_Interface::ThreadContext> ARM_DynCom::NewContext() const { | ||||
|     return std::make_unique<DynComThreadContext>(); | ||||
| } | ||||
| 
 | ||||
| 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<ThreadContext>& arg) { | ||||
|     DynComThreadContext* ctx = dynamic_cast<DynComThreadContext*>(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<ThreadContext>& arg) { | ||||
|     DynComThreadContext* ctx = dynamic_cast<DynComThreadContext*>(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() { | ||||
|  |  | |||
|  | @ -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<ThreadContext> NewContext() const override; | ||||
|     void SaveContext(const std::unique_ptr<ThreadContext>& arg) override; | ||||
|     void LoadContext(const std::unique_ptr<ThreadContext>& arg) override; | ||||
| 
 | ||||
|     void PrepareReschedule() override; | ||||
| 
 | ||||
|  |  | |||
|  | @ -763,8 +763,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))); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& 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<ARM_Interface::ThreadContext>& 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<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority, | ||||
|  | @ -453,8 +452,8 @@ SharedPtr<Thread> SetupMainThread(u32 entry_point, u32 priority, SharedPtr<Proce | |||
| 
 | ||||
|     SharedPtr<Thread> 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 { | ||||
|  |  | |||
|  | @ -181,7 +181,7 @@ public: | |||
|         return status == THREADSTATUS_WAIT_SYNCH_ALL; | ||||
|     } | ||||
| 
 | ||||
|     ARM_Interface::ThreadContext context; | ||||
|     std::unique_ptr<ARM_Interface::ThreadContext> context; | ||||
| 
 | ||||
|     u32 thread_id; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue