TranslateArm: Implement BLX (imm), BLX (reg) and BXJ

This commit is contained in:
MerryMage 2016-08-07 20:19:37 +01:00
parent 939bb5c0cb
commit 1af5bef32c
4 changed files with 43 additions and 21 deletions

View file

@ -119,8 +119,8 @@ struct LocationDescriptor {
return LocationDescriptor(new_arm_pc, tflag, eflag, fpscr);
}
LocationDescriptor AdvancePC(s32 amount) const {
return LocationDescriptor(arm_pc + amount, tflag, eflag, fpscr);
LocationDescriptor AdvancePC(int amount) const {
return LocationDescriptor(static_cast<u32>(arm_pc + amount), tflag, eflag, fpscr);
}
LocationDescriptor SetTFlag(bool new_tflag) const {

View file

@ -11,12 +11,10 @@
namespace Dynarmic {
namespace Arm {
bool ArmTranslatorVisitor::arm_B(Cond cond, Imm24 imm24)
{
s32 imm32 = Common::SignExtend<26, s32>(imm24 << 2) + 8;
// B <cond> <label>
if (ConditionPassed(cond))
{
bool ArmTranslatorVisitor::arm_B(Cond cond, Imm24 imm24) {
u32 imm32 = Common::SignExtend<26, u32>(imm24 << 2) + 8;
// B <label>
if (ConditionPassed(cond)) {
auto new_location = ir.current_location.AdvancePC(imm32);
ir.SetTerm(IR::Term::LinkBlock{ new_location });
return false;
@ -24,12 +22,10 @@ bool ArmTranslatorVisitor::arm_B(Cond cond, Imm24 imm24)
return true;
}
bool ArmTranslatorVisitor::arm_BL(Cond cond, Imm24 imm24)
{
s32 imm32 = Common::SignExtend<26, s32>(imm24 << 2) + 8;
// BL <cond> <label>
if (ConditionPassed(cond))
{
bool ArmTranslatorVisitor::arm_BL(Cond cond, Imm24 imm24) {
u32 imm32 = Common::SignExtend<26, u32>(imm24 << 2) + 8;
// BL <label>
if (ConditionPassed(cond)) {
ir.SetRegister(Reg::LR, ir.Imm32(ir.current_location.PC() + 4));
auto new_location = ir.current_location.AdvancePC(imm32);
ir.SetTerm(IR::Term::LinkBlock{ new_location });
@ -38,17 +34,28 @@ bool ArmTranslatorVisitor::arm_BL(Cond cond, Imm24 imm24)
return true;
}
bool ArmTranslatorVisitor::arm_BLX_imm(Cond cond, Imm24 imm24)
{
return InterpretThisInstruction();
bool ArmTranslatorVisitor::arm_BLX_imm(bool H, Imm24 imm24) {
u32 imm32 = Common::SignExtend<26, u32>((imm24 << 2)) + (H ? 2 : 0) + 8;
// BLX <label>
ir.SetRegister(Reg::LR, ir.Imm32(ir.current_location.PC() + 4));
auto new_location = ir.current_location.AdvancePC(imm32).SetTFlag(true);
ir.SetTerm(IR::Term::LinkBlock{ new_location });
return false;
}
bool ArmTranslatorVisitor::arm_BLX_reg(Cond cond, Reg m) {
return InterpretThisInstruction();
// BLX <Rm>
if (ConditionPassed(cond)) {
ir.SetRegister(Reg::LR, ir.Imm32(ir.current_location.PC() + 4));
ir.BXWritePC(ir.GetRegister(m));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
return true;
}
bool ArmTranslatorVisitor::arm_BX(Cond cond, Reg m) {
// BX <cond> <Rm>
// BX <Rm>
if (ConditionPassed(cond)) {
ir.BXWritePC(ir.GetRegister(m));
ir.SetTerm(IR::Term::ReturnToDispatch{});
@ -58,7 +65,8 @@ bool ArmTranslatorVisitor::arm_BX(Cond cond, Reg m) {
}
bool ArmTranslatorVisitor::arm_BXJ(Cond cond, Reg m) {
return InterpretThisInstruction();
// Jazelle not supported
return arm_BX(cond, m);
}
} // namespace Arm

View file

@ -65,7 +65,7 @@ struct ArmTranslatorVisitor final {
// Branch instructions
bool arm_B(Cond cond, Imm24 imm24);
bool arm_BL(Cond cond, Imm24 imm24);
bool arm_BLX_imm(Cond cond, Imm24 imm24);
bool arm_BLX_imm(bool H, Imm24 imm24);
bool arm_BLX_reg(Cond cond, Reg m);
bool arm_BX(Cond cond, Reg m);
bool arm_BXJ(Cond cond, Reg m);

View file

@ -560,6 +560,20 @@ TEST_CASE("Fuzz ARM data processing instructions", "[JitX64]") {
}
}
TEST_CASE("Fuzz ARM branch instructions", "[JitX64]") {
const std::array<InstructionGenerator, 6> instructions = {{
InstructionGenerator("1111101hvvvvvvvvvvvvvvvvvvvvvvvv"),
InstructionGenerator("cccc000100101111111111110011mmmm"),
InstructionGenerator("cccc1010vvvvvvvvvvvvvvvvvvvvvvvv"),
InstructionGenerator("cccc1011vvvvvvvvvvvvvvvvvvvvvvvv"),
InstructionGenerator("cccc000100101111111111110001mmmm"),
InstructionGenerator("cccc000100101111111111110010mmmm"),
}};
FuzzJitArm(1, 1, 10000, [&instructions]() -> u32 {
return instructions[RandInt<size_t>(0, instructions.size() - 1)].Generate();
});
}
TEST_CASE("Fuzz ARM reversal instructions", "[JitX64]") {
const auto is_valid = [](u32 instr) -> bool {
// R15 is UNPREDICTABLE