diff --git a/src/dynarmic/frontend/A32/translate/translate_arm.cpp b/src/dynarmic/frontend/A32/translate/translate_arm.cpp index 3ee908fc..24b5797d 100644 --- a/src/dynarmic/frontend/A32/translate/translate_arm.cpp +++ b/src/dynarmic/frontend/A32/translate/translate_arm.cpp @@ -30,6 +30,11 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c const u32 arm_pc = visitor.ir.current_location.PC(); u64 ticks_for_instruction = 1; + if (!tcb->PreCodeReadHook(false, arm_pc, visitor.ir)) { + should_continue = false; + break; + } + if (const auto arm_instruction = tcb->MemoryReadCode(arm_pc)) { visitor.current_instruction_size = 4; diff --git a/src/dynarmic/frontend/A32/translate/translate_callbacks.h b/src/dynarmic/frontend/A32/translate/translate_callbacks.h index aab01853..e0ad48ea 100644 --- a/src/dynarmic/frontend/A32/translate/translate_callbacks.h +++ b/src/dynarmic/frontend/A32/translate/translate_callbacks.h @@ -18,7 +18,13 @@ struct TranslateCallbacks { // Memory must be interpreted as little endian. virtual std::optional MemoryReadCode(VAddr vaddr) = 0; - // Thus function is called before the instruction at pc is interpreted. + // This function is called before the instruction at pc is read. + // IR code can be emitted by the callee prior to instruction handling. + // By returning false the callee precludes the translation of the instruction; + // in such case the callee is responsible for setting the terminal. + virtual bool PreCodeReadHook(bool is_thumb, VAddr pc, A32::IREmitter& ir) = 0; + + // This function is called before the instruction at pc is interpreted. // IR code can be emitted by the callee prior to translation of the instruction. virtual void PreCodeTranslationHook(bool is_thumb, VAddr pc, A32::IREmitter& ir) = 0; diff --git a/src/dynarmic/frontend/A32/translate/translate_thumb.cpp b/src/dynarmic/frontend/A32/translate/translate_thumb.cpp index 845a0679..d61d8ccb 100644 --- a/src/dynarmic/frontend/A32/translate/translate_thumb.cpp +++ b/src/dynarmic/frontend/A32/translate/translate_thumb.cpp @@ -111,6 +111,11 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, const u32 arm_pc = visitor.ir.current_location.PC(); u64 ticks_for_instruction = 1; + if (!tcb->PreCodeReadHook(true, arm_pc, visitor.ir)) { + should_continue = false; + break; + } + if (const auto maybe_instruction = ReadThumbInstruction(arm_pc, tcb)) { const auto [thumb_instruction, inst_size] = *maybe_instruction; const bool is_thumb_16 = inst_size == ThumbInstSize::Thumb16; diff --git a/src/dynarmic/interface/A32/config.h b/src/dynarmic/interface/A32/config.h index a7b194ab..a3c2aa15 100644 --- a/src/dynarmic/interface/A32/config.h +++ b/src/dynarmic/interface/A32/config.h @@ -65,6 +65,12 @@ struct UserCallbacks : public TranslateCallbacks { // Memory must be interpreted as little endian. std::optional MemoryReadCode(VAddr vaddr) override { return MemoryRead32(vaddr); } + // This function is called before the instruction at pc is read. + // IR code can be emitted by the callee prior to instruction handling. + // By returning true the callee precludes the translation of the instruction; + // in such case the callee is responsible for setting the terminal. + bool PreCodeReadHook(bool /*is_thumb*/, VAddr /*pc*/, A32::IREmitter& /*ir*/) override { return true; } + // Thus function is called before the instruction at pc is interpreted. // IR code can be emitted by the callee prior to translation of the instruction. void PreCodeTranslationHook(bool /*is_thumb*/, VAddr /*pc*/, A32::IREmitter& /*ir*/) override {}