core: Implement separate A32/A64 ARM interfaces.
parent
6fc485a607
commit
c083ea7d78
@ -0,0 +1,208 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cinttypes>
|
||||
#include <memory>
|
||||
#include <dynarmic/A32/a32.h>
|
||||
#include <dynarmic/A32/config.h>
|
||||
#include <dynarmic/A32/context.h>
|
||||
#include "common/microprofile.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_manager.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
|
||||
public:
|
||||
explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent) : parent(parent) {}
|
||||
|
||||
u8 MemoryRead8(u32 vaddr) override {
|
||||
return parent.system.Memory().Read8(vaddr);
|
||||
}
|
||||
u16 MemoryRead16(u32 vaddr) override {
|
||||
return parent.system.Memory().Read16(vaddr);
|
||||
}
|
||||
u32 MemoryRead32(u32 vaddr) override {
|
||||
return parent.system.Memory().Read32(vaddr);
|
||||
}
|
||||
u64 MemoryRead64(u32 vaddr) override {
|
||||
return parent.system.Memory().Read64(vaddr);
|
||||
}
|
||||
|
||||
void MemoryWrite8(u32 vaddr, u8 value) override {
|
||||
parent.system.Memory().Write8(vaddr, value);
|
||||
}
|
||||
void MemoryWrite16(u32 vaddr, u16 value) override {
|
||||
parent.system.Memory().Write16(vaddr, value);
|
||||
}
|
||||
void MemoryWrite32(u32 vaddr, u32 value) override {
|
||||
parent.system.Memory().Write32(vaddr, value);
|
||||
}
|
||||
void MemoryWrite64(u32 vaddr, u64 value) override {
|
||||
parent.system.Memory().Write64(vaddr, value);
|
||||
}
|
||||
|
||||
void InterpreterFallback(u32 pc, std::size_t num_instructions) override {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
|
||||
switch (exception) {
|
||||
case Dynarmic::A32::Exception::UndefinedInstruction:
|
||||
case Dynarmic::A32::Exception::UnpredictableInstruction:
|
||||
break;
|
||||
case Dynarmic::A32::Exception::Breakpoint:
|
||||
break;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
|
||||
static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void CallSVC(u32 swi) override {
|
||||
Kernel::CallSVC(parent.system, swi);
|
||||
}
|
||||
|
||||
void AddTicks(u64 ticks) override {
|
||||
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
|
||||
// rough approximation of the amount of executed ticks in the system, it may be thrown off
|
||||
// if not all cores are doing a similar amount of work. Instead of doing this, we should
|
||||
// device a way so that timing is consistent across all cores without increasing the ticks 4
|
||||
// times.
|
||||
u64 amortized_ticks = (ticks - num_interpreted_instructions) / Core::NUM_CPU_CORES;
|
||||
// Always execute at least one tick.
|
||||
amortized_ticks = std::max<u64>(amortized_ticks, 1);
|
||||
|
||||
parent.system.CoreTiming().AddTicks(amortized_ticks);
|
||||
num_interpreted_instructions = 0;
|
||||
}
|
||||
u64 GetTicksRemaining() override {
|
||||
return std::max(parent.system.CoreTiming().GetDowncount(), {});
|
||||
}
|
||||
|
||||
ARM_Dynarmic_32& parent;
|
||||
std::size_t num_interpreted_instructions{};
|
||||
u64 tpidrro_el0{};
|
||||
u64 tpidr_el0{};
|
||||
};
|
||||
|
||||
std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table,
|
||||
std::size_t address_space_bits) const {
|
||||
Dynarmic::A32::UserConfig config;
|
||||
config.callbacks = cb.get();
|
||||
// TODO(bunnei): Implement page table for 32-bit
|
||||
// config.page_table = &page_table.pointers;
|
||||
config.coprocessors[15] = std::make_shared<DynarmicCP15>((u32*)&CP15_regs[0]);
|
||||
config.define_unpredictable_behaviour = true;
|
||||
return std::make_unique<Dynarmic::A32::Jit>(config);
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_32, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64));
|
||||
|
||||
void ARM_Dynarmic_32::Run() {
|
||||
MICROPROFILE_SCOPE(ARM_Jit_Dynarmic_32);
|
||||
jit->Run();
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_32::Step() {
|
||||
cb->InterpreterFallback(jit->Regs()[15], 1);
|
||||
}
|
||||
|
||||
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, ExclusiveMonitor& exclusive_monitor,
|
||||
std::size_t core_index)
|
||||
: ARM_Interface{system},
|
||||
cb(std::make_unique<DynarmicCallbacks32>(*this)), core_index{core_index},
|
||||
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
|
||||
|
||||
ARM_Dynarmic_32::~ARM_Dynarmic_32() = default;
|
||||
|
||||
void ARM_Dynarmic_32::SetPC(u64 pc) {
|
||||
jit->Regs()[15] = static_cast<u32>(pc);
|
||||
}
|
||||
|
||||
u64 ARM_Dynarmic_32::GetPC() const {
|
||||
return jit->Regs()[15];
|
||||
}
|
||||
|
||||
u64 ARM_Dynarmic_32::GetReg(int index) const {
|
||||
return jit->Regs()[index];
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_32::SetReg(int index, u64 value) {
|
||||
jit->Regs()[index] = static_cast<u32>(value);
|
||||
}
|
||||
|
||||
u128 ARM_Dynarmic_32::GetVectorReg(int index) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_32::SetVectorReg(int index, u128 value) {}
|
||||
|
||||
u32 ARM_Dynarmic_32::GetPSTATE() const {
|
||||
return jit->Cpsr();
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_32::SetPSTATE(u32 cpsr) {
|
||||
jit->SetCpsr(cpsr);
|
||||
}
|
||||
|
||||
u64 ARM_Dynarmic_32::GetTlsAddress() const {
|
||||
return CP15_regs[static_cast<std::size_t>(CP15Register::CP15_THREAD_URO)];
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_32::SetTlsAddress(VAddr address) {
|
||||
CP15_regs[static_cast<std::size_t>(CP15Register::CP15_THREAD_URO)] = static_cast<u32>(address);
|
||||
}
|
||||
|
||||
u64 ARM_Dynarmic_32::GetTPIDR_EL0() const {
|
||||
return cb->tpidr_el0;
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) {
|
||||
cb->tpidr_el0 = value;
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
|
||||
Dynarmic::A32::Context context;
|
||||
jit->SaveContext(context);
|
||||
ctx.cpu_registers = context.Regs();
|
||||
ctx.cpsr = context.Cpsr();
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
|
||||
Dynarmic::A32::Context context;
|
||||
context.Regs() = ctx.cpu_registers;
|
||||
context.SetCpsr(ctx.cpsr);
|
||||
jit->LoadContext(context);
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_32::PrepareReschedule() {
|
||||
jit->HaltExecution();
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_32::ClearInstructionCache() {
|
||||
jit->ClearCache();
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_32::ClearExclusiveState() {}
|
||||
|
||||
void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
|
||||
std::size_t new_address_space_size_in_bits) {
|
||||
auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
|
||||
auto iter = jit_cache.find(key);
|
||||
if (iter != jit_cache.end()) {
|
||||
jit = iter->second;
|
||||
return;
|
||||
}
|
||||
jit = MakeJit(page_table, new_address_space_size_in_bits);
|
||||
jit_cache.emplace(key, jit);
|
||||
}
|
||||
|
||||
} // namespace Core
|
@ -0,0 +1,77 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <dynarmic/A32/a32.h>
|
||||
#include <dynarmic/A64/a64.h>
|
||||
#include <dynarmic/A64/exclusive_monitor.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/hash.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
|
||||
namespace Memory {
|
||||
class Memory;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
|
||||
class DynarmicCallbacks32;
|
||||
class DynarmicExclusiveMonitor;
|
||||
class System;
|
||||
|
||||
class ARM_Dynarmic_32 final : public ARM_Interface {
|
||||
public:
|
||||
ARM_Dynarmic_32(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
||||
~ARM_Dynarmic_32() override;
|
||||
|
||||
void SetPC(u64 pc) override;
|
||||
u64 GetPC() const override;
|
||||
u64 GetReg(int index) const override;
|
||||
void SetReg(int index, u64 value) override;
|
||||
u128 GetVectorReg(int index) const override;
|
||||
void SetVectorReg(int index, u128 value) override;
|
||||
u32 GetPSTATE() const override;
|
||||
void SetPSTATE(u32 pstate) override;
|
||||
void Run() override;
|
||||
void Step() override;
|
||||
VAddr GetTlsAddress() const override;
|
||||
void SetTlsAddress(VAddr address) override;
|
||||
void SetTPIDR_EL0(u64 value) override;
|
||||
u64 GetTPIDR_EL0() const override;
|
||||
|
||||
void SaveContext(ThreadContext32& ctx) override;
|
||||
void SaveContext(ThreadContext64& ctx) override {}
|
||||
void LoadContext(const ThreadContext32& ctx) override;
|
||||
void LoadContext(const ThreadContext64& ctx) override {}
|
||||
|
||||
void PrepareReschedule() override;
|
||||
void ClearExclusiveState() override;
|
||||
|
||||
void ClearInstructionCache() override;
|
||||
void PageTableChanged(Common::PageTable& new_page_table,
|
||||
std::size_t new_address_space_size_in_bits) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable& page_table,
|
||||
std::size_t address_space_bits) const;
|
||||
|
||||
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
|
||||
using JitCacheType =
|
||||
std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A32::Jit>, Common::PairHash>;
|
||||
|
||||
friend class DynarmicCallbacks32;
|
||||
std::unique_ptr<DynarmicCallbacks32> cb;
|
||||
JitCacheType jit_cache;
|
||||
std::shared_ptr<Dynarmic::A32::Jit> jit;
|
||||
std::size_t core_index;
|
||||
DynarmicExclusiveMonitor& exclusive_monitor;
|
||||
std::array<u32, 84> CP15_regs{};
|
||||
};
|
||||
|
||||
} // namespace Core
|
Loading…
Reference in New Issue