Add AddTicks and GetTicksRemaining callbacks

This commit is contained in:
MerryMage 2017-12-03 02:42:22 +00:00
parent 80c56aa89d
commit 256749910f
10 changed files with 38 additions and 13 deletions

View file

@ -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.

View file

@ -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.

View file

@ -57,13 +57,13 @@ void BlockOfCode::ClearCache() {
SetCodePtr(near_code_begin); SetCodePtr(near_code_begin);
} }
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) {
@ -118,6 +118,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();
}; };

View file

@ -30,7 +30,7 @@ public:
void ClearCache(); void ClearCache();
/// 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

View file

@ -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();
} }

View file

@ -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) {
@ -155,18 +155,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() {

View file

@ -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;

View file

@ -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;
} }

View file

@ -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;
} }

View file

@ -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;
} }