Merge pull request #193 from N00byKing/3184_2_robotic_boogaloo

Implement Pull #3184 from citra: core/arm: Improve timing accuracy before service calls in JIT (Rebased)
master
bunnei 2018-03-18 22:35:47 +07:00 committed by GitHub
commit 23a0d2d7b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 41 additions and 41 deletions

@ -25,19 +25,11 @@ public:
VAddr tls_address; VAddr tls_address;
}; };
/** /// Runs the CPU until an event happens
* Runs the CPU for the given number of instructions virtual void Run() = 0;
* @param num_instructions Number of instructions to run
*/
void Run(int num_instructions) {
ExecuteInstructions(num_instructions);
this->num_instructions += num_instructions;
}
/// Step CPU by one instruction /// Step CPU by one instruction
void Step() { virtual void Step() = 0;
Run(1);
}
/// Maps a backing memory region for the CPU /// Maps a backing memory region for the CPU
virtual void MapBackingMemory(VAddr address, size_t size, u8* memory, virtual void MapBackingMemory(VAddr address, size_t size, u8* memory,
@ -126,19 +118,4 @@ public:
/// Prepare core for thread reschedule (if needed to correctly handle state) /// Prepare core for thread reschedule (if needed to correctly handle state)
virtual void PrepareReschedule() = 0; virtual void PrepareReschedule() = 0;
/// Getter for num_instructions
u64 GetNumInstructions() const {
return num_instructions;
}
protected:
/**
* Executes the given number of instructions
* @param num_instructions Number of instructions to executes
*/
virtual void ExecuteInstructions(int num_instructions) = 0;
private:
u64 num_instructions = 0; ///< Number of instructions executed
}; };

@ -122,11 +122,22 @@ std::unique_ptr<Dynarmic::A64::Jit> MakeJit(const std::unique_ptr<ARM_Dynarmic_C
return std::make_unique<Dynarmic::A64::Jit>(config); return std::make_unique<Dynarmic::A64::Jit>(config);
} }
void ARM_Dynarmic::Run() {
ASSERT(Memory::GetCurrentPageTable() == current_page_table);
jit->Run();
}
void ARM_Dynarmic::Step() {
cb->InterpreterFallback(jit->GetPC(), 1);
}
ARM_Dynarmic::ARM_Dynarmic() ARM_Dynarmic::ARM_Dynarmic()
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), jit(MakeJit(cb)) { : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), jit(MakeJit(cb)) {
ARM_Interface::ThreadContext ctx; ARM_Interface::ThreadContext ctx;
inner_unicorn.SaveContext(ctx); inner_unicorn.SaveContext(ctx);
LoadContext(ctx); LoadContext(ctx);
PageTableChanged();
} }
ARM_Dynarmic::~ARM_Dynarmic() = default; ARM_Dynarmic::~ARM_Dynarmic() = default;
@ -189,13 +200,6 @@ void ARM_Dynarmic::SetTlsAddress(u64 address) {
cb->tpidrro_el0 = address; cb->tpidrro_el0 = address;
} }
void ARM_Dynarmic::ExecuteInstructions(int num_instructions) {
cb->ticks_remaining = num_instructions;
jit->Run();
CoreTiming::AddTicks(num_instructions - cb->num_interpreted_instructions);
cb->num_interpreted_instructions = 0;
}
void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) { void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
ctx.cpu_registers = jit->GetRegisters(); ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP(); ctx.sp = jit->GetSP();
@ -228,4 +232,5 @@ void ARM_Dynarmic::ClearInstructionCache() {
void ARM_Dynarmic::PageTableChanged() { void ARM_Dynarmic::PageTableChanged() {
jit = MakeJit(cb); jit = MakeJit(cb);
current_page_table = Memory::GetCurrentPageTable();
} }

@ -29,6 +29,8 @@ public:
u32 GetVFPReg(int index) const override; u32 GetVFPReg(int index) const override;
void SetVFPReg(int index, u32 value) override; void SetVFPReg(int index, u32 value) override;
u32 GetCPSR() const override; u32 GetCPSR() const override;
void Run() override;
void Step() override;
void SetCPSR(u32 cpsr) override; void SetCPSR(u32 cpsr) override;
VAddr GetTlsAddress() const override; VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override; void SetTlsAddress(VAddr address) override;
@ -37,7 +39,6 @@ public:
void LoadContext(const ThreadContext& ctx) override; void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override; void PrepareReschedule() override;
void ExecuteInstructions(int num_instructions) override;
void ClearInstructionCache() override; void ClearInstructionCache() override;
void PageTableChanged() override; void PageTableChanged() override;
@ -47,4 +48,6 @@ private:
std::unique_ptr<ARM_Dynarmic_Callbacks> cb; std::unique_ptr<ARM_Dynarmic_Callbacks> cb;
std::unique_ptr<Dynarmic::A64::Jit> jit; std::unique_ptr<Dynarmic::A64::Jit> jit;
ARM_Unicorn inner_unicorn; ARM_Unicorn inner_unicorn;
Memory::PageTable* current_page_table = nullptr;
}; };

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <algorithm>
#include <unicorn/arm64.h> #include <unicorn/arm64.h>
#include "common/assert.h" #include "common/assert.h"
#include "common/microprofile.h" #include "common/microprofile.h"
@ -153,6 +154,14 @@ void ARM_Unicorn::SetTlsAddress(VAddr base) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base)); CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
} }
void ARM_Unicorn::Run() {
ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0));
}
void ARM_Unicorn::Step() {
ExecuteInstructions(1);
}
MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64)); MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64));
void ARM_Unicorn::ExecuteInstructions(int num_instructions) { void ARM_Unicorn::ExecuteInstructions(int num_instructions) {

@ -30,7 +30,9 @@ public:
void SaveContext(ThreadContext& ctx) override; void SaveContext(ThreadContext& ctx) override;
void LoadContext(const ThreadContext& ctx) override; void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override; void PrepareReschedule() override;
void ExecuteInstructions(int num_instructions) override; void ExecuteInstructions(int num_instructions);
void Run() override;
void Step() override;
void ClearInstructionCache() override; void ClearInstructionCache() override;
void PageTableChanged() override{}; void PageTableChanged() override{};

@ -26,7 +26,7 @@ namespace Core {
/*static*/ System System::s_instance; /*static*/ System System::s_instance;
System::ResultStatus System::RunLoop(int tight_loop) { System::ResultStatus System::RunLoop(bool tight_loop) {
status = ResultStatus::Success; status = ResultStatus::Success;
if (!cpu_core) { if (!cpu_core) {
return ResultStatus::ErrorNotInitialized; return ResultStatus::ErrorNotInitialized;
@ -40,7 +40,7 @@ System::ResultStatus System::RunLoop(int tight_loop) {
if (GDBStub::GetCpuHaltFlag()) { if (GDBStub::GetCpuHaltFlag()) {
if (GDBStub::GetCpuStepFlag()) { if (GDBStub::GetCpuStepFlag()) {
GDBStub::SetCpuStepFlag(false); GDBStub::SetCpuStepFlag(false);
tight_loop = 1; tight_loop = false;
} else { } else {
return ResultStatus::Success; return ResultStatus::Success;
} }
@ -56,7 +56,11 @@ System::ResultStatus System::RunLoop(int tight_loop) {
PrepareReschedule(); PrepareReschedule();
} else { } else {
CoreTiming::Advance(); CoreTiming::Advance();
cpu_core->Run(tight_loop); if (tight_loop) {
cpu_core->Run();
} else {
cpu_core->Step();
}
} }
HW::Update(); HW::Update();
@ -66,7 +70,7 @@ System::ResultStatus System::RunLoop(int tight_loop) {
} }
System::ResultStatus System::SingleStep() { System::ResultStatus System::SingleStep() {
return RunLoop(1); return RunLoop(false);
} }
System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) { System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) {

@ -53,10 +53,10 @@ public:
* is not required to do a full dispatch with each instruction. NOTE: the number of instructions * is not required to do a full dispatch with each instruction. NOTE: the number of instructions
* requested is not guaranteed to run, as this will be interrupted preemptively if a hardware * requested is not guaranteed to run, as this will be interrupted preemptively if a hardware
* update is requested (e.g. on a thread switch). * update is requested (e.g. on a thread switch).
* @param tight_loop Number of instructions to execute. * @param tight_loop If false, the CPU single-steps.
* @return Result status, indicating whether or not the operation succeeded. * @return Result status, indicating whether or not the operation succeeded.
*/ */
ResultStatus RunLoop(int tight_loop = 100000); ResultStatus RunLoop(bool tight_loop = true);
/** /**
* Step the CPU one instruction * Step the CPU one instruction