diff --git a/src/frontend/decoder/arm.h b/src/frontend/decoder/arm.h index 041b5bc5..3e38d4ac 100644 --- a/src/frontend/decoder/arm.h +++ b/src/frontend/decoder/arm.h @@ -59,7 +59,7 @@ private: }; template -static const std::array, 4> g_arm_instruction_table = { +static const std::array, 6> g_arm_instruction_table = { #define INST(fn, name, bitstring) detail::detail::GetMatcher(name, bitstring) @@ -235,9 +235,9 @@ static const std::array, 4> g_arm_instruction_table = { //INST(&V::arm_PKHTB, "PKHTB", "cccc01101000nnnnddddvvvvv101mmmm"), // v6K // Reversal instructions - //INST(&V::arm_REV, "REV", "cccc011010111111dddd11110011mmmm"), // v6 + INST(&V::arm_REV, "REV", "cccc011010111111dddd11110011mmmm"), // v6 //INST(&V::arm_REV16, "REV16", "cccc011010111111dddd11111011mmmm"), // v6 - //INST(&V::arm_REVSH, "REVSH", "cccc011011111111dddd11111011mmmm"), // v6 + INST(&V::arm_REVSH, "REVSH", "cccc011011111111dddd11111011mmmm"), // v6 // Saturation instructions //INST(&V::arm_SSAT, "SSAT", "cccc0110101vvvvvddddvvvvvr01nnnn"), // v6 diff --git a/src/frontend/disassembler/disassembler_arm.cpp b/src/frontend/disassembler/disassembler_arm.cpp index 0ded3cc1..67e21207 100644 --- a/src/frontend/disassembler/disassembler_arm.cpp +++ b/src/frontend/disassembler/disassembler_arm.cpp @@ -405,9 +405,15 @@ public: std::string arm_PKHTB(Cond cond, Reg n, Reg d, Imm5 imm5, Reg m) { return "ice"; } // Reversal instructions - std::string arm_REV(Cond cond, Reg d, Reg m) { return "ice"; } - std::string arm_REV16(Cond cond, Reg d, Reg m) { return "ice"; } - std::string arm_REVSH(Cond cond, Reg d, Reg m) { return "ice"; } + std::string arm_REV(Cond cond, Reg d, Reg m) { + return Common::StringFromFormat("rev%s %s, %s", CondStr(cond), RegStr(d), RegStr(m)); + } + std::string arm_REV16(Cond cond, Reg d, Reg m) { + return Common::StringFromFormat("rev16%s %s, %s", CondStr(cond), RegStr(d), RegStr(m)); + } + std::string arm_REVSH(Cond cond, Reg d, Reg m) { + return Common::StringFromFormat("revsh%s %s, %s", CondStr(cond), RegStr(d), RegStr(m)); + } // Saturation instructions std::string arm_SSAT(Cond cond, Imm5 sat_imm, Reg d, Imm5 imm5, bool sh, Reg n) { return "ice"; } diff --git a/src/frontend/translate/translate_arm.cpp b/src/frontend/translate/translate_arm.cpp index d3ccc09c..c1d66ed4 100644 --- a/src/frontend/translate/translate_arm.cpp +++ b/src/frontend/translate/translate_arm.cpp @@ -280,6 +280,32 @@ struct ArmTranslatorVisitor final { bool arm_UDF() { return InterpretThisInstruction(); } + + bool arm_REV(Cond cond, Reg d, Reg m) { + // REV , + ASSERT(d != Reg::PC && m != Reg::PC); + + if (ConditionPassed(cond)) { + auto result = ir.ByteReverseWord(ir.GetRegister(m)); + ir.SetRegister(d, result); + } + return true; + } + + bool arm_REV16(Cond cond, Reg d, Reg m) { + return InterpretThisInstruction(); + } + + bool arm_REVSH(Cond cond, Reg d, Reg m) { + // REVSH , + ASSERT(d != Reg::PC && m != Reg::PC); + + if (ConditionPassed(cond)) { + auto rev_half = ir.ByteReverseHalf(ir.LeastSignificantHalf(ir.GetRegister(m))); + ir.SetRegister(d, ir.SignExtendHalfToWord(rev_half)); + } + return true; + } }; } // local namespace diff --git a/tests/arm/fuzz_arm.cpp b/tests/arm/fuzz_arm.cpp index 798f81ee..8777c964 100644 --- a/tests/arm/fuzz_arm.cpp +++ b/tests/arm/fuzz_arm.cpp @@ -327,8 +327,8 @@ TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") { if (Rd == 15) S = false; u32 Rn = RandInt(0, 15); u32 shifter_operand = RandInt(0, 0xFFF); - u32 - assemble_randoms = (shifter_operand << 0) | (Rd << 12) | (Rn << 16) | (S << 20) | (cond << 28); + u32 assemble_randoms = + (shifter_operand << 0) | (Rd << 12) | (Rn << 16) | (S << 20) | (cond << 28); return instruction.Bits() | (assemble_randoms & ~instruction.Mask()); } case 2: { @@ -359,3 +359,36 @@ TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") { FuzzJitArm(1, 1, 10000, instruction_select(/*Rd_can_be_r15=*/true)); } } + +TEST_CASE("Fuzz ARM reversal instructions", "[JitX64]") { + const auto is_valid = [](u32 instr) -> bool { + // R15 is UNPREDICTABLE + return Dynarmic::Common::Bits<0, 3>(instr) != 0b1111 && Dynarmic::Common::Bits<12, 15>(instr) != 0b1111; + }; + + const std::array reg_instructions = { + { + InstructionGenerator("cccc011010111111dddd11110011mmmm", is_valid), + InstructionGenerator("cccc011010111111dddd11111011mmmm", is_valid), + InstructionGenerator("cccc011011111111dddd11111011mmmm", is_valid), + } + }; + + SECTION("REV tests") { + FuzzJitArm(1, 1, 10000, [®_instructions]() -> u32 { + return reg_instructions[0].Generate(); + }); + } + + SECTION("REV16 tests") { + FuzzJitArm(1, 1, 10000, [®_instructions]() -> u32 { + return reg_instructions[1].Generate(); + }); + } + + SECTION("REVSH tests") { + FuzzJitArm(1, 1, 10000, [®_instructions]() -> u32 { + return reg_instructions[2].Generate(); + }); + } +} \ No newline at end of file