core/arm: Backend-specific context implementations

This commit is contained in:
MerryMage 2017-12-12 19:12:03 +00:00
parent 7d5c3b00a8
commit fb2d34997e
9 changed files with 212 additions and 73 deletions

View file

@ -172,8 +172,8 @@ QString WaitTreeThread::GetText() const {
break; break;
} }
QString pc_info = tr(" PC = 0x%1 LR = 0x%2") QString pc_info = tr(" PC = 0x%1 LR = 0x%2")
.arg(thread.context.pc, 8, 16, QLatin1Char('0')) .arg(thread.context->GetProgramCounter(), 8, 16, QLatin1Char('0'))
.arg(thread.context.lr, 8, 16, QLatin1Char('0')); .arg(thread.context->GetLinkRegister(), 8, 16, QLatin1Char('0'));
return WaitTreeWaitObject::GetText() + pc_info + " (" + status + ") "; return WaitTreeWaitObject::GetText() + pc_info + " (" + status + ") ";
} }

View file

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <cstddef> #include <cstddef>
#include <memory>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/arm/skyeye_common/arm_regformat.h" #include "core/arm/skyeye_common/arm_regformat.h"
#include "core/arm/skyeye_common/vfp/asm_vfp.h" #include "core/arm/skyeye_common/vfp/asm_vfp.h"
@ -14,15 +15,42 @@ class ARM_Interface : NonCopyable {
public: public:
virtual ~ARM_Interface() {} virtual ~ARM_Interface() {}
struct ThreadContext { class ThreadContext {
u32 cpu_registers[13]; public:
u32 sp; virtual ~ThreadContext() = default;
u32 lr;
u32 pc; virtual void Reset() = 0;
u32 cpsr; virtual u32 GetCpuRegister(size_t index) const = 0;
u32 fpu_registers[64]; virtual void SetCpuRegister(size_t index, u32 value) = 0;
u32 fpscr; virtual u32 GetCpsr() const = 0;
u32 fpexc; 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 /// Runs the CPU until an event happens
@ -124,17 +152,23 @@ public:
*/ */
virtual void SetCP15Register(CP15Register reg, u32 value) = 0; 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 * Saves the current CPU context
* @param ctx Thread context to save * @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 * Loads a CPU context
* @param ctx Thread context to load * @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) /// Prepare core for thread reschedule (if needed to correctly handle state)
virtual void PrepareReschedule() = 0; virtual void PrepareReschedule() = 0;

View file

@ -3,6 +3,7 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <cstring> #include <cstring>
#include <dynarmic/context.h>
#include <dynarmic/dynarmic.h> #include <dynarmic/dynarmic.h>
#include "common/assert.h" #include "common/assert.h"
#include "common/microprofile.h" #include "common/microprofile.h"
@ -14,6 +15,59 @@
#include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc.h"
#include "core/memory.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) { static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void* user_arg) {
ARMul_State* state = static_cast<ARMul_State*>(user_arg); ARMul_State* state = static_cast<ARMul_State*>(user_arg);
@ -148,30 +202,24 @@ void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) {
interpreter_state->CP15[reg] = value; interpreter_state->CP15[reg] = value;
} }
void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) { std::unique_ptr<ARM_Interface::ThreadContext> ARM_Dynarmic::NewContext() const {
memcpy(ctx.cpu_registers, jit->Regs().data(), sizeof(ctx.cpu_registers)); return std::make_unique<DynarmicThreadContext>();
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];
} }
void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) { void ARM_Dynarmic::SaveContext(const std::unique_ptr<ThreadContext>& arg) {
memcpy(jit->Regs().data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); DynarmicThreadContext* ctx = dynamic_cast<DynarmicThreadContext*>(arg.get());
memcpy(jit->ExtRegs().data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); ASSERT(ctx);
jit->Regs()[13] = ctx.sp; jit->SaveContext(ctx->ctx);
jit->Regs()[14] = ctx.lr; ctx->fpexc = interpreter_state->VFP[VFP_FPEXC];
jit->Regs()[15] = ctx.pc; }
jit->SetCpsr(ctx.cpsr);
jit->SetFpscr(ctx.fpscr); void ARM_Dynarmic::LoadContext(const std::unique_ptr<ThreadContext>& arg) {
interpreter_state->VFP[VFP_FPEXC] = ctx.fpexc; 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() { void ARM_Dynarmic::PrepareReschedule() {

View file

@ -35,8 +35,9 @@ public:
u32 GetCP15Register(CP15Register reg) override; u32 GetCP15Register(CP15Register reg) override;
void SetCP15Register(CP15Register reg, u32 value) override; void SetCP15Register(CP15Register reg, u32 value) override;
void SaveContext(ThreadContext& ctx) override; std::unique_ptr<ThreadContext> NewContext() const override;
void LoadContext(const ThreadContext& ctx) override; void SaveContext(const std::unique_ptr<ThreadContext>& arg) override;
void LoadContext(const std::unique_ptr<ThreadContext>& arg) override;
void PrepareReschedule() override; void PrepareReschedule() override;

View file

@ -12,6 +12,62 @@
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.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) { ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
state = std::make_unique<ARMul_State>(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); CoreTiming::AddTicks(ticks_executed);
} }
void ARM_DynCom::SaveContext(ThreadContext& ctx) { std::unique_ptr<ARM_Interface::ThreadContext> ARM_DynCom::NewContext() const {
memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers)); return std::make_unique<DynComThreadContext>();
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];
} }
void ARM_DynCom::LoadContext(const ThreadContext& ctx) { void ARM_DynCom::SaveContext(const std::unique_ptr<ThreadContext>& arg) {
memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); DynComThreadContext* ctx = dynamic_cast<DynComThreadContext*>(arg.get());
memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); ASSERT(ctx);
state->Reg[13] = ctx.sp; ctx->cpu_registers = state->Reg;
state->Reg[14] = ctx.lr; ctx->cpsr = state->Cpsr;
state->Reg[15] = ctx.pc; ctx->fpu_registers = state->ExtReg;
state->Cpsr = ctx.cpsr; ctx->fpscr = state->VFP[VFP_FPSCR];
ctx->fpexc = state->VFP[VFP_FPEXC];
}
state->VFP[VFP_FPSCR] = ctx.fpscr; void ARM_DynCom::LoadContext(const std::unique_ptr<ThreadContext>& arg) {
state->VFP[VFP_FPEXC] = ctx.fpexc; 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() { void ARM_DynCom::PrepareReschedule() {

View file

@ -35,8 +35,9 @@ public:
u32 GetCP15Register(CP15Register reg) override; u32 GetCP15Register(CP15Register reg) override;
void SetCP15Register(CP15Register reg, u32 value) override; void SetCP15Register(CP15Register reg, u32 value) override;
void SaveContext(ThreadContext& ctx) override; std::unique_ptr<ThreadContext> NewContext() const override;
void LoadContext(const ThreadContext& ctx) override; void SaveContext(const std::unique_ptr<ThreadContext>& arg) override;
void LoadContext(const std::unique_ptr<ThreadContext>& arg) override;
void PrepareReschedule() override; void PrepareReschedule() override;

View file

@ -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, Thread::Create(name, entry_point, priority, arg, processor_id, stack_top,
g_current_process)); g_current_process));
thread->context.fpscr = thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO |
FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000 FPSCR_ROUND_TOZERO); // 0x03C00000
CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(thread))); CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(thread)));

View file

@ -60,7 +60,7 @@ inline static u32 const NewThreadId() {
return next_thread_id++; return next_thread_id++;
} }
Thread::Thread() {} Thread::Thread() : context(Core::CPU().NewContext()) {}
Thread::~Thread() {} Thread::~Thread() {}
Thread* GetCurrentThread() { 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 entry_point Address of entry point for execution
* @param arg User argument for thread * @param arg User argument for thread
*/ */
static void ResetThreadContext(ARM_Interface::ThreadContext& context, u32 stack_top, static void ResetThreadContext(const std::unique_ptr<ARM_Interface::ThreadContext>& context,
u32 entry_point, u32 arg) { u32 stack_top, u32 entry_point, u32 arg) {
memset(&context, 0, sizeof(ARM_Interface::ThreadContext)); context->Reset();
context->SetCpuRegister(0, arg);
context.cpu_registers[0] = arg; context->SetProgramCounter(entry_point);
context.pc = entry_point; context->SetStackPointer(stack_top);
context.sp = stack_top; context->SetCpsr(USER32MODE | ((entry_point & 1) << 5)); // Usermode and THUMB mode
context.cpsr = USER32MODE | ((entry_point & 1) << 5); // Usermode and THUMB mode
} }
ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority, 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(); SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
thread->context.fpscr = thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO |
FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010 FPSCR_IXC); // 0x03C00010
// Note: The newly created thread will be run when the scheduler fires. // Note: The newly created thread will be run when the scheduler fires.
return thread; return thread;
@ -480,11 +479,11 @@ void Reschedule() {
} }
void Thread::SetWaitSynchronizationResult(ResultCode result) { void Thread::SetWaitSynchronizationResult(ResultCode result) {
context.cpu_registers[0] = result.raw; context->SetCpuRegister(0, result.raw);
} }
void Thread::SetWaitSynchronizationOutput(s32 output) { void Thread::SetWaitSynchronizationOutput(s32 output) {
context.cpu_registers[1] = output; context->SetCpuRegister(1, output);
} }
s32 Thread::GetWaitObjectIndex(WaitObject* object) const { s32 Thread::GetWaitObjectIndex(WaitObject* object) const {

View file

@ -181,7 +181,7 @@ public:
return status == THREADSTATUS_WAIT_SYNCH_ALL; return status == THREADSTATUS_WAIT_SYNCH_ALL;
} }
ARM_Interface::ThreadContext context; std::unique_ptr<ARM_Interface::ThreadContext> context;
u32 thread_id; u32 thread_id;