A32: Implement ARM-mode RBIT

This commit is contained in:
Lioncash 2019-04-20 10:16:18 -04:00 committed by MerryMage
parent b2f7a0e7ba
commit 7305d13221
5 changed files with 39 additions and 3 deletions

View file

@ -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

View file

@ -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);
}

View file

@ -8,6 +8,36 @@
namespace Dynarmic::A32 {
// RBIT<c> <Rd>, <Rm>
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<c> <Rd>, <Rm>
bool ArmTranslatorVisitor::arm_REV(Cond cond, Reg d, Reg m) {
if (d == Reg::PC || m == Reg::PC) {

View file

@ -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

View file

@ -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") {