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)
This commit is contained in:
commit
23a0d2d7b7
|
@ -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
|
||||||
|
|
Reference in New Issue