From d345220251a1c67c512fccd9c3ce7da365d4ad5a Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sat, 11 Aug 2018 18:14:00 +0100 Subject: [PATCH] A32/translate: Add TranslateSingleInstruction --- src/frontend/A32/translate/translate.cpp | 7 +++ src/frontend/A32/translate/translate.h | 9 ++++ src/frontend/A32/translate/translate_arm.cpp | 34 ++++++++++++-- .../A32/translate/translate_thumb.cpp | 47 +++++++++++++++---- 4 files changed, 84 insertions(+), 13 deletions(-) diff --git a/src/frontend/A32/translate/translate.cpp b/src/frontend/A32/translate/translate.cpp index b4bcdc10..a8a812a3 100644 --- a/src/frontend/A32/translate/translate.cpp +++ b/src/frontend/A32/translate/translate.cpp @@ -17,4 +17,11 @@ IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_code); } +bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction); +bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction); + +bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) { + return (descriptor.TFlag() ? TranslateSingleThumbInstruction : TranslateSingleArmInstruction)(block, descriptor, instruction); +} + } // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/translate.h b/src/frontend/A32/translate/translate.h index 9e089fe1..226c4bf6 100644 --- a/src/frontend/A32/translate/translate.h +++ b/src/frontend/A32/translate/translate.h @@ -25,4 +25,13 @@ using MemoryReadCodeFuncType = std::function; */ IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code); +/** + * This function translates a single provided instruction into our intermediate representation. + * @param block The block to append the IR for the instruction to. + * @param descriptor The location of the instruction. Includes information like PC, Thumb state, &c. + * @param instruction The instruction to translate. + * @return The translated instruction translated to the intermediate representation. + */ +bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction); + } // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/translate_arm.cpp b/src/frontend/A32/translate/translate_arm.cpp index 09a03ee2..39a3dfd2 100644 --- a/src/frontend/A32/translate/translate_arm.cpp +++ b/src/frontend/A32/translate/translate_arm.cpp @@ -37,9 +37,9 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType mem const u32 arm_pc = visitor.ir.current_location.PC(); const u32 arm_instruction = memory_read_code(arm_pc); - if (auto vfp_decoder = DecodeVFP2(arm_instruction)) { + if (const auto vfp_decoder = DecodeVFP2(arm_instruction)) { should_continue = vfp_decoder->call(visitor, arm_instruction); - } else if (auto decoder = DecodeArm(arm_instruction)) { + } else if (const auto decoder = DecodeArm(arm_instruction)) { should_continue = decoder->call(visitor, arm_instruction); } else { should_continue = visitor.arm_UDF(); @@ -66,10 +66,38 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType mem return block; } +bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 arm_instruction) { + ArmTranslatorVisitor visitor{block, descriptor}; + + // TODO: Proper cond handling + + bool should_continue = true; + if (const auto vfp_decoder = DecodeVFP2(arm_instruction)) { + should_continue = vfp_decoder->call(visitor, arm_instruction); + } else if (const auto decoder = DecodeArm(arm_instruction)) { + should_continue = decoder->call(visitor, arm_instruction); + } else { + should_continue = visitor.arm_UDF(); + } + + // TODO: Feedback resulting cond status to caller somehow. + + visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4); + block.CycleCount()++; + + block.SetEndLocation(visitor.ir.current_location); + + return should_continue; +} + bool ArmTranslatorVisitor::ConditionPassed(Cond cond) { ASSERT_MSG(cond_state != ConditionalState::Break, "This should never happen. We requested a break but that wasn't honored."); - ASSERT_MSG(cond != Cond::NV, "NV conditional is obsolete"); + if (cond == Cond::NV) { + // NV conditional is obsolete + ir.ExceptionRaised(Exception::UnpredictableInstruction); + return false; + } if (cond_state == ConditionalState::Translating) { if (ir.block.ConditionFailedLocation() != ir.current_location || cond == Cond::AL) { diff --git a/src/frontend/A32/translate/translate_thumb.cpp b/src/frontend/A32/translate/translate_thumb.cpp index d71cc472..6a841cf3 100644 --- a/src/frontend/A32/translate/translate_thumb.cpp +++ b/src/frontend/A32/translate/translate_thumb.cpp @@ -851,13 +851,17 @@ enum class ThumbInstSize { Thumb16, Thumb32 }; +bool IsThumb16(u16 first_part) { + return (first_part & 0xF800) <= 0xE800; +} + std::tuple ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFuncType memory_read_code) { u32 first_part = memory_read_code(arm_pc & 0xFFFFFFFC); if ((arm_pc & 0x2) != 0) first_part >>= 16; first_part &= 0xFFFF; - if ((first_part & 0xF800) <= 0xE800) { + if (IsThumb16(static_cast(first_part))) { // 16-bit thumb instruction return std::make_tuple(first_part, ThumbInstSize::Thumb16); } @@ -882,28 +886,23 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType m bool should_continue = true; while (should_continue) { const u32 arm_pc = visitor.ir.current_location.PC(); - - u32 thumb_instruction; - ThumbInstSize inst_size; - std::tie(thumb_instruction, inst_size) = ReadThumbInstruction(arm_pc, memory_read_code); + const auto [thumb_instruction, inst_size] = ReadThumbInstruction(arm_pc, memory_read_code); if (inst_size == ThumbInstSize::Thumb16) { - auto decoder = DecodeThumb16(static_cast(thumb_instruction)); - if (decoder) { + if (const auto decoder = DecodeThumb16(static_cast(thumb_instruction))) { should_continue = decoder->call(visitor, static_cast(thumb_instruction)); } else { should_continue = visitor.thumb16_UDF(); } } else { - auto decoder = DecodeThumb32(thumb_instruction); - if (decoder) { + if (const auto decoder = DecodeThumb32(thumb_instruction)) { should_continue = decoder->call(visitor, thumb_instruction); } else { should_continue = visitor.thumb32_UDF(); } } - 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); block.CycleCount()++; } @@ -913,4 +912,32 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType m return block; } +bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descriptor, u32 thumb_instruction) { + ThumbTranslatorVisitor visitor{block, descriptor}; + + const bool is_thumb_16 = IsThumb16(static_cast(thumb_instruction)); + bool should_continue = true; + if (is_thumb_16) { + if (const auto decoder = DecodeThumb16(static_cast(thumb_instruction))) { + should_continue = decoder->call(visitor, static_cast(thumb_instruction)); + } else { + should_continue = visitor.thumb16_UDF(); + } + } else { + if (const auto decoder = DecodeThumb32(thumb_instruction)) { + should_continue = decoder->call(visitor, thumb_instruction); + } else { + should_continue = visitor.thumb32_UDF(); + } + } + + const s32 advance_pc = is_thumb_16 ? 2 : 4; + visitor.ir.current_location = visitor.ir.current_location.AdvancePC(advance_pc); + block.CycleCount()++; + + block.SetEndLocation(visitor.ir.current_location); + + return should_continue; +} + } // namepsace Dynarmic::A32