Implement halt_reason
* Provide reason for halting and atomically update this. * Allow user to specify a halt reason and return this information on halt. * Check if halt was requested prior to starting execution.
This commit is contained in:
parent
116297ccd5
commit
aac1f6ab1b
12 changed files with 136 additions and 53 deletions
|
@ -1206,7 +1206,7 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescr
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
void A32EmitX64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||||
code.cmp(code.byte[r15 + offsetof(A32JitState, halt_requested)], u8(0));
|
code.cmp(dword[r15 + offsetof(A32JitState, halt_reason)], 0);
|
||||||
code.jne(code.GetForceReturnFromRunCodeAddress());
|
code.jne(code.GetForceReturnFromRunCodeAddress());
|
||||||
EmitTerminal(terminal.else_, initial_location, is_single_step);
|
EmitTerminal(terminal.else_, initial_location, is_single_step);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "dynarmic/backend/x64/devirtualize.h"
|
#include "dynarmic/backend/x64/devirtualize.h"
|
||||||
#include "dynarmic/backend/x64/jitstate_info.h"
|
#include "dynarmic/backend/x64/jitstate_info.h"
|
||||||
#include "dynarmic/common/assert.h"
|
#include "dynarmic/common/assert.h"
|
||||||
|
#include "dynarmic/common/atomic.h"
|
||||||
#include "dynarmic/common/cast_util.h"
|
#include "dynarmic/common/cast_util.h"
|
||||||
#include "dynarmic/common/common_types.h"
|
#include "dynarmic/common/common_types.h"
|
||||||
#include "dynarmic/common/scope_exit.h"
|
#include "dynarmic/common/scope_exit.h"
|
||||||
|
@ -76,7 +77,7 @@ struct Jit::Impl {
|
||||||
boost::icl::interval_set<u32> invalid_cache_ranges;
|
boost::icl::interval_set<u32> invalid_cache_ranges;
|
||||||
bool invalidate_entire_cache = false;
|
bool invalidate_entire_cache = false;
|
||||||
|
|
||||||
void Execute() {
|
HaltReason Execute() {
|
||||||
const CodePtr current_codeptr = [this] {
|
const CodePtr current_codeptr = [this] {
|
||||||
// RSB optimization
|
// RSB optimization
|
||||||
const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A32JitState::RSBPtrMask;
|
const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A32JitState::RSBPtrMask;
|
||||||
|
@ -88,11 +89,15 @@ struct Jit::Impl {
|
||||||
return GetCurrentBlock();
|
return GetCurrentBlock();
|
||||||
}();
|
}();
|
||||||
|
|
||||||
block_of_code.RunCode(&jit_state, current_codeptr);
|
return block_of_code.RunCode(&jit_state, current_codeptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Step() {
|
HaltReason Step() {
|
||||||
block_of_code.StepCode(&jit_state, GetCurrentSingleStep());
|
return block_of_code.StepCode(&jit_state, GetCurrentSingleStep());
|
||||||
|
}
|
||||||
|
|
||||||
|
void HaltExecution(HaltReason hr) {
|
||||||
|
Atomic::Or(&jit_state.halt_reason, static_cast<u32>(hr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearExclusiveState() {
|
void ClearExclusiveState() {
|
||||||
|
@ -123,7 +128,7 @@ struct Jit::Impl {
|
||||||
|
|
||||||
void RequestCacheInvalidation() {
|
void RequestCacheInvalidation() {
|
||||||
if (jit_interface->is_executing) {
|
if (jit_interface->is_executing) {
|
||||||
jit_state.halt_requested = true;
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,28 +187,28 @@ Jit::Jit(UserConfig conf)
|
||||||
|
|
||||||
Jit::~Jit() = default;
|
Jit::~Jit() = default;
|
||||||
|
|
||||||
void Jit::Run() {
|
HaltReason Jit::Run() {
|
||||||
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;
|
const HaltReason hr = impl->Execute();
|
||||||
|
|
||||||
impl->Execute();
|
|
||||||
|
|
||||||
impl->PerformCacheInvalidation();
|
impl->PerformCacheInvalidation();
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit::Step() {
|
HaltReason Jit::Step() {
|
||||||
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 = true;
|
const HaltReason hr = impl->Step();
|
||||||
|
|
||||||
impl->Step();
|
|
||||||
|
|
||||||
impl->PerformCacheInvalidation();
|
impl->PerformCacheInvalidation();
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit::ClearCache() {
|
void Jit::ClearCache() {
|
||||||
|
@ -221,8 +226,8 @@ void Jit::Reset() {
|
||||||
impl->jit_state = {};
|
impl->jit_state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit::HaltExecution() {
|
void Jit::HaltExecution(HaltReason hr) {
|
||||||
impl->jit_state.halt_requested = true;
|
impl->HaltExecution(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit::ClearExclusiveState() {
|
void Jit::ClearExclusiveState() {
|
||||||
|
|
|
@ -40,7 +40,7 @@ struct A32JitState {
|
||||||
// For internal use (See: BlockOfCode::RunCode)
|
// For internal use (See: BlockOfCode::RunCode)
|
||||||
u32 guest_MXCSR = 0x00001f80;
|
u32 guest_MXCSR = 0x00001f80;
|
||||||
u32 asimd_MXCSR = 0x00009fc0;
|
u32 asimd_MXCSR = 0x00009fc0;
|
||||||
bool halt_requested = false;
|
volatile u32 halt_reason = 0;
|
||||||
|
|
||||||
// Exclusive state
|
// Exclusive state
|
||||||
u32 exclusive_state = 0;
|
u32 exclusive_state = 0;
|
||||||
|
|
|
@ -691,7 +691,7 @@ void A64EmitX64::EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescr
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
void A64EmitX64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||||
code.cmp(code.byte[r15 + offsetof(A64JitState, halt_requested)], u8(0));
|
code.cmp(dword[r15 + offsetof(A64JitState, halt_reason)], 0);
|
||||||
code.jne(code.GetForceReturnFromRunCodeAddress());
|
code.jne(code.GetForceReturnFromRunCodeAddress());
|
||||||
EmitTerminal(terminal.else_, initial_location, is_single_step);
|
EmitTerminal(terminal.else_, initial_location, is_single_step);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "dynarmic/backend/x64/devirtualize.h"
|
#include "dynarmic/backend/x64/devirtualize.h"
|
||||||
#include "dynarmic/backend/x64/jitstate_info.h"
|
#include "dynarmic/backend/x64/jitstate_info.h"
|
||||||
#include "dynarmic/common/assert.h"
|
#include "dynarmic/common/assert.h"
|
||||||
|
#include "dynarmic/common/atomic.h"
|
||||||
#include "dynarmic/common/scope_exit.h"
|
#include "dynarmic/common/scope_exit.h"
|
||||||
#include "dynarmic/common/x64_disassemble.h"
|
#include "dynarmic/common/x64_disassemble.h"
|
||||||
#include "dynarmic/frontend/A64/translate/a64_translate.h"
|
#include "dynarmic/frontend/A64/translate/a64_translate.h"
|
||||||
|
@ -63,13 +64,12 @@ public:
|
||||||
|
|
||||||
~Impl() = default;
|
~Impl() = default;
|
||||||
|
|
||||||
void Run() {
|
HaltReason Run() {
|
||||||
ASSERT(!is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation();
|
PerformRequestedCacheInvalidation();
|
||||||
|
|
||||||
is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT { this->is_executing = false; };
|
SCOPE_EXIT { this->is_executing = false; };
|
||||||
jit_state.halt_requested = false;
|
|
||||||
|
|
||||||
// TODO: Check code alignment
|
// TODO: Check code alignment
|
||||||
|
|
||||||
|
@ -83,29 +83,33 @@ public:
|
||||||
|
|
||||||
return GetCurrentBlock();
|
return GetCurrentBlock();
|
||||||
}();
|
}();
|
||||||
block_of_code.RunCode(&jit_state, current_code_ptr);
|
|
||||||
|
const HaltReason hr = block_of_code.RunCode(&jit_state, current_code_ptr);
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation();
|
PerformRequestedCacheInvalidation();
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Step() {
|
HaltReason Step() {
|
||||||
ASSERT(!is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation();
|
PerformRequestedCacheInvalidation();
|
||||||
|
|
||||||
is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT { this->is_executing = false; };
|
SCOPE_EXIT { this->is_executing = false; };
|
||||||
jit_state.halt_requested = true;
|
|
||||||
|
|
||||||
block_of_code.StepCode(&jit_state, GetCurrentSingleStep());
|
const HaltReason hr = block_of_code.StepCode(&jit_state, GetCurrentSingleStep());
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation();
|
PerformRequestedCacheInvalidation();
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearCache() {
|
void ClearCache() {
|
||||||
std::unique_lock lock{invalidation_mutex};
|
std::unique_lock lock{invalidation_mutex};
|
||||||
invalidate_entire_cache = true;
|
invalidate_entire_cache = true;
|
||||||
if (is_executing) {
|
if (is_executing) {
|
||||||
jit_state.halt_requested = true;
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +119,7 @@ public:
|
||||||
const auto range = boost::icl::discrete_interval<u64>::closed(start_address, end_address);
|
const auto range = boost::icl::discrete_interval<u64>::closed(start_address, end_address);
|
||||||
invalid_cache_ranges.add(range);
|
invalid_cache_ranges.add(range);
|
||||||
if (is_executing) {
|
if (is_executing) {
|
||||||
jit_state.halt_requested = true;
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,8 +128,8 @@ public:
|
||||||
jit_state = {};
|
jit_state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void HaltExecution() {
|
void HaltExecution(HaltReason hr) {
|
||||||
jit_state.halt_requested = true;
|
Atomic::Or(&jit_state.halt_reason, static_cast<u32>(hr));
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetSP() const {
|
u64 GetSP() const {
|
||||||
|
@ -279,7 +283,7 @@ private:
|
||||||
|
|
||||||
void RequestCacheInvalidation() {
|
void RequestCacheInvalidation() {
|
||||||
if (is_executing) {
|
if (is_executing) {
|
||||||
jit_state.halt_requested = true;
|
HaltExecution(HaltReason::CacheInvalidation);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,12 +325,12 @@ Jit::Jit(UserConfig conf)
|
||||||
|
|
||||||
Jit::~Jit() = default;
|
Jit::~Jit() = default;
|
||||||
|
|
||||||
void Jit::Run() {
|
HaltReason Jit::Run() {
|
||||||
impl->Run();
|
return impl->Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit::Step() {
|
HaltReason Jit::Step() {
|
||||||
impl->Step();
|
return impl->Step();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit::ClearCache() {
|
void Jit::ClearCache() {
|
||||||
|
@ -341,8 +345,8 @@ void Jit::Reset() {
|
||||||
impl->Reset();
|
impl->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit::HaltExecution() {
|
void Jit::HaltExecution(HaltReason hr) {
|
||||||
impl->HaltExecution();
|
impl->HaltExecution(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Jit::GetSP() const {
|
u64 Jit::GetSP() const {
|
||||||
|
|
|
@ -43,7 +43,7 @@ struct A64JitState {
|
||||||
// For internal use (See: BlockOfCode::RunCode)
|
// For internal use (See: BlockOfCode::RunCode)
|
||||||
u32 guest_MXCSR = 0x00001f80;
|
u32 guest_MXCSR = 0x00001f80;
|
||||||
u32 asimd_MXCSR = 0x00009fc0;
|
u32 asimd_MXCSR = 0x00009fc0;
|
||||||
bool halt_requested = false;
|
volatile u32 halt_reason = 0;
|
||||||
|
|
||||||
// Exclusive state
|
// Exclusive state
|
||||||
static constexpr u64 RESERVATION_GRANULE_MASK = 0xFFFF'FFFF'FFFF'FFF0ull;
|
static constexpr u64 RESERVATION_GRANULE_MASK = 0xFFFF'FFFF'FFFF'FFF0ull;
|
||||||
|
|
|
@ -201,12 +201,12 @@ size_t BlockOfCode::SpaceRemaining() const {
|
||||||
return std::min(reinterpret_cast<const u8*>(far_code_begin) - current_near_ptr, &top_[maxSize_] - current_far_ptr);
|
return std::min(reinterpret_cast<const u8*>(far_code_begin) - current_near_ptr, &top_[maxSize_] - current_far_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::RunCode(void* jit_state, CodePtr code_ptr) const {
|
HaltReason BlockOfCode::RunCode(void* jit_state, CodePtr code_ptr) const {
|
||||||
run_code(jit_state, code_ptr);
|
return run_code(jit_state, code_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::StepCode(void* jit_state, CodePtr code_ptr) const {
|
HaltReason BlockOfCode::StepCode(void* jit_state, CodePtr code_ptr) const {
|
||||||
step_code(jit_state, code_ptr);
|
return step_code(jit_state, code_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::ReturnFromRunCode(bool mxcsr_already_exited) {
|
void BlockOfCode::ReturnFromRunCode(bool mxcsr_already_exited) {
|
||||||
|
@ -224,6 +224,8 @@ void BlockOfCode::ForceReturnFromRunCode(bool mxcsr_already_exited) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
|
void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
|
||||||
|
Xbyak::Label return_to_caller, return_to_caller_mxcsr_already_exited;
|
||||||
|
|
||||||
align();
|
align();
|
||||||
run_code = getCurr<RunCodeFuncType>();
|
run_code = getCurr<RunCodeFuncType>();
|
||||||
|
|
||||||
|
@ -242,6 +244,9 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
|
||||||
|
|
||||||
rcp(*this);
|
rcp(*this);
|
||||||
|
|
||||||
|
cmp(dword[r15 + jsi.offsetof_halt_reason], 0);
|
||||||
|
jne(return_to_caller_mxcsr_already_exited, T_NEAR);
|
||||||
|
|
||||||
SwitchMxcsrOnEntry();
|
SwitchMxcsrOnEntry();
|
||||||
jmp(rbx);
|
jmp(rbx);
|
||||||
|
|
||||||
|
@ -257,16 +262,21 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
|
||||||
|
|
||||||
rcp(*this);
|
rcp(*this);
|
||||||
|
|
||||||
|
cmp(dword[r15 + jsi.offsetof_halt_reason], 0);
|
||||||
|
jne(return_to_caller_mxcsr_already_exited, T_NEAR);
|
||||||
|
lock();
|
||||||
|
or_(dword[r15 + jsi.offsetof_halt_reason], static_cast<u32>(HaltReason::Step));
|
||||||
|
|
||||||
SwitchMxcsrOnEntry();
|
SwitchMxcsrOnEntry();
|
||||||
jmp(ABI_PARAM2);
|
jmp(ABI_PARAM2);
|
||||||
|
|
||||||
// Dispatcher loop
|
// Dispatcher loop
|
||||||
|
|
||||||
Xbyak::Label return_to_caller, return_to_caller_mxcsr_already_exited;
|
|
||||||
|
|
||||||
align();
|
align();
|
||||||
return_from_run_code[0] = getCurr<const void*>();
|
return_from_run_code[0] = getCurr<const void*>();
|
||||||
|
|
||||||
|
cmp(dword[r15 + jsi.offsetof_halt_reason], 0);
|
||||||
|
jne(return_to_caller);
|
||||||
cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0);
|
cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0);
|
||||||
jng(return_to_caller);
|
jng(return_to_caller);
|
||||||
cb.LookupBlock->EmitCall(*this);
|
cb.LookupBlock->EmitCall(*this);
|
||||||
|
@ -275,6 +285,8 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
|
||||||
align();
|
align();
|
||||||
return_from_run_code[MXCSR_ALREADY_EXITED] = getCurr<const void*>();
|
return_from_run_code[MXCSR_ALREADY_EXITED] = getCurr<const void*>();
|
||||||
|
|
||||||
|
cmp(dword[r15 + jsi.offsetof_halt_reason], 0);
|
||||||
|
jne(return_to_caller_mxcsr_already_exited);
|
||||||
cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0);
|
cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0);
|
||||||
jng(return_to_caller_mxcsr_already_exited);
|
jng(return_to_caller_mxcsr_already_exited);
|
||||||
SwitchMxcsrOnEntry();
|
SwitchMxcsrOnEntry();
|
||||||
|
@ -296,6 +308,10 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
|
||||||
sub(param[0], qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)]);
|
sub(param[0], qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
xor_(eax, eax);
|
||||||
|
lock();
|
||||||
|
xchg(dword[r15 + jsi.offsetof_halt_reason], eax);
|
||||||
|
|
||||||
ABI_PopCalleeSaveRegistersAndAdjustStack(*this, sizeof(StackLayout));
|
ABI_PopCalleeSaveRegistersAndAdjustStack(*this, sizeof(StackLayout));
|
||||||
ret();
|
ret();
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "dynarmic/backend/x64/jitstate_info.h"
|
#include "dynarmic/backend/x64/jitstate_info.h"
|
||||||
#include "dynarmic/common/cast_util.h"
|
#include "dynarmic/common/cast_util.h"
|
||||||
#include "dynarmic/common/common_types.h"
|
#include "dynarmic/common/common_types.h"
|
||||||
|
#include "dynarmic/interface/halt_reason.h"
|
||||||
|
|
||||||
namespace Dynarmic::Backend::X64 {
|
namespace Dynarmic::Backend::X64 {
|
||||||
|
|
||||||
|
@ -50,9 +51,9 @@ public:
|
||||||
size_t SpaceRemaining() const;
|
size_t SpaceRemaining() const;
|
||||||
|
|
||||||
/// Runs emulated code from code_ptr.
|
/// Runs emulated code from code_ptr.
|
||||||
void RunCode(void* jit_state, CodePtr code_ptr) const;
|
HaltReason RunCode(void* jit_state, CodePtr code_ptr) const;
|
||||||
/// Runs emulated code from code_ptr for a single cycle.
|
/// Runs emulated code from code_ptr for a single cycle.
|
||||||
void StepCode(void* jit_state, CodePtr code_ptr) const;
|
HaltReason StepCode(void* jit_state, CodePtr code_ptr) const;
|
||||||
/// Code emitter: Returns to dispatcher
|
/// Code emitter: Returns to dispatcher
|
||||||
void ReturnFromRunCode(bool mxcsr_already_exited = false);
|
void ReturnFromRunCode(bool mxcsr_already_exited = false);
|
||||||
/// Code emitter: Returns to dispatcher, forces return to host
|
/// Code emitter: Returns to dispatcher, forces return to host
|
||||||
|
@ -183,7 +184,7 @@ private:
|
||||||
CodePtr near_code_ptr;
|
CodePtr near_code_ptr;
|
||||||
CodePtr far_code_ptr;
|
CodePtr far_code_ptr;
|
||||||
|
|
||||||
using RunCodeFuncType = void (*)(void*, CodePtr);
|
using RunCodeFuncType = HaltReason (*)(void*, CodePtr);
|
||||||
RunCodeFuncType run_code = nullptr;
|
RunCodeFuncType run_code = nullptr;
|
||||||
RunCodeFuncType step_code = nullptr;
|
RunCodeFuncType step_code = nullptr;
|
||||||
static constexpr size_t MXCSR_ALREADY_EXITED = 1 << 0;
|
static constexpr size_t MXCSR_ALREADY_EXITED = 1 << 0;
|
||||||
|
|
|
@ -20,7 +20,8 @@ struct JitStateInfo {
|
||||||
, offsetof_rsb_codeptrs(offsetof(JitStateType, rsb_codeptrs))
|
, offsetof_rsb_codeptrs(offsetof(JitStateType, rsb_codeptrs))
|
||||||
, offsetof_cpsr_nzcv(offsetof(JitStateType, cpsr_nzcv))
|
, offsetof_cpsr_nzcv(offsetof(JitStateType, cpsr_nzcv))
|
||||||
, offsetof_fpsr_exc(offsetof(JitStateType, fpsr_exc))
|
, offsetof_fpsr_exc(offsetof(JitStateType, fpsr_exc))
|
||||||
, offsetof_fpsr_qc(offsetof(JitStateType, fpsr_qc)) {}
|
, offsetof_fpsr_qc(offsetof(JitStateType, fpsr_qc))
|
||||||
|
, offsetof_halt_reason(offsetof(JitStateType, halt_reason)) {}
|
||||||
|
|
||||||
const size_t offsetof_guest_MXCSR;
|
const size_t offsetof_guest_MXCSR;
|
||||||
const size_t offsetof_asimd_MXCSR;
|
const size_t offsetof_asimd_MXCSR;
|
||||||
|
@ -31,6 +32,7 @@ struct JitStateInfo {
|
||||||
const size_t offsetof_cpsr_nzcv;
|
const size_t offsetof_cpsr_nzcv;
|
||||||
const size_t offsetof_fpsr_exc;
|
const size_t offsetof_fpsr_exc;
|
||||||
const size_t offsetof_fpsr_qc;
|
const size_t offsetof_fpsr_qc;
|
||||||
|
const size_t offsetof_halt_reason;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::X64
|
} // namespace Dynarmic::Backend::X64
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "dynarmic/interface/A32/config.h"
|
#include "dynarmic/interface/A32/config.h"
|
||||||
|
#include "dynarmic/interface/halt_reason.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace A32 {
|
namespace A32 {
|
||||||
|
@ -27,13 +28,13 @@ public:
|
||||||
* Runs the emulated CPU.
|
* Runs the emulated CPU.
|
||||||
* Cannot be recursively called.
|
* Cannot be recursively called.
|
||||||
*/
|
*/
|
||||||
void Run();
|
HaltReason Run();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Steps the emulated CPU.
|
* Steps the emulated CPU.
|
||||||
* Cannot be recursively called.
|
* Cannot be recursively called.
|
||||||
*/
|
*/
|
||||||
void Step();
|
HaltReason Step();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the code cache of all compiled code.
|
* Clears the code cache of all compiled code.
|
||||||
|
@ -58,7 +59,7 @@ public:
|
||||||
* Stops execution in Jit::Run.
|
* Stops execution in Jit::Run.
|
||||||
* Can only be called from a callback.
|
* Can only be called from a callback.
|
||||||
*/
|
*/
|
||||||
void HaltExecution();
|
void HaltExecution(HaltReason hr = HaltReason::UserDefined1);
|
||||||
|
|
||||||
/// View and modify registers.
|
/// View and modify registers.
|
||||||
std::array<std::uint32_t, 16>& Regs();
|
std::array<std::uint32_t, 16>& Regs();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "dynarmic/interface/A64/config.h"
|
#include "dynarmic/interface/A64/config.h"
|
||||||
|
#include "dynarmic/interface/halt_reason.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace A64 {
|
namespace A64 {
|
||||||
|
@ -28,13 +29,13 @@ public:
|
||||||
* Runs the emulated CPU.
|
* Runs the emulated CPU.
|
||||||
* Cannot be recursively called.
|
* Cannot be recursively called.
|
||||||
*/
|
*/
|
||||||
void Run();
|
HaltReason Run();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Step the emulated CPU for one instruction.
|
* Step the emulated CPU for one instruction.
|
||||||
* Cannot be recursively called.
|
* Cannot be recursively called.
|
||||||
*/
|
*/
|
||||||
void Step();
|
HaltReason Step();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the code cache of all compiled code.
|
* Clears the code cache of all compiled code.
|
||||||
|
@ -59,7 +60,7 @@ public:
|
||||||
* Stops execution in Jit::Run.
|
* Stops execution in Jit::Run.
|
||||||
* Can only be called from a callback.
|
* Can only be called from a callback.
|
||||||
*/
|
*/
|
||||||
void HaltExecution();
|
void HaltExecution(HaltReason hr = HaltReason::UserDefined1);
|
||||||
|
|
||||||
/// Read Stack Pointer
|
/// Read Stack Pointer
|
||||||
std::uint64_t GetSP() const;
|
std::uint64_t GetSP() const;
|
||||||
|
|
53
src/dynarmic/interface/halt_reason.h
Normal file
53
src/dynarmic/interface/halt_reason.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2020 MerryMage
|
||||||
|
* SPDX-License-Identifier: 0BSD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
|
||||||
|
enum class HaltReason : std::uint32_t {
|
||||||
|
Step = 0x00000001,
|
||||||
|
CacheInvalidation = 0x00000002,
|
||||||
|
UserDefined1 = 0x01000000,
|
||||||
|
UserDefined2 = 0x02000000,
|
||||||
|
UserDefined3 = 0x04000000,
|
||||||
|
UserDefined4 = 0x08000000,
|
||||||
|
UserDefined5 = 0x10000000,
|
||||||
|
UserDefined6 = 0x20000000,
|
||||||
|
UserDefined7 = 0x40000000,
|
||||||
|
UserDefined8 = 0x80000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr HaltReason operator~(HaltReason hr) {
|
||||||
|
return static_cast<HaltReason>(~static_cast<std::uint32_t>(hr));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr HaltReason operator|(HaltReason hr1, HaltReason hr2) {
|
||||||
|
return static_cast<HaltReason>(static_cast<std::uint32_t>(hr1) | static_cast<std::uint32_t>(hr2));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr HaltReason operator&(HaltReason hr1, HaltReason hr2) {
|
||||||
|
return static_cast<HaltReason>(static_cast<std::uint32_t>(hr1) & static_cast<std::uint32_t>(hr2));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr HaltReason operator|=(HaltReason& result, HaltReason hr) {
|
||||||
|
return result = (result | hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr HaltReason operator&=(HaltReason& result, HaltReason hr) {
|
||||||
|
return result = (result & hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!(HaltReason hr) {
|
||||||
|
return static_cast<std::uint32_t>(hr) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool Has(HaltReason hr1, HaltReason hr2) {
|
||||||
|
return (static_cast<std::uint32_t>(hr1) & static_cast<std::uint32_t>(hr2)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dynarmic
|
Loading…
Reference in a new issue