Merge pull request #3272 from MerryMage/dynarmic

core/arm: Backend-specific context implementations
master
bunnei 2018-02-02 12:27:52 +07:00 committed by GitHub
commit dca5fd291f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 215 additions and 76 deletions

@ -1 +1 @@
Subproject commit 4110494ac4edc83f74c65834ab3ba6ddd166f42e
Subproject commit d1d4705364031512cb89333aebc00b8d75a2f732

@ -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);
@ -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;