diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5e3ea5c2..565faaab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -125,6 +125,8 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS) frontend/A32/location_descriptor.cpp frontend/A32/location_descriptor.h frontend/A32/PSR.h + frontend/A32/translate/conditional_state.cpp + frontend/A32/translate/conditional_state.h frontend/A32/translate/impl/asimd_load_store_structures.cpp frontend/A32/translate/impl/asimd_misc.cpp frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp diff --git a/src/frontend/A32/translate/conditional_state.cpp b/src/frontend/A32/translate/conditional_state.cpp new file mode 100644 index 00000000..4d7c963a --- /dev/null +++ b/src/frontend/A32/translate/conditional_state.cpp @@ -0,0 +1,79 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2020 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#include + +#include + +#include "common/assert.h" +#include "common/common_types.h" +#include "frontend/A32/ir_emitter.h" +#include "frontend/A32/translate/conditional_state.h" +#include "frontend/ir/cond.h" + +namespace Dynarmic::A32 { + +bool CondCanContinue(ConditionalState cond_state, const A32::IREmitter& ir) { + ASSERT_MSG(cond_state != ConditionalState::Break, "Should never happen."); + + if (cond_state == ConditionalState::None) + return true; + + // TODO: This is more conservative than necessary. + return std::all_of(ir.block.begin(), ir.block.end(), [](const IR::Inst& inst) { return !inst.WritesToCPSR(); }); +} + +bool IsConditionPassed(IR::Cond cond, ConditionalState& cond_state, A32::IREmitter& ir, int instruction_size) { + ASSERT_MSG(cond_state != ConditionalState::Break, + "This should never happen. We requested a break but that wasn't honored."); + + if (cond == IR::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 == IR::Cond::AL) { + cond_state = ConditionalState::Trailing; + } else { + if (cond == ir.block.GetCondition()) { + ir.block.SetConditionFailedLocation(ir.current_location.AdvancePC(instruction_size).AdvanceIT()); + ir.block.ConditionFailedCycleCount()++; + return true; + } + + // cond has changed, abort + cond_state = ConditionalState::Break; + ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location}); + return false; + } + } + + if (cond == IR::Cond::AL) { + // Everything is fine with the world + return true; + } + + // non-AL cond + + if (!ir.block.empty()) { + // We've already emitted instructions. Quit for now, we'll make a new block here later. + cond_state = ConditionalState::Break; + ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location}); + return false; + } + + // We've not emitted instructions yet. + // We'll emit one instruction, and set the block-entry conditional appropriately. + + cond_state = ConditionalState::Translating; + ir.block.SetCondition(cond); + ir.block.SetConditionFailedLocation(ir.current_location.AdvancePC(instruction_size).AdvanceIT()); + ir.block.ConditionFailedCycleCount() = ir.block.CycleCount() + 1; + return true; +} + +} // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/conditional_state.h b/src/frontend/A32/translate/conditional_state.h new file mode 100644 index 00000000..0c3b1e19 --- /dev/null +++ b/src/frontend/A32/translate/conditional_state.h @@ -0,0 +1,32 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2020 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#pragma once + +#include "common/common_types.h" + +namespace Dynarmic::IR { +enum class Cond; +} // namespace Dynarmic::IR + +namespace Dynarmic::A32 { + +class IREmitter; + +enum class ConditionalState { + /// We haven't met any conditional instructions yet. + None, + /// Current instruction is a conditional. This marks the end of this basic block. + Break, + /// This basic block is made up solely of conditional instructions. + Translating, + /// This basic block is made up of conditional instructions followed by unconditional instructions. + Trailing, +}; + +bool CondCanContinue(ConditionalState cond_state, const A32::IREmitter& ir); +bool IsConditionPassed(IR::Cond cond, ConditionalState& cond_state, A32::IREmitter& ir, int instruction_size); + +} // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index f9a239b9..b1a7016f 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -10,6 +10,7 @@ #include "frontend/imm.h" #include "frontend/A32/ir_emitter.h" #include "frontend/A32/location_descriptor.h" +#include "frontend/A32/translate/conditional_state.h" #include "frontend/A32/translate/translate.h" #include "frontend/A32/types.h" @@ -17,17 +18,6 @@ namespace Dynarmic::A32 { enum class Exception; -enum class ConditionalState { - /// We haven't met any conditional instructions yet. - None, - /// Current instruction is a conditional. This marks the end of this basic block. - Break, - /// This basic block is made up solely of conditional instructions. - Translating, - /// This basic block is made up of conditional instructions followed by unconditional instructions. - Trailing, -}; - struct ArmTranslatorVisitor final { using instruction_return_type = bool; diff --git a/src/frontend/A32/translate/translate_arm.cpp b/src/frontend/A32/translate/translate_arm.cpp index 203774d0..bbc0204d 100644 --- a/src/frontend/A32/translate/translate_arm.cpp +++ b/src/frontend/A32/translate/translate_arm.cpp @@ -3,8 +3,6 @@ * SPDX-License-Identifier: 0BSD */ -#include - #include #include "common/assert.h" @@ -12,6 +10,7 @@ #include "frontend/A32/decoder/asimd.h" #include "frontend/A32/decoder/vfp.h" #include "frontend/A32/location_descriptor.h" +#include "frontend/A32/translate/conditional_state.h" #include "frontend/A32/translate/impl/translate_arm.h" #include "frontend/A32/translate/translate.h" #include "frontend/A32/types.h" @@ -19,16 +18,6 @@ namespace Dynarmic::A32 { -static bool CondCanContinue(ConditionalState cond_state, const A32::IREmitter& ir) { - ASSERT_MSG(cond_state != ConditionalState::Break, "Should never happen."); - - if (cond_state == ConditionalState::None) - return true; - - // TODO: This is more conservative than necessary. - return std::all_of(ir.block.begin(), ir.block.end(), [](const IR::Inst& inst) { return !inst.WritesToCPSR(); }); -} - IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options) { const bool single_step = descriptor.SingleStepping(); @@ -102,53 +91,7 @@ bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descript } bool ArmTranslatorVisitor::ConditionPassed(Cond cond) { - ASSERT_MSG(cond_state != ConditionalState::Break, - "This should never happen. We requested a break but that wasn't honored."); - 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) { - cond_state = ConditionalState::Trailing; - } else { - if (cond == ir.block.GetCondition()) { - ir.block.SetConditionFailedLocation(ir.current_location.AdvancePC(4)); - ir.block.ConditionFailedCycleCount()++; - return true; - } - - // cond has changed, abort - cond_state = ConditionalState::Break; - ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location}); - return false; - } - } - - if (cond == Cond::AL) { - // Everything is fine with the world - return true; - } - - // non-AL cond - - if (!ir.block.empty()) { - // We've already emitted instructions. Quit for now, we'll make a new block here later. - cond_state = ConditionalState::Break; - ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location}); - return false; - } - - // We've not emitted instructions yet. - // We'll emit one instruction, and set the block-entry conditional appropriately. - - cond_state = ConditionalState::Translating; - ir.block.SetCondition(cond); - ir.block.SetConditionFailedLocation(ir.current_location.AdvancePC(4)); - ir.block.ConditionFailedCycleCount() = ir.block.CycleCount() + 1; - return true; + return IsConditionPassed(cond, cond_state, ir, 4); } bool ArmTranslatorVisitor::InterpretThisInstruction() {