diff --git a/include/dynarmic/A32/config.h b/include/dynarmic/A32/config.h index 36f53be5..9486c62d 100644 --- a/include/dynarmic/A32/config.h +++ b/include/dynarmic/A32/config.h @@ -82,6 +82,11 @@ struct UserConfig { // Coprocessors std::array, 16> coprocessors; + + /// This option relates to translation. Generally when we run into an unpredictable + /// instruction the ExceptionRaised callback is called. If this is true, we define + /// definite behaviour for some unpredictable instructions. + bool define_unpredictable_behaviour = false; }; } // namespace A32 diff --git a/src/backend/x64/a32_interface.cpp b/src/backend/x64/a32_interface.cpp index d7287acb..ccd987aa 100644 --- a/src/backend/x64/a32_interface.cpp +++ b/src/backend/x64/a32_interface.cpp @@ -131,7 +131,7 @@ private: PerformCacheInvalidation(); } - IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, [this](u32 vaddr) { return config.callbacks->MemoryReadCode(vaddr); }); + IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, [this](u32 vaddr) { return config.callbacks->MemoryReadCode(vaddr); }, {config.define_unpredictable_behaviour}); Optimization::A32GetSetElimination(ir_block); Optimization::DeadCodeElimination(ir_block); Optimization::A32ConstantMemoryReads(ir_block, config.callbacks); diff --git a/src/frontend/A32/translate/translate.cpp b/src/frontend/A32/translate/translate.cpp index a8a812a3..acfcc12b 100644 --- a/src/frontend/A32/translate/translate.cpp +++ b/src/frontend/A32/translate/translate.cpp @@ -10,11 +10,11 @@ namespace Dynarmic::A32 { -IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code); -IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code); +IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options); +IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options); -IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) { - return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_code); +IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options) { + return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_code, options); } bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction); diff --git a/src/frontend/A32/translate/translate.h b/src/frontend/A32/translate/translate.h index 226c4bf6..64e125d7 100644 --- a/src/frontend/A32/translate/translate.h +++ b/src/frontend/A32/translate/translate.h @@ -17,13 +17,20 @@ class LocationDescriptor; using MemoryReadCodeFuncType = std::function; +struct TranslationOptions { + /// This changes what IR we emit when we translate an unpredictable instruction. + /// If this is false, the ExceptionRaised IR instruction is emitted. + /// If this is true, we define some behaviour for some instructions. + bool define_unpredictable_behaviour = false; +}; + /** * This function translates instructions in memory into our intermediate representation. * @param descriptor The starting location of the basic block. Includes information like PC, Thumb state, &c. * @param memory_read_code The function we should use to read emulated memory. * @return A translated basic block in the intermediate representation. */ -IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code); +IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options); /** * This function translates a single provided instruction into our intermediate representation. diff --git a/src/frontend/A32/translate/translate_arm.cpp b/src/frontend/A32/translate/translate_arm.cpp index 39a3dfd2..0a77abe7 100644 --- a/src/frontend/A32/translate/translate_arm.cpp +++ b/src/frontend/A32/translate/translate_arm.cpp @@ -28,9 +28,9 @@ static bool CondCanContinue(ConditionalState cond_state, const A32::IREmitter& i 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) { +IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options) { IR::Block block{descriptor}; - ArmTranslatorVisitor visitor{block, descriptor}; + ArmTranslatorVisitor visitor{block, descriptor, options}; bool should_continue = true; while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir)) { @@ -67,7 +67,7 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType mem } bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 arm_instruction) { - ArmTranslatorVisitor visitor{block, descriptor}; + ArmTranslatorVisitor visitor{block, descriptor, {}}; // TODO: Proper cond handling diff --git a/src/frontend/A32/translate/translate_arm/translate_arm.h b/src/frontend/A32/translate/translate_arm/translate_arm.h index a168424e..63d7071e 100644 --- a/src/frontend/A32/translate/translate_arm/translate_arm.h +++ b/src/frontend/A32/translate/translate_arm/translate_arm.h @@ -9,6 +9,7 @@ #include "common/bit_util.h" #include "frontend/A32/ir_emitter.h" #include "frontend/A32/location_descriptor.h" +#include "frontend/A32/translate/translate.h" namespace Dynarmic::A32 { @@ -26,12 +27,13 @@ enum class ConditionalState { struct ArmTranslatorVisitor final { using instruction_return_type = bool; - explicit ArmTranslatorVisitor(IR::Block& block, LocationDescriptor descriptor) : ir(block, descriptor) { + explicit ArmTranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const TranslationOptions& options) : ir(block, descriptor), options(options) { ASSERT_MSG(!descriptor.TFlag(), "The processor must be in Arm mode"); } A32::IREmitter ir; ConditionalState cond_state = ConditionalState::None; + TranslationOptions options; bool ConditionPassed(Cond cond); bool InterpretThisInstruction(); diff --git a/src/frontend/A32/translate/translate_thumb.cpp b/src/frontend/A32/translate/translate_thumb.cpp index 6a841cf3..7967d86d 100644 --- a/src/frontend/A32/translate/translate_thumb.cpp +++ b/src/frontend/A32/translate/translate_thumb.cpp @@ -21,11 +21,12 @@ namespace { struct ThumbTranslatorVisitor final { using instruction_return_type = bool; - explicit ThumbTranslatorVisitor(IR::Block& block, LocationDescriptor descriptor) : ir(block, descriptor) { + explicit ThumbTranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const TranslationOptions& options) : ir(block, descriptor), options(options) { ASSERT_MSG(descriptor.TFlag(), "The processor must be in Thumb mode"); } A32::IREmitter ir; + TranslationOptions options; bool InterpretThisInstruction() { ir.SetTerm(IR::Term::Interpret(ir.current_location)); @@ -879,9 +880,9 @@ std::tuple ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFu } // local namespace -IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) { +IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options) { IR::Block block{descriptor}; - ThumbTranslatorVisitor visitor{block, descriptor}; + ThumbTranslatorVisitor visitor{block, descriptor, options}; bool should_continue = true; while (should_continue) { @@ -913,7 +914,7 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType m } bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descriptor, u32 thumb_instruction) { - ThumbTranslatorVisitor visitor{block, descriptor}; + ThumbTranslatorVisitor visitor{block, descriptor, {}}; const bool is_thumb_16 = IsThumb16(static_cast(thumb_instruction)); bool should_continue = true; diff --git a/tests/A32/fuzz_arm.cpp b/tests/A32/fuzz_arm.cpp index e2a073b5..3a1ee1b0 100644 --- a/tests/A32/fuzz_arm.cpp +++ b/tests/A32/fuzz_arm.cpp @@ -193,7 +193,7 @@ void FuzzJitArm(const size_t instruction_count, const size_t instructions_to_exe size_t num_insts = 0; while (num_insts < instructions_to_execute_count) { Dynarmic::A32::LocationDescriptor descriptor = {u32(num_insts * 4), Dynarmic::A32::PSR{}, Dynarmic::A32::FPSCR{}}; - Dynarmic::IR::Block ir_block = Dynarmic::A32::Translate(descriptor, [&test_env](u32 vaddr) { return test_env.MemoryReadCode(vaddr); }); + Dynarmic::IR::Block ir_block = Dynarmic::A32::Translate(descriptor, [&test_env](u32 vaddr) { return test_env.MemoryReadCode(vaddr); }, {}); Dynarmic::Optimization::A32GetSetElimination(ir_block); Dynarmic::Optimization::DeadCodeElimination(ir_block); Dynarmic::Optimization::A32ConstantMemoryReads(ir_block, &test_env); diff --git a/tests/A32/fuzz_thumb.cpp b/tests/A32/fuzz_thumb.cpp index 95e54b7e..5cc4cd1c 100644 --- a/tests/A32/fuzz_thumb.cpp +++ b/tests/A32/fuzz_thumb.cpp @@ -152,7 +152,7 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, ARMul_State& size_t num_insts = 0; while (num_insts < instructions_to_execute_count) { Dynarmic::A32::LocationDescriptor descriptor = {u32(num_insts * 4), cpsr, Dynarmic::A32::FPSCR{}}; - Dynarmic::IR::Block ir_block = Dynarmic::A32::Translate(descriptor, [&test_env](u32 vaddr) { return test_env.MemoryReadCode(vaddr); }); + Dynarmic::IR::Block ir_block = Dynarmic::A32::Translate(descriptor, [&test_env](u32 vaddr) { return test_env.MemoryReadCode(vaddr); }, {}); Dynarmic::Optimization::A32GetSetElimination(ir_block); Dynarmic::Optimization::DeadCodeElimination(ir_block); Dynarmic::Optimization::A32ConstantMemoryReads(ir_block, &test_env);