diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index af643b55..d0eb50fa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -38,6 +38,7 @@ set(HEADERS frontend/decoder/arm.h frontend/decoder/decoder_detail.h frontend/decoder/thumb16.h + frontend/decoder/thumb32.h frontend/disassembler/disassembler.h frontend/ir/ir.h frontend/ir/ir_emitter.h diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index 30b2e181..16cc642d 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -922,10 +922,16 @@ void EmitX64::EmitTerminalReturnToDispatch(IR::Term::ReturnToDispatch, Arm::Loca } void EmitX64::EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, Arm::LocationDescriptor initial_location) { - ASSERT_MSG(terminal.next.TFlag == initial_location.TFlag, "Unimplemented"); ASSERT_MSG(terminal.next.EFlag == initial_location.EFlag, "Unimplemented"); code->MOV(32, MJitStateReg(Arm::Reg::PC), Imm32(terminal.next.arm_pc)); + if (terminal.next.TFlag != initial_location.TFlag) { + if (terminal.next.TFlag) { + code->OR(32, MJitStateCpsr(), Imm32(1 << 5)); + } else { + code->AND(32, MJitStateCpsr(), Imm32(~(1 << 5))); + } + } routines->GenReturnFromRunCode(code); // TODO: Check cycles, Properly do a link } diff --git a/src/frontend/decoder/thumb32.h b/src/frontend/decoder/thumb32.h new file mode 100644 index 00000000..0da17eba --- /dev/null +++ b/src/frontend/decoder/thumb32.h @@ -0,0 +1,82 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2016 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#include +#include +#include + +#include + +#include "common/common_types.h" +#include "frontend/decoder/decoder_detail.h" + +namespace Dynarmic { +namespace Arm { + +template +struct Thumb32Matcher { + using CallRetT = typename mp::MemFnInfo::return_type; + + Thumb32Matcher(const char* const name, u32 mask, u32 expect, std::function fn) + : name(name), mask(mask), expect(expect), fn(fn) {} + + /// Gets the name of this type of instruction. + const char* GetName() const { + return name; + } + + /** + * Tests to see if the instruction is this type of instruction. + * @param instruction The instruction to test + * @returns true if the instruction is + */ + bool Matches(u32 instruction) const { + return (instruction & mask) == expect; + } + + /** + * Calls the corresponding instruction handler on visitor for this type of instruction. + * @param v The visitor to use + * @param instruction The instruction to decode. + */ + CallRetT call(Visitor& v, u32 instruction) const { + assert(Matches(instruction)); + return fn(v, instruction); + } + +private: + const char* name; + u32 mask, expect; + std::function fn; +}; + +template +boost::optional&> DecodeThumb32(u32 instruction) { + const static std::vector> table = { + +#define INST(fn, name, bitstring) detail::detail::GetMatcher(name, bitstring) + + // Branch instructions + INST(&V::thumb32_BL_imm, "BL (imm)", "11110vvvvvvvvvvv11111vvvvvvvvvvv"), // v4T + INST(&V::thumb32_BLX_imm, "BLX (imm)", "11110vvvvvvvvvvv11101vvvvvvvvvvv"), // v5T + + // Misc instructions + INST(&V::thumb32_UDF, "UDF", "111101111111----1010------------"), // v6T2 + +#undef INST + + }; + + const auto matches_instruction = [instruction](const auto& matcher){ return matcher.Matches(instruction); }; + + auto iter = std::find_if(table.begin(), table.end(), matches_instruction); + return iter != table.end() ? boost::make_optional&>(*iter) : boost::none; +} + +} // namespace Arm +} // namespace Dynarmic diff --git a/src/frontend/translate/translate_thumb.cpp b/src/frontend/translate/translate_thumb.cpp index 91f4a0e5..d16dc2a4 100644 --- a/src/frontend/translate/translate_thumb.cpp +++ b/src/frontend/translate/translate_thumb.cpp @@ -10,6 +10,7 @@ #include "common/bit_util.h" #include "frontend/arm_types.h" #include "frontend/decoder/thumb16.h" +#include "frontend/decoder/thumb32.h" #include "frontend/ir/ir_emitter.h" #include "frontend/translate/translate.h" @@ -786,6 +787,34 @@ struct ThumbTranslatorVisitor final { ir.SetTerm(IR::Term::LinkBlock{next_location}); return false; } + + bool thumb32_BL_imm(Imm11 hi, Imm11 lo) { + s32 imm32 = Common::SignExtend<32, s32>((hi << 12) | (lo << 1)); + // BL