Merged in Subv/dynarmic/rev (pull request #2)
Implemented ARM REV and REVSH instructions, with tests.
This commit is contained in:
commit
6708960aeb
4 changed files with 73 additions and 8 deletions
|
@ -59,7 +59,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename V>
|
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)
|
#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
|
//INST(&V::arm_PKHTB, "PKHTB", "cccc01101000nnnnddddvvvvv101mmmm"), // v6K
|
||||||
|
|
||||||
// Reversal instructions
|
// 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_REV16, "REV16", "cccc011010111111dddd11111011mmmm"), // v6
|
||||||
//INST(&V::arm_REVSH, "REVSH", "cccc011011111111dddd11111011mmmm"), // v6
|
INST(&V::arm_REVSH, "REVSH", "cccc011011111111dddd11111011mmmm"), // v6
|
||||||
|
|
||||||
// Saturation instructions
|
// Saturation instructions
|
||||||
//INST(&V::arm_SSAT, "SSAT", "cccc0110101vvvvvddddvvvvvr01nnnn"), // v6
|
//INST(&V::arm_SSAT, "SSAT", "cccc0110101vvvvvddddvvvvvr01nnnn"), // v6
|
||||||
|
|
|
@ -405,9 +405,15 @@ public:
|
||||||
std::string arm_PKHTB(Cond cond, Reg n, Reg d, Imm5 imm5, Reg m) { return "ice"; }
|
std::string arm_PKHTB(Cond cond, Reg n, Reg d, Imm5 imm5, Reg m) { return "ice"; }
|
||||||
|
|
||||||
// Reversal instructions
|
// Reversal instructions
|
||||||
std::string arm_REV(Cond cond, Reg d, Reg m) { return "ice"; }
|
std::string arm_REV(Cond cond, Reg d, Reg m) {
|
||||||
std::string arm_REV16(Cond cond, Reg d, Reg m) { return "ice"; }
|
return Common::StringFromFormat("rev%s %s, %s", CondStr(cond), RegStr(d), RegStr(m));
|
||||||
std::string arm_REVSH(Cond cond, Reg d, Reg m) { return "ice"; }
|
}
|
||||||
|
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
|
// Saturation instructions
|
||||||
std::string arm_SSAT(Cond cond, Imm5 sat_imm, Reg d, Imm5 imm5, bool sh, Reg n) { return "ice"; }
|
std::string arm_SSAT(Cond cond, Imm5 sat_imm, Reg d, Imm5 imm5, bool sh, Reg n) { return "ice"; }
|
||||||
|
|
|
@ -280,6 +280,32 @@ struct ArmTranslatorVisitor final {
|
||||||
bool arm_UDF() {
|
bool arm_UDF() {
|
||||||
return InterpretThisInstruction();
|
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
|
} // local namespace
|
||||||
|
|
|
@ -327,8 +327,8 @@ TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") {
|
||||||
if (Rd == 15) S = false;
|
if (Rd == 15) S = false;
|
||||||
u32 Rn = RandInt<u32>(0, 15);
|
u32 Rn = RandInt<u32>(0, 15);
|
||||||
u32 shifter_operand = RandInt<u32>(0, 0xFFF);
|
u32 shifter_operand = RandInt<u32>(0, 0xFFF);
|
||||||
u32
|
u32 assemble_randoms =
|
||||||
assemble_randoms = (shifter_operand << 0) | (Rd << 12) | (Rn << 16) | (S << 20) | (cond << 28);
|
(shifter_operand << 0) | (Rd << 12) | (Rn << 16) | (S << 20) | (cond << 28);
|
||||||
return instruction.Bits() | (assemble_randoms & ~instruction.Mask());
|
return instruction.Bits() | (assemble_randoms & ~instruction.Mask());
|
||||||
}
|
}
|
||||||
case 2: {
|
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));
|
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, [®_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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue