A32: Add Step
This commit is contained in:
parent
f69c77391e
commit
b6536115ef
6 changed files with 88 additions and 32 deletions
|
@ -35,6 +35,12 @@ public:
|
||||||
*/
|
*/
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Steps the emulated CPU.
|
||||||
|
* Cannot be recursively called.
|
||||||
|
*/
|
||||||
|
void Step();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the code cache of all compiled code.
|
* Clears the code cache of all compiled code.
|
||||||
* Can be called at any time. Halts execution if called within a callback.
|
* Can be called at any time. Halts execution if called within a callback.
|
||||||
|
|
|
@ -41,7 +41,7 @@ static RunCodeCallbacks GenRunCodeCallbacks(A32::UserCallbacks* cb, CodePtr (*Lo
|
||||||
|
|
||||||
struct Jit::Impl {
|
struct Jit::Impl {
|
||||||
Impl(Jit* jit, A32::UserConfig config)
|
Impl(Jit* jit, A32::UserConfig config)
|
||||||
: block_of_code(GenRunCodeCallbacks(config.callbacks, &GetCurrentBlock, this), JitStateInfo{jit_state})
|
: block_of_code(GenRunCodeCallbacks(config.callbacks, &GetCurrentBlockThunk, this), JitStateInfo{jit_state})
|
||||||
, emitter(block_of_code, config, jit)
|
, emitter(block_of_code, config, jit)
|
||||||
, config(std::move(config))
|
, config(std::move(config))
|
||||||
, jit_interface(jit)
|
, jit_interface(jit)
|
||||||
|
@ -59,13 +59,22 @@ struct Jit::Impl {
|
||||||
bool invalidate_entire_cache = false;
|
bool invalidate_entire_cache = false;
|
||||||
|
|
||||||
void Execute() {
|
void Execute() {
|
||||||
|
const CodePtr current_codeptr = [this]{
|
||||||
|
// 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;
|
||||||
if (jit_state.GetUniqueHash() == jit_state.rsb_location_descriptors[new_rsb_ptr]) {
|
if (jit_state.GetUniqueHash() == jit_state.rsb_location_descriptors[new_rsb_ptr]) {
|
||||||
jit_state.rsb_ptr = new_rsb_ptr;
|
jit_state.rsb_ptr = new_rsb_ptr;
|
||||||
block_of_code.RunCodeFrom(&jit_state, reinterpret_cast<CodePtr>(jit_state.rsb_codeptrs[new_rsb_ptr]));
|
return reinterpret_cast<CodePtr>(jit_state.rsb_codeptrs[new_rsb_ptr]);
|
||||||
} else {
|
|
||||||
block_of_code.RunCode(&jit_state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return GetCurrentBlock();
|
||||||
|
}();
|
||||||
|
|
||||||
|
block_of_code.RunCodeFrom(&jit_state, current_codeptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Step() {
|
||||||
|
block_of_code.StepCode(&jit_state, GetCurrentSingleStep());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Disassemble(const IR::LocationDescriptor& descriptor) {
|
std::string Disassemble(const IR::LocationDescriptor& descriptor) {
|
||||||
|
@ -109,16 +118,21 @@ struct Jit::Impl {
|
||||||
private:
|
private:
|
||||||
Jit* jit_interface;
|
Jit* jit_interface;
|
||||||
|
|
||||||
static CodePtr GetCurrentBlock(void* this_voidptr) {
|
static CodePtr GetCurrentBlockThunk(void* this_voidptr) {
|
||||||
Jit::Impl& this_ = *static_cast<Jit::Impl*>(this_voidptr);
|
Jit::Impl& this_ = *static_cast<Jit::Impl*>(this_voidptr);
|
||||||
A32JitState& jit_state = this_.jit_state;
|
return this_.GetCurrentBlock();
|
||||||
|
}
|
||||||
|
|
||||||
u32 pc = jit_state.Reg[15];
|
IR::LocationDescriptor GetCurrentLocation() const {
|
||||||
A32::PSR cpsr{jit_state.Cpsr()};
|
return IR::LocationDescriptor{jit_state.GetUniqueHash()};
|
||||||
A32::FPSCR fpscr{jit_state.upper_location_descriptor};
|
}
|
||||||
A32::LocationDescriptor descriptor{pc, cpsr, fpscr};
|
|
||||||
|
|
||||||
return this_.GetBasicBlock(descriptor).entrypoint;
|
CodePtr GetCurrentBlock() {
|
||||||
|
return GetBasicBlock(GetCurrentLocation()).entrypoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
CodePtr GetCurrentSingleStep() {
|
||||||
|
return GetBasicBlock(A32::LocationDescriptor{GetCurrentLocation()}.SetSingleStepping(true)).entrypoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
A32EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
|
A32EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
|
||||||
|
@ -159,6 +173,18 @@ void Jit::Run() {
|
||||||
impl->PerformCacheInvalidation();
|
impl->PerformCacheInvalidation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Jit::Step() {
|
||||||
|
ASSERT(!is_executing);
|
||||||
|
is_executing = true;
|
||||||
|
SCOPE_EXIT { this->is_executing = false; };
|
||||||
|
|
||||||
|
impl->jit_state.halt_requested = true;
|
||||||
|
|
||||||
|
impl->Step();
|
||||||
|
|
||||||
|
impl->PerformCacheInvalidation();
|
||||||
|
}
|
||||||
|
|
||||||
void Jit::ClearCache() {
|
void Jit::ClearCache() {
|
||||||
impl->invalidate_entire_cache = true;
|
impl->invalidate_entire_cache = true;
|
||||||
impl->RequestCacheInvalidation();
|
impl->RequestCacheInvalidation();
|
||||||
|
|
|
@ -11,11 +11,12 @@
|
||||||
namespace Dynarmic::A32 {
|
namespace Dynarmic::A32 {
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor) {
|
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor) {
|
||||||
o << fmt::format("{{{:08x},{},{},{:08x}}}",
|
o << fmt::format("{{{:08x},{},{},{:08x}{}}}",
|
||||||
descriptor.PC(),
|
descriptor.PC(),
|
||||||
descriptor.TFlag() ? "T" : "!T",
|
descriptor.TFlag() ? "T" : "!T",
|
||||||
descriptor.EFlag() ? "E" : "!E",
|
descriptor.EFlag() ? "E" : "!E",
|
||||||
descriptor.FPSCR().Value());
|
descriptor.FPSCR().Value(),
|
||||||
|
descriptor.SingleStepping() ? ",step" : "");
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,12 @@ public:
|
||||||
static constexpr u32 CPSR_MODE_MASK = 0x0600FE20;
|
static constexpr u32 CPSR_MODE_MASK = 0x0600FE20;
|
||||||
static constexpr u32 FPSCR_MODE_MASK = 0x07F70000;
|
static constexpr u32 FPSCR_MODE_MASK = 0x07F70000;
|
||||||
|
|
||||||
LocationDescriptor(u32 arm_pc, PSR cpsr, FPSCR fpscr)
|
LocationDescriptor(u32 arm_pc, PSR cpsr, FPSCR fpscr, bool single_stepping = false)
|
||||||
: arm_pc(arm_pc), cpsr(cpsr.Value() & CPSR_MODE_MASK), fpscr(fpscr.Value() & FPSCR_MODE_MASK) {}
|
: arm_pc(arm_pc)
|
||||||
|
, cpsr(cpsr.Value() & CPSR_MODE_MASK)
|
||||||
|
, fpscr(fpscr.Value() & FPSCR_MODE_MASK)
|
||||||
|
, single_stepping(single_stepping)
|
||||||
|
{}
|
||||||
|
|
||||||
explicit LocationDescriptor(const IR::LocationDescriptor& o) {
|
explicit LocationDescriptor(const IR::LocationDescriptor& o) {
|
||||||
arm_pc = static_cast<u32>(o.Value());
|
arm_pc = static_cast<u32>(o.Value());
|
||||||
|
@ -38,6 +42,7 @@ public:
|
||||||
cpsr.E((o.Value() >> 32) & 2);
|
cpsr.E((o.Value() >> 32) & 2);
|
||||||
fpscr = (o.Value() >> 32) & FPSCR_MODE_MASK;
|
fpscr = (o.Value() >> 32) & FPSCR_MODE_MASK;
|
||||||
cpsr.IT(ITState{static_cast<u8>(o.Value() >> 40)});
|
cpsr.IT(ITState{static_cast<u8>(o.Value() >> 40)});
|
||||||
|
single_stepping = (o.Value() >> 32) & 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 PC() const { return arm_pc; }
|
u32 PC() const { return arm_pc; }
|
||||||
|
@ -48,8 +53,10 @@ public:
|
||||||
A32::PSR CPSR() const { return cpsr; }
|
A32::PSR CPSR() const { return cpsr; }
|
||||||
A32::FPSCR FPSCR() const { return fpscr; }
|
A32::FPSCR FPSCR() const { return fpscr; }
|
||||||
|
|
||||||
|
bool SingleStepping() const { return single_stepping; }
|
||||||
|
|
||||||
bool operator == (const LocationDescriptor& o) const {
|
bool operator == (const LocationDescriptor& o) const {
|
||||||
return std::tie(arm_pc, cpsr, fpscr) == std::tie(o.arm_pc, o.cpsr, o.fpscr);
|
return std::tie(arm_pc, cpsr, fpscr, single_stepping) == std::tie(o.arm_pc, o.cpsr, o.fpscr, single_stepping);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator != (const LocationDescriptor& o) const {
|
bool operator != (const LocationDescriptor& o) const {
|
||||||
|
@ -57,36 +64,40 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor SetPC(u32 new_arm_pc) const {
|
LocationDescriptor SetPC(u32 new_arm_pc) const {
|
||||||
return LocationDescriptor(new_arm_pc, cpsr, fpscr);
|
return LocationDescriptor(new_arm_pc, cpsr, fpscr, single_stepping);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor AdvancePC(int amount) const {
|
LocationDescriptor AdvancePC(int amount) const {
|
||||||
return LocationDescriptor(static_cast<u32>(arm_pc + amount), cpsr, fpscr);
|
return LocationDescriptor(static_cast<u32>(arm_pc + amount), cpsr, fpscr, single_stepping);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor SetTFlag(bool new_tflag) const {
|
LocationDescriptor SetTFlag(bool new_tflag) const {
|
||||||
PSR new_cpsr = cpsr;
|
PSR new_cpsr = cpsr;
|
||||||
new_cpsr.T(new_tflag);
|
new_cpsr.T(new_tflag);
|
||||||
|
|
||||||
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
return LocationDescriptor(arm_pc, new_cpsr, fpscr, single_stepping);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor SetEFlag(bool new_eflag) const {
|
LocationDescriptor SetEFlag(bool new_eflag) const {
|
||||||
PSR new_cpsr = cpsr;
|
PSR new_cpsr = cpsr;
|
||||||
new_cpsr.E(new_eflag);
|
new_cpsr.E(new_eflag);
|
||||||
|
|
||||||
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
return LocationDescriptor(arm_pc, new_cpsr, fpscr, single_stepping);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor SetFPSCR(u32 new_fpscr) const {
|
LocationDescriptor SetFPSCR(u32 new_fpscr) const {
|
||||||
return LocationDescriptor(arm_pc, cpsr, A32::FPSCR{new_fpscr & FPSCR_MODE_MASK});
|
return LocationDescriptor(arm_pc, cpsr, A32::FPSCR{new_fpscr & FPSCR_MODE_MASK}, single_stepping);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor AdvanceIT() const {
|
LocationDescriptor AdvanceIT() const {
|
||||||
PSR new_cpsr = cpsr;
|
PSR new_cpsr = cpsr;
|
||||||
new_cpsr.IT(new_cpsr.IT().Advance());
|
new_cpsr.IT(new_cpsr.IT().Advance());
|
||||||
|
|
||||||
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
return LocationDescriptor(arm_pc, new_cpsr, fpscr, single_stepping);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationDescriptor SetSingleStepping(bool new_single_stepping) const {
|
||||||
|
return LocationDescriptor(arm_pc, cpsr, fpscr, new_single_stepping);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 UniqueHash() const noexcept {
|
u64 UniqueHash() const noexcept {
|
||||||
|
@ -96,8 +107,9 @@ public:
|
||||||
const u64 fpscr_u64 = fpscr.Value();
|
const u64 fpscr_u64 = fpscr.Value();
|
||||||
const u64 t_u64 = cpsr.T() ? 1 : 0;
|
const u64 t_u64 = cpsr.T() ? 1 : 0;
|
||||||
const u64 e_u64 = cpsr.E() ? 2 : 0;
|
const u64 e_u64 = cpsr.E() ? 2 : 0;
|
||||||
|
const u64 single_stepping_u64 = single_stepping ? 4 : 0;
|
||||||
const u64 it_u64 = u64(cpsr.IT().Value()) << 8;
|
const u64 it_u64 = u64(cpsr.IT().Value()) << 8;
|
||||||
const u64 upper = (fpscr_u64 | t_u64 | e_u64 | it_u64) << 32;
|
const u64 upper = (fpscr_u64 | t_u64 | e_u64 | single_stepping_u64 | it_u64) << 32;
|
||||||
return pc_u64 | upper;
|
return pc_u64 | upper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +121,7 @@ private:
|
||||||
u32 arm_pc; ///< Current program counter value.
|
u32 arm_pc; ///< Current program counter value.
|
||||||
PSR cpsr; ///< Current program status register.
|
PSR cpsr; ///< Current program status register.
|
||||||
A32::FPSCR fpscr; ///< Floating point status control register.
|
A32::FPSCR fpscr; ///< Floating point status control register.
|
||||||
|
bool single_stepping;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -33,8 +33,9 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType mem
|
||||||
IR::Block block{descriptor};
|
IR::Block block{descriptor};
|
||||||
ArmTranslatorVisitor visitor{block, descriptor, options};
|
ArmTranslatorVisitor visitor{block, descriptor, options};
|
||||||
|
|
||||||
|
const bool single_step = descriptor.SingleStepping();
|
||||||
bool should_continue = true;
|
bool should_continue = true;
|
||||||
while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir)) {
|
do {
|
||||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
const u32 arm_pc = visitor.ir.current_location.PC();
|
||||||
const u32 arm_instruction = memory_read_code(arm_pc);
|
const u32 arm_instruction = memory_read_code(arm_pc);
|
||||||
|
|
||||||
|
@ -52,13 +53,17 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType mem
|
||||||
|
|
||||||
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4);
|
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4);
|
||||||
block.CycleCount()++;
|
block.CycleCount()++;
|
||||||
}
|
} while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir) && !single_step);
|
||||||
|
|
||||||
if (visitor.cond_state == ConditionalState::Translating || visitor.cond_state == ConditionalState::Trailing) {
|
if (visitor.cond_state == ConditionalState::Translating || visitor.cond_state == ConditionalState::Trailing || single_step) {
|
||||||
if (should_continue) {
|
if (should_continue) {
|
||||||
|
if (single_step) {
|
||||||
|
visitor.ir.SetTerm(IR::Term::LinkBlock{visitor.ir.current_location});
|
||||||
|
} else {
|
||||||
visitor.ir.SetTerm(IR::Term::LinkBlockFast{visitor.ir.current_location});
|
visitor.ir.SetTerm(IR::Term::LinkBlockFast{visitor.ir.current_location});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT_MSG(block.HasTerminal(), "Terminal has not been set");
|
ASSERT_MSG(block.HasTerminal(), "Terminal has not been set");
|
||||||
|
|
||||||
|
|
|
@ -59,8 +59,9 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType m
|
||||||
IR::Block block{descriptor};
|
IR::Block block{descriptor};
|
||||||
ThumbTranslatorVisitor visitor{block, descriptor, options};
|
ThumbTranslatorVisitor visitor{block, descriptor, options};
|
||||||
|
|
||||||
|
const bool single_step = descriptor.SingleStepping();
|
||||||
bool should_continue = true;
|
bool should_continue = true;
|
||||||
while (should_continue) {
|
do {
|
||||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
const u32 arm_pc = visitor.ir.current_location.PC();
|
||||||
const auto [thumb_instruction, inst_size] = ReadThumbInstruction(arm_pc, memory_read_code);
|
const auto [thumb_instruction, inst_size] = ReadThumbInstruction(arm_pc, memory_read_code);
|
||||||
|
|
||||||
|
@ -81,6 +82,10 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType m
|
||||||
const s32 advance_pc = (inst_size == ThumbInstSize::Thumb16) ? 2 : 4;
|
const s32 advance_pc = (inst_size == ThumbInstSize::Thumb16) ? 2 : 4;
|
||||||
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(advance_pc);
|
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(advance_pc);
|
||||||
block.CycleCount()++;
|
block.CycleCount()++;
|
||||||
|
} while (should_continue && !single_step);
|
||||||
|
|
||||||
|
if (single_step && should_continue) {
|
||||||
|
visitor.ir.SetTerm(IR::Term::LinkBlock{visitor.ir.current_location});
|
||||||
}
|
}
|
||||||
|
|
||||||
block.SetEndLocation(visitor.ir.current_location);
|
block.SetEndLocation(visitor.ir.current_location);
|
||||||
|
|
Loading…
Reference in a new issue