From 7305d1322156ede482d3c269d33766dd43c6691a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 20 Apr 2019 10:16:18 -0400 Subject: [PATCH] A32: Implement ARM-mode RBIT --- src/frontend/A32/decoder/arm.inc | 1 + .../A32/disassembler/disassembler_arm.cpp | 3 ++ .../A32/translate/translate_arm/reversal.cpp | 30 +++++++++++++++++++ .../translate/translate_arm/translate_arm.h | 1 + tests/A32/fuzz_arm.cpp | 7 +++-- 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/frontend/A32/decoder/arm.inc b/src/frontend/A32/decoder/arm.inc index 13f4b78a..5666b2c7 100644 --- a/src/frontend/A32/decoder/arm.inc +++ b/src/frontend/A32/decoder/arm.inc @@ -177,6 +177,7 @@ INST(arm_PKHBT, "PKHBT", "cccc01101000nnnnddddvvvvv001mmmm INST(arm_PKHTB, "PKHTB", "cccc01101000nnnnddddvvvvv101mmmm") // v6K // Reversal instructions +INST(arm_RBIT, "RBIT", "cccc011011111111dddd11110011mmmm") // v6T2 INST(arm_REV, "REV", "cccc011010111111dddd11110011mmmm") // v6 INST(arm_REV16, "REV16", "cccc011010111111dddd11111011mmmm") // v6 INST(arm_REVSH, "REVSH", "cccc011011111111dddd11111011mmmm") // v6 diff --git a/src/frontend/A32/disassembler/disassembler_arm.cpp b/src/frontend/A32/disassembler/disassembler_arm.cpp index d3717e8f..b3e7ef90 100644 --- a/src/frontend/A32/disassembler/disassembler_arm.cpp +++ b/src/frontend/A32/disassembler/disassembler_arm.cpp @@ -589,6 +589,9 @@ public: std::string arm_NOP() { return "nop"; } + std::string arm_RBIT(Cond cond, Reg d, Reg m) { + return fmt::format("rbit{} {}, {}", CondToString(cond), d, m); + } std::string arm_SEL(Cond cond, Reg n, Reg d, Reg m) { return fmt::format("sel{} {}, {}, {}", CondToString(cond), d, n, m); } diff --git a/src/frontend/A32/translate/translate_arm/reversal.cpp b/src/frontend/A32/translate/translate_arm/reversal.cpp index ae7f4506..d75ade41 100644 --- a/src/frontend/A32/translate/translate_arm/reversal.cpp +++ b/src/frontend/A32/translate/translate_arm/reversal.cpp @@ -8,6 +8,36 @@ namespace Dynarmic::A32 { +// RBIT , +bool ArmTranslatorVisitor::arm_RBIT(Cond cond, Reg d, Reg m) { + if (d == Reg::PC || m == Reg::PC) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U32 swapped = ir.ByteReverseWord(ir.GetRegister(m)); + + // ((x & 0xF0F0F0F0) >> 4) | ((x & 0x0F0F0F0F) << 4) + const IR::U32 first_lsr = ir.LogicalShiftRight(ir.And(swapped, ir.Imm32(0xF0F0F0F0)), ir.Imm8(4)); + const IR::U32 first_lsl = ir.LogicalShiftLeft(ir.And(swapped, ir.Imm32(0x0F0F0F0F)), ir.Imm8(4)); + const IR::U32 corrected = ir.Or(first_lsl, first_lsr); + + // ((x & 0x88888888) >> 3) | ((x & 0x44444444) >> 1) | + // ((x & 0x22222222) << 1) | ((x & 0x11111111) << 3) + const IR::U32 second_lsr = ir.LogicalShiftRight(ir.And(corrected, ir.Imm32(0x88888888)), ir.Imm8(3)); + const IR::U32 third_lsr = ir.LogicalShiftRight(ir.And(corrected, ir.Imm32(0x44444444)), ir.Imm8(1)); + const IR::U32 second_lsl = ir.LogicalShiftLeft(ir.And(corrected, ir.Imm32(0x22222222)), ir.Imm8(1)); + const IR::U32 third_lsl = ir.LogicalShiftLeft(ir.And(corrected, ir.Imm32(0x11111111)), ir.Imm8(3)); + + const IR::U32 result = ir.Or(ir.Or(ir.Or(second_lsr, third_lsr), second_lsl), third_lsl); + + ir.SetRegister(d, result); + return true; +} + // REV , bool ArmTranslatorVisitor::arm_REV(Cond cond, Reg d, Reg m) { if (d == Reg::PC || m == Reg::PC) { diff --git a/src/frontend/A32/translate/translate_arm/translate_arm.h b/src/frontend/A32/translate/translate_arm/translate_arm.h index fff624b3..d92a0050 100644 --- a/src/frontend/A32/translate/translate_arm/translate_arm.h +++ b/src/frontend/A32/translate/translate_arm/translate_arm.h @@ -209,6 +209,7 @@ struct ArmTranslatorVisitor final { // Miscellaneous instructions bool arm_CLZ(Cond cond, Reg d, Reg m); bool arm_NOP() { return true; } + bool arm_RBIT(Cond cond, Reg d, Reg m); bool arm_SEL(Cond cond, Reg n, Reg d, Reg m); // Unsigned sum of absolute difference functions diff --git a/tests/A32/fuzz_arm.cpp b/tests/A32/fuzz_arm.cpp index 4358d966..6515c821 100644 --- a/tests/A32/fuzz_arm.cpp +++ b/tests/A32/fuzz_arm.cpp @@ -763,9 +763,10 @@ TEST_CASE("Fuzz ARM reversal instructions", "[JitX64][A32]") { }; const std::array rev_instructions = { - InstructionGenerator("cccc011010111111dddd11110011mmmm", is_valid), - InstructionGenerator("cccc011010111111dddd11111011mmmm", is_valid), - InstructionGenerator("cccc011011111111dddd11111011mmmm", is_valid), + InstructionGenerator("cccc011011111111dddd11110011mmmm", is_valid), // RBIT + InstructionGenerator("cccc011010111111dddd11110011mmmm", is_valid), // REV + InstructionGenerator("cccc011010111111dddd11111011mmmm", is_valid), // REV16 + InstructionGenerator("cccc011011111111dddd11111011mmmm", is_valid), // REVSH }; SECTION("Reverse tests") {