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
-
68src/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
-
29src/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