diff --git a/src/dynarmic/frontend/A32/translate/translate_arm.cpp b/src/dynarmic/frontend/A32/translate/translate_arm.cpp index 8db6cab9..3ee908fc 100644 --- a/src/dynarmic/frontend/A32/translate/translate_arm.cpp +++ b/src/dynarmic/frontend/A32/translate/translate_arm.cpp @@ -28,10 +28,13 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c bool should_continue = true; do { const u32 arm_pc = visitor.ir.current_location.PC(); - visitor.current_instruction_size = 4; + u64 ticks_for_instruction = 1; if (const auto arm_instruction = tcb->MemoryReadCode(arm_pc)) { + visitor.current_instruction_size = 4; + tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir); + ticks_for_instruction = tcb->GetTicksForCode(false, arm_pc, *arm_instruction); if (const auto vfp_decoder = DecodeVFP(*arm_instruction)) { should_continue = vfp_decoder->get().call(visitor, *arm_instruction); @@ -43,6 +46,8 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c should_continue = visitor.arm_UDF(); } } else { + visitor.current_instruction_size = 4; + should_continue = visitor.RaiseException(Exception::NoExecuteFault); } @@ -51,7 +56,7 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c } visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4); - block.CycleCount()++; + block.CycleCount() += ticks_for_instruction; } while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir) && !single_step); if (visitor.cond_state == ConditionalState::Translating || visitor.cond_state == ConditionalState::Trailing || single_step) { @@ -74,9 +79,14 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 arm_instruction) { TranslatorVisitor visitor{block, descriptor, {}}; + bool should_continue = true; + // TODO: Proper cond handling - bool should_continue = true; + visitor.current_instruction_size = 4; + + const u64 ticks_for_instruction = 1; + if (const auto vfp_decoder = DecodeVFP(arm_instruction)) { should_continue = vfp_decoder->get().call(visitor, arm_instruction); } else if (const auto asimd_decoder = DecodeASIMD(arm_instruction)) { @@ -90,7 +100,7 @@ bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descript // TODO: Feedback resulting cond status to caller somehow. visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4); - block.CycleCount()++; + block.CycleCount() += ticks_for_instruction; block.SetEndLocation(visitor.ir.current_location); diff --git a/src/dynarmic/frontend/A32/translate/translate_callbacks.h b/src/dynarmic/frontend/A32/translate/translate_callbacks.h index a9d8e043..aab01853 100644 --- a/src/dynarmic/frontend/A32/translate/translate_callbacks.h +++ b/src/dynarmic/frontend/A32/translate/translate_callbacks.h @@ -21,6 +21,9 @@ struct TranslateCallbacks { // 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. virtual void PreCodeTranslationHook(bool is_thumb, VAddr pc, A32::IREmitter& ir) = 0; + + // How many ticks should this instruction take to execute? + virtual std::uint64_t GetTicksForCode(bool is_thumb, VAddr vaddr, std::uint32_t instruction) = 0; }; } // namespace Dynarmic::A32 diff --git a/src/dynarmic/frontend/A32/translate/translate_thumb.cpp b/src/dynarmic/frontend/A32/translate/translate_thumb.cpp index a3cc4e8f..845a0679 100644 --- a/src/dynarmic/frontend/A32/translate/translate_thumb.cpp +++ b/src/dynarmic/frontend/A32/translate/translate_thumb.cpp @@ -109,12 +109,15 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, bool should_continue = true; do { const u32 arm_pc = visitor.ir.current_location.PC(); + u64 ticks_for_instruction = 1; + 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; visitor.current_instruction_size = is_thumb_16 ? 2 : 4; - tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir); + tcb->PreCodeTranslationHook(true, arm_pc, visitor.ir); + ticks_for_instruction = tcb->GetTicksForCode(true, arm_pc, thumb_instruction); if (IsUnconditionalInstruction(is_thumb_16, thumb_instruction) || visitor.ThumbConditionPassed()) { if (is_thumb_16) { @@ -143,6 +146,7 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, } } else { visitor.current_instruction_size = 2; + should_continue = visitor.RaiseException(Exception::NoExecuteFault); } @@ -151,7 +155,7 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, } visitor.ir.current_location = visitor.ir.current_location.AdvancePC(static_cast(visitor.current_instruction_size)).AdvanceIT(); - block.CycleCount()++; + block.CycleCount() += ticks_for_instruction; } while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir) && !single_step); if (visitor.cond_state == ConditionalState::Translating || visitor.cond_state == ConditionalState::Trailing || single_step) { @@ -179,6 +183,8 @@ bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descri const bool is_thumb_16 = IsThumb16(static_cast(thumb_instruction)); visitor.current_instruction_size = is_thumb_16 ? 2 : 4; + const u64 ticks_for_instruction = 1; + if (is_thumb_16) { if (const auto decoder = DecodeThumb16(static_cast(thumb_instruction))) { should_continue = decoder->get().call(visitor, static_cast(thumb_instruction)); @@ -206,7 +212,7 @@ bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descri const s32 advance_pc = is_thumb_16 ? 2 : 4; visitor.ir.current_location = visitor.ir.current_location.AdvancePC(advance_pc); - block.CycleCount()++; + block.CycleCount() += ticks_for_instruction; block.SetEndLocation(visitor.ir.current_location); diff --git a/src/dynarmic/interface/A32/config.h b/src/dynarmic/interface/A32/config.h index 32798edc..33f6e194 100644 --- a/src/dynarmic/interface/A32/config.h +++ b/src/dynarmic/interface/A32/config.h @@ -109,6 +109,8 @@ struct UserCallbacks : public TranslateCallbacks { virtual void AddTicks(std::uint64_t ticks) = 0; // How many more ticks am I allowed to execute? virtual std::uint64_t GetTicksRemaining() = 0; + // How many ticks should this instruction take to execute? + std::uint64_t GetTicksForCode(bool /*is_thumb*/, VAddr /*vaddr*/, std::uint32_t /*instruction*/) override { return 1; } }; struct UserConfig {