Merge branch 'timing'
We do this to improve timing information before entering a supervior function. We also do this to try and stay within JITted code as much as possible, by updating the cycles we have remaining.
This commit is contained in:
commit
2a818f9d8e
10 changed files with 38 additions and 13 deletions
|
@ -51,6 +51,10 @@ struct UserCallbacks {
|
||||||
// This callback is called whenever a SVC instruction is executed.
|
// This callback is called whenever a SVC instruction is executed.
|
||||||
void (*CallSVC)(std::uint32_t swi);
|
void (*CallSVC)(std::uint32_t swi);
|
||||||
|
|
||||||
|
// Timing-related callbacks
|
||||||
|
void (*AddTicks)(std::uint64_t ticks);
|
||||||
|
std::uint64_t (*GetTicksRemaining)();
|
||||||
|
|
||||||
// Page Table
|
// Page Table
|
||||||
// The page table is used for faster memory access. If an entry in the table is nullptr,
|
// The page table is used for faster memory access. If an entry in the table is nullptr,
|
||||||
// the JIT will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
|
// the JIT will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
|
||||||
|
|
|
@ -28,9 +28,8 @@ public:
|
||||||
* Runs the emulated CPU for about cycle_count cycles.
|
* Runs the emulated CPU for about cycle_count cycles.
|
||||||
* Cannot be recursively called.
|
* Cannot be recursively called.
|
||||||
* @param cycle_count Estimated number of cycles to run the CPU for.
|
* @param cycle_count Estimated number of cycles to run the CPU for.
|
||||||
* @returns Actual cycle count.
|
|
||||||
*/
|
*/
|
||||||
std::size_t Run(std::size_t cycle_count);
|
void Run(std::size_t cycle_count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the code cache of all compiled code.
|
* Clears the code cache of all compiled code.
|
||||||
|
|
|
@ -76,13 +76,13 @@ size_t BlockOfCode::SpaceRemaining() const {
|
||||||
return std::min(TOTAL_CODE_SIZE - far_code_offset, FAR_CODE_OFFSET - near_code_offset);
|
return std::min(TOTAL_CODE_SIZE - far_code_offset, FAR_CODE_OFFSET - near_code_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t BlockOfCode::RunCode(JitState* jit_state, size_t cycles_to_run) const {
|
void BlockOfCode::RunCode(JitState* jit_state, size_t cycles_to_run) const {
|
||||||
constexpr size_t max_cycles_to_run = static_cast<size_t>(std::numeric_limits<decltype(jit_state->cycles_remaining)>::max());
|
constexpr size_t max_cycles_to_run = static_cast<size_t>(std::numeric_limits<decltype(jit_state->cycles_remaining)>::max());
|
||||||
ASSERT(cycles_to_run <= max_cycles_to_run);
|
ASSERT(cycles_to_run <= max_cycles_to_run);
|
||||||
|
|
||||||
|
jit_state->cycles_to_run = cycles_to_run;
|
||||||
jit_state->cycles_remaining = cycles_to_run;
|
jit_state->cycles_remaining = cycles_to_run;
|
||||||
run_code(jit_state);
|
run_code(jit_state);
|
||||||
return cycles_to_run - jit_state->cycles_remaining; // Return number of cycles actually run.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::ReturnFromRunCode(bool MXCSR_switch) {
|
void BlockOfCode::ReturnFromRunCode(bool MXCSR_switch) {
|
||||||
|
@ -137,6 +137,10 @@ void BlockOfCode::GenRunCode() {
|
||||||
jg(loop);
|
jg(loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mov(ABI_PARAM1, qword[r15 + offsetof(JitState, cycles_to_run)]);
|
||||||
|
sub(ABI_PARAM1, qword[r15 + offsetof(JitState, cycles_remaining)]);
|
||||||
|
CallFunction(cb.AddTicks);
|
||||||
|
|
||||||
ABI_PopCalleeSaveRegistersAndAdjustStack(this);
|
ABI_PopCalleeSaveRegistersAndAdjustStack(this);
|
||||||
ret();
|
ret();
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,7 +32,7 @@ public:
|
||||||
size_t SpaceRemaining() const;
|
size_t SpaceRemaining() const;
|
||||||
|
|
||||||
/// Runs emulated code for approximately `cycles_to_run` cycles.
|
/// Runs emulated code for approximately `cycles_to_run` cycles.
|
||||||
size_t RunCode(JitState* jit_state, size_t cycles_to_run) const;
|
void RunCode(JitState* jit_state, size_t cycles_to_run) const;
|
||||||
/// Code emitter: Returns to dispatcher
|
/// Code emitter: Returns to dispatcher
|
||||||
void ReturnFromRunCode(bool MXCSR_switch = true);
|
void ReturnFromRunCode(bool MXCSR_switch = true);
|
||||||
/// Code emitter: Returns to dispatcher, forces return to host
|
/// Code emitter: Returns to dispatcher, forces return to host
|
||||||
|
|
|
@ -421,11 +421,21 @@ void EmitX64::EmitBXWritePC(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitCallSupervisor(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
|
void EmitX64::EmitCallSupervisor(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
|
||||||
auto args = reg_alloc.GetArgumentInfo(inst);
|
using namespace Xbyak::util;
|
||||||
reg_alloc.HostCall(nullptr, args[0]);
|
|
||||||
|
reg_alloc.HostCall(nullptr);
|
||||||
|
|
||||||
code->SwitchMxcsrOnExit();
|
code->SwitchMxcsrOnExit();
|
||||||
|
code->mov(code->ABI_PARAM1, qword[r15 + offsetof(JitState, cycles_to_run)]);
|
||||||
|
code->sub(code->ABI_PARAM1, qword[r15 + offsetof(JitState, cycles_remaining)]);
|
||||||
|
code->CallFunction(cb.AddTicks);
|
||||||
|
reg_alloc.EndOfAllocScope();
|
||||||
|
auto args = reg_alloc.GetArgumentInfo(inst);
|
||||||
|
reg_alloc.HostCall(nullptr, args[0]);
|
||||||
code->CallFunction(cb.CallSVC);
|
code->CallFunction(cb.CallSVC);
|
||||||
|
code->CallFunction(cb.GetTicksRemaining);
|
||||||
|
code->mov(qword[r15 + offsetof(JitState, cycles_to_run)], code->ABI_RETURN);
|
||||||
|
code->mov(qword[r15 + offsetof(JitState, cycles_remaining)], code->ABI_RETURN);
|
||||||
code->SwitchMxcsrOnEntry();
|
code->SwitchMxcsrOnEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,8 +48,8 @@ struct Jit::Impl {
|
||||||
std::deque<Common::AddressRange> invalid_cache_ranges;
|
std::deque<Common::AddressRange> invalid_cache_ranges;
|
||||||
bool invalidate_entire_cache = false;
|
bool invalidate_entire_cache = false;
|
||||||
|
|
||||||
size_t Execute(size_t cycle_count) {
|
void Execute(size_t cycle_count) {
|
||||||
return block_of_code.RunCode(&jit_state, cycle_count);
|
block_of_code.RunCode(&jit_state, cycle_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Disassemble(const IR::LocationDescriptor& descriptor) {
|
std::string Disassemble(const IR::LocationDescriptor& descriptor) {
|
||||||
|
@ -161,18 +161,16 @@ Jit::Jit(UserCallbacks callbacks) : impl(std::make_unique<Impl>(this, callbacks)
|
||||||
|
|
||||||
Jit::~Jit() {}
|
Jit::~Jit() {}
|
||||||
|
|
||||||
size_t Jit::Run(size_t cycle_count) {
|
void Jit::Run(size_t cycle_count) {
|
||||||
ASSERT(!is_executing);
|
ASSERT(!is_executing);
|
||||||
is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT({ this->is_executing = false; });
|
SCOPE_EXIT({ this->is_executing = false; });
|
||||||
|
|
||||||
impl->jit_state.halt_requested = false;
|
impl->jit_state.halt_requested = false;
|
||||||
|
|
||||||
size_t cycles_executed = impl->Execute(cycle_count);
|
impl->Execute(cycle_count);
|
||||||
|
|
||||||
impl->PerformCacheInvalidation();
|
impl->PerformCacheInvalidation();
|
||||||
|
|
||||||
return cycles_executed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit::ClearCache() {
|
void Jit::ClearCache() {
|
||||||
|
|
|
@ -36,6 +36,7 @@ struct JitState {
|
||||||
// For internal use (See: BlockOfCode::RunCode)
|
// For internal use (See: BlockOfCode::RunCode)
|
||||||
u32 guest_MXCSR = 0x00001f80;
|
u32 guest_MXCSR = 0x00001f80;
|
||||||
u32 save_host_MXCSR = 0;
|
u32 save_host_MXCSR = 0;
|
||||||
|
s64 cycles_to_run = 0;
|
||||||
s64 cycles_remaining = 0;
|
s64 cycles_remaining = 0;
|
||||||
bool halt_requested = false;
|
bool halt_requested = false;
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,8 @@ static void Fail() {
|
||||||
FAIL();
|
FAIL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AddTicks(u64) {}
|
||||||
|
|
||||||
static Dynarmic::UserCallbacks GetUserCallbacks() {
|
static Dynarmic::UserCallbacks GetUserCallbacks() {
|
||||||
Dynarmic::UserCallbacks user_callbacks{};
|
Dynarmic::UserCallbacks user_callbacks{};
|
||||||
user_callbacks.InterpreterFallback = &InterpreterFallback;
|
user_callbacks.InterpreterFallback = &InterpreterFallback;
|
||||||
|
@ -137,6 +139,7 @@ static Dynarmic::UserCallbacks GetUserCallbacks() {
|
||||||
user_callbacks.memory.Write16 = &MemoryWrite16;
|
user_callbacks.memory.Write16 = &MemoryWrite16;
|
||||||
user_callbacks.memory.Write32 = &MemoryWrite32;
|
user_callbacks.memory.Write32 = &MemoryWrite32;
|
||||||
user_callbacks.memory.Write64 = &MemoryWrite64;
|
user_callbacks.memory.Write64 = &MemoryWrite64;
|
||||||
|
user_callbacks.AddTicks = &AddTicks;
|
||||||
return user_callbacks;
|
return user_callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,8 @@ static void Fail() {
|
||||||
FAIL();
|
FAIL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AddTicks(u64) {}
|
||||||
|
|
||||||
static Dynarmic::UserCallbacks GetUserCallbacks() {
|
static Dynarmic::UserCallbacks GetUserCallbacks() {
|
||||||
Dynarmic::UserCallbacks user_callbacks{};
|
Dynarmic::UserCallbacks user_callbacks{};
|
||||||
user_callbacks.InterpreterFallback = &InterpreterFallback;
|
user_callbacks.InterpreterFallback = &InterpreterFallback;
|
||||||
|
@ -128,6 +130,7 @@ static Dynarmic::UserCallbacks GetUserCallbacks() {
|
||||||
user_callbacks.memory.Write16 = &MemoryWrite16;
|
user_callbacks.memory.Write16 = &MemoryWrite16;
|
||||||
user_callbacks.memory.Write32 = &MemoryWrite32;
|
user_callbacks.memory.Write32 = &MemoryWrite32;
|
||||||
user_callbacks.memory.Write64 = &MemoryWrite64;
|
user_callbacks.memory.Write64 = &MemoryWrite64;
|
||||||
|
user_callbacks.AddTicks = &AddTicks;
|
||||||
return user_callbacks;
|
return user_callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,11 +46,14 @@ static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void*) {
|
||||||
jit->Cpsr() = interp_state.Cpsr;
|
jit->Cpsr() = interp_state.Cpsr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AddTicks(u64) {}
|
||||||
|
|
||||||
static Dynarmic::UserCallbacks GetUserCallbacks() {
|
static Dynarmic::UserCallbacks GetUserCallbacks() {
|
||||||
Dynarmic::UserCallbacks user_callbacks{};
|
Dynarmic::UserCallbacks user_callbacks{};
|
||||||
user_callbacks.memory.Read32 = &MemoryRead32;
|
user_callbacks.memory.Read32 = &MemoryRead32;
|
||||||
user_callbacks.memory.ReadCode = &MemoryReadCode;
|
user_callbacks.memory.ReadCode = &MemoryReadCode;
|
||||||
user_callbacks.InterpreterFallback = &InterpreterFallback;
|
user_callbacks.InterpreterFallback = &InterpreterFallback;
|
||||||
|
user_callbacks.AddTicks = &AddTicks;
|
||||||
return user_callbacks;
|
return user_callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue