21 changed files with 454 additions and 122 deletions
-
6src/core/CMakeLists.txt
-
32src/core/arm/arm_interface.h
-
208src/core/arm/dynarmic/arm_dynarmic_32.cpp
-
77src/core/arm/dynarmic/arm_dynarmic_32.h
-
74src/core/arm/dynarmic/arm_dynarmic_64.cpp
-
30src/core/arm/dynarmic/arm_dynarmic_64.h
-
2src/core/arm/exclusive_monitor.cpp
-
8src/core/arm/unicorn/arm_unicorn.cpp
-
7src/core/arm/unicorn/arm_unicorn.h
-
3src/core/core_manager.cpp
-
14src/core/gdbstub/gdbstub.cpp
-
4src/core/hle/kernel/kernel.cpp
-
19src/core/hle/kernel/physical_core.cpp
-
6src/core/hle/kernel/physical_core.h
-
3src/core/hle/kernel/process.cpp
-
21src/core/hle/kernel/scheduler.cpp
-
3src/core/hle/kernel/scheduler.h
-
31src/core/hle/kernel/thread.cpp
-
22src/core/hle/kernel/thread.h
-
2src/core/reporter.cpp
-
4src/yuzu/debugger/wait_tree.cpp
@ -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 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue