|
|
|
@ -3,8 +3,8 @@
|
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <dynarmic/context.h>
|
|
|
|
|
#include <dynarmic/dynarmic.h>
|
|
|
|
|
#include <dynarmic/A32/a32.h>
|
|
|
|
|
#include <dynarmic/A32/context.h>
|
|
|
|
|
#include "common/assert.h"
|
|
|
|
|
#include "common/microprofile.h"
|
|
|
|
|
#include "core/arm/dynarmic/arm_dynarmic.h"
|
|
|
|
@ -64,86 +64,101 @@ public:
|
|
|
|
|
private:
|
|
|
|
|
friend class ARM_Dynarmic;
|
|
|
|
|
|
|
|
|
|
Dynarmic::Context ctx;
|
|
|
|
|
Dynarmic::A32::Context ctx;
|
|
|
|
|
u32 fpexc;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void* user_arg) {
|
|
|
|
|
ARMul_State* state = static_cast<ARMul_State*>(user_arg);
|
|
|
|
|
class DynarmicUserCallbacks final : public Dynarmic::A32::UserCallbacks {
|
|
|
|
|
public:
|
|
|
|
|
explicit DynarmicUserCallbacks(ARM_Dynarmic& parent) : parent(parent) {}
|
|
|
|
|
~DynarmicUserCallbacks() = default;
|
|
|
|
|
|
|
|
|
|
state->Reg = jit->Regs();
|
|
|
|
|
state->Cpsr = jit->Cpsr();
|
|
|
|
|
state->Reg[15] = pc;
|
|
|
|
|
state->ExtReg = jit->ExtRegs();
|
|
|
|
|
state->VFP[VFP_FPSCR] = jit->Fpscr();
|
|
|
|
|
state->NumInstrsToExecute = 1;
|
|
|
|
|
|
|
|
|
|
InterpreterMainLoop(state);
|
|
|
|
|
|
|
|
|
|
bool is_thumb = (state->Cpsr & (1 << 5)) != 0;
|
|
|
|
|
state->Reg[15] &= (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC);
|
|
|
|
|
|
|
|
|
|
jit->Regs() = state->Reg;
|
|
|
|
|
jit->SetCpsr(state->Cpsr);
|
|
|
|
|
jit->ExtRegs() = state->ExtReg;
|
|
|
|
|
jit->SetFpscr(state->VFP[VFP_FPSCR]);
|
|
|
|
|
|
|
|
|
|
state->ServeBreak();
|
|
|
|
|
std::uint8_t MemoryRead8(VAddr vaddr) override {
|
|
|
|
|
return Memory::Read8(vaddr);
|
|
|
|
|
}
|
|
|
|
|
std::uint16_t MemoryRead16(VAddr vaddr) override {
|
|
|
|
|
return Memory::Read16(vaddr);
|
|
|
|
|
}
|
|
|
|
|
std::uint32_t MemoryRead32(VAddr vaddr) override {
|
|
|
|
|
return Memory::Read32(vaddr);
|
|
|
|
|
}
|
|
|
|
|
std::uint64_t MemoryRead64(VAddr vaddr) override {
|
|
|
|
|
return Memory::Read64(vaddr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool IsReadOnlyMemory(u32 vaddr) {
|
|
|
|
|
// TODO(bunnei): ImplementMe
|
|
|
|
|
return false;
|
|
|
|
|
void MemoryWrite8(VAddr vaddr, std::uint8_t value) override {
|
|
|
|
|
Memory::Write8(vaddr, value);
|
|
|
|
|
}
|
|
|
|
|
void MemoryWrite16(VAddr vaddr, std::uint16_t value) override {
|
|
|
|
|
Memory::Write16(vaddr, value);
|
|
|
|
|
}
|
|
|
|
|
void MemoryWrite32(VAddr vaddr, std::uint32_t value) override {
|
|
|
|
|
Memory::Write32(vaddr, value);
|
|
|
|
|
}
|
|
|
|
|
void MemoryWrite64(VAddr vaddr, std::uint64_t value) override {
|
|
|
|
|
Memory::Write64(vaddr, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void AddTicks(u64 ticks) {
|
|
|
|
|
void InterpreterFallback(VAddr pc, size_t num_instructions) override {
|
|
|
|
|
parent.interpreter_state->Reg = parent.jit->Regs();
|
|
|
|
|
parent.interpreter_state->Cpsr = parent.jit->Cpsr();
|
|
|
|
|
parent.interpreter_state->Reg[15] = pc;
|
|
|
|
|
parent.interpreter_state->ExtReg = parent.jit->ExtRegs();
|
|
|
|
|
parent.interpreter_state->VFP[VFP_FPSCR] = parent.jit->Fpscr();
|
|
|
|
|
parent.interpreter_state->NumInstrsToExecute = num_instructions;
|
|
|
|
|
|
|
|
|
|
InterpreterMainLoop(parent.interpreter_state.get());
|
|
|
|
|
|
|
|
|
|
bool is_thumb = (parent.interpreter_state->Cpsr & (1 << 5)) != 0;
|
|
|
|
|
parent.interpreter_state->Reg[15] &= (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC);
|
|
|
|
|
|
|
|
|
|
parent.jit->Regs() = parent.interpreter_state->Reg;
|
|
|
|
|
parent.jit->SetCpsr(parent.interpreter_state->Cpsr);
|
|
|
|
|
parent.jit->ExtRegs() = parent.interpreter_state->ExtReg;
|
|
|
|
|
parent.jit->SetFpscr(parent.interpreter_state->VFP[VFP_FPSCR]);
|
|
|
|
|
|
|
|
|
|
parent.interpreter_state->ServeBreak();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CallSVC(std::uint32_t swi) override {
|
|
|
|
|
Kernel::CallSVC(swi);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ExceptionRaised(VAddr pc, Dynarmic::A32::Exception exception) override {
|
|
|
|
|
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})",
|
|
|
|
|
static_cast<size_t>(exception), pc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AddTicks(std::uint64_t ticks) override {
|
|
|
|
|
CoreTiming::AddTicks(ticks);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static u64 GetTicksRemaining() {
|
|
|
|
|
std::uint64_t GetTicksRemaining() override {
|
|
|
|
|
s64 ticks = CoreTiming::GetDowncount();
|
|
|
|
|
return static_cast<u64>(ticks <= 0 ? 0 : ticks);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Dynarmic::UserCallbacks GetUserCallbacks(
|
|
|
|
|
const std::shared_ptr<ARMul_State>& interpreter_state, Memory::PageTable* current_page_table) {
|
|
|
|
|
Dynarmic::UserCallbacks user_callbacks{};
|
|
|
|
|
user_callbacks.InterpreterFallback = &InterpreterFallback;
|
|
|
|
|
user_callbacks.user_arg = static_cast<void*>(interpreter_state.get());
|
|
|
|
|
user_callbacks.CallSVC = &Kernel::CallSVC;
|
|
|
|
|
user_callbacks.memory.IsReadOnlyMemory = &IsReadOnlyMemory;
|
|
|
|
|
user_callbacks.memory.ReadCode = &Memory::Read32;
|
|
|
|
|
user_callbacks.memory.Read8 = &Memory::Read8;
|
|
|
|
|
user_callbacks.memory.Read16 = &Memory::Read16;
|
|
|
|
|
user_callbacks.memory.Read32 = &Memory::Read32;
|
|
|
|
|
user_callbacks.memory.Read64 = &Memory::Read64;
|
|
|
|
|
user_callbacks.memory.Write8 = &Memory::Write8;
|
|
|
|
|
user_callbacks.memory.Write16 = &Memory::Write16;
|
|
|
|
|
user_callbacks.memory.Write32 = &Memory::Write32;
|
|
|
|
|
user_callbacks.memory.Write64 = &Memory::Write64;
|
|
|
|
|
user_callbacks.AddTicks = &AddTicks;
|
|
|
|
|
user_callbacks.GetTicksRemaining = &GetTicksRemaining;
|
|
|
|
|
user_callbacks.page_table = ¤t_page_table->pointers;
|
|
|
|
|
user_callbacks.coprocessors[15] = std::make_shared<DynarmicCP15>(interpreter_state);
|
|
|
|
|
return user_callbacks;
|
|
|
|
|
}
|
|
|
|
|
ARM_Dynarmic& parent;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ARM_Dynarmic::ARM_Dynarmic(PrivilegeMode initial_mode) {
|
|
|
|
|
ARM_Dynarmic::ARM_Dynarmic(PrivilegeMode initial_mode)
|
|
|
|
|
: cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
|
|
|
|
|
interpreter_state = std::make_shared<ARMul_State>(initial_mode);
|
|
|
|
|
PageTableChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ARM_Dynarmic::~ARM_Dynarmic() = default;
|
|
|
|
|
|
|
|
|
|
MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64));
|
|
|
|
|
|
|
|
|
|
void ARM_Dynarmic::Run() {
|
|
|
|
|
ASSERT(Memory::GetCurrentPageTable() == current_page_table);
|
|
|
|
|
MICROPROFILE_SCOPE(ARM_Jit);
|
|
|
|
|
|
|
|
|
|
jit->Run(GetTicksRemaining());
|
|
|
|
|
jit->Run();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ARM_Dynarmic::Step() {
|
|
|
|
|
InterpreterFallback(jit->Regs()[15], jit, static_cast<void*>(interpreter_state.get()));
|
|
|
|
|
cb->InterpreterFallback(jit->Regs()[15], 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ARM_Dynarmic::SetPC(u32 pc) {
|
|
|
|
@ -251,6 +266,16 @@ void ARM_Dynarmic::PageTableChanged() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jit = new Dynarmic::Jit(GetUserCallbacks(interpreter_state, current_page_table));
|
|
|
|
|
jits.emplace(current_page_table, std::unique_ptr<Dynarmic::Jit>(jit));
|
|
|
|
|
auto new_jit = MakeJit();
|
|
|
|
|
jit = new_jit.get();
|
|
|
|
|
jits.emplace(current_page_table, std::move(new_jit));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<Dynarmic::A32::Jit> ARM_Dynarmic::MakeJit() {
|
|
|
|
|
Dynarmic::A32::UserConfig config;
|
|
|
|
|
config.callbacks = cb.get();
|
|
|
|
|
config.page_table = ¤t_page_table->pointers;
|
|
|
|
|
config.coprocessors[15] = std::make_shared<DynarmicCP15>(interpreter_state);
|
|
|
|
|
config.define_unpredictable_behaviour = true;
|
|
|
|
|
return std::make_unique<Dynarmic::A32::Jit>(config);
|
|
|
|
|
}
|
|
|
|
|