Implemented ARM REV and REVSH instructions, with tests.

This commit is contained in:
Subv 2016-07-17 14:45:42 -05:00
parent 24aa24b1bc
commit 0cdf5fe751
4 changed files with 73 additions and 8 deletions

View file

@ -59,7 +59,7 @@ private:
};
template <typename V>
static const std::array<ArmMatcher<V>, 4> g_arm_instruction_table = {
static const std::array<ArmMatcher<V>, 6> g_arm_instruction_table = {
#define INST(fn, name, bitstring) detail::detail<ArmMatcher, u32, 32>::GetMatcher<decltype(fn), fn>(name, bitstring)
@ -235,9 +235,9 @@ static const std::array<ArmMatcher<V>, 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

View file

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

View file

@ -280,6 +280,32 @@ struct ArmTranslatorVisitor final {
bool arm_UDF() {
return InterpretThisInstruction();
}
bool arm_REV(Cond cond, Reg d, Reg m) {
// REV<c> <Rd>, <Rm>
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<c> <Rd>, <Rm>
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

View file

@ -327,8 +327,8 @@ TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") {
if (Rd == 15) S = false;
u32 Rn = RandInt<u32>(0, 15);
u32 shifter_operand = RandInt<u32>(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<InstructionGenerator, 3> reg_instructions = {
{
InstructionGenerator("cccc011010111111dddd11110011mmmm", is_valid),
InstructionGenerator("cccc011010111111dddd11111011mmmm", is_valid),
InstructionGenerator("cccc011011111111dddd11111011mmmm", is_valid),
}
};
SECTION("REV tests") {
FuzzJitArm(1, 1, 10000, [&reg_instructions]() -> u32 {
return reg_instructions[0].Generate();
});
}
SECTION("REV16 tests") {
FuzzJitArm(1, 1, 10000, [&reg_instructions]() -> u32 {
return reg_instructions[1].Generate();
});
}
SECTION("REVSH tests") {
FuzzJitArm(1, 1, 10000, [&reg_instructions]() -> u32 {
return reg_instructions[2].Generate();
});
}
}