mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-15 03:50:06 +00:00
core/arm: Backend-specific context implementations
This commit is contained in:
parent
7d5c3b00a8
commit
fb2d34997e
@ -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 + ") ";
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
@ -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->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<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;
|
||||
|
||||
|
@ -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)));
|
||||
|
||||
|
@ -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…
Reference in New Issue
Block a user