A32: Implement Thumb-1's CBZ/CBNZ instructions

Introduced in ARMv6T2, this allows for short forward branches.
This commit is contained in:
Lioncash 2019-05-03 18:17:08 -04:00 committed by MerryMage
parent bd755ae494
commit 03e6899fd7
4 changed files with 32 additions and 0 deletions

View file

@ -116,6 +116,7 @@ std::optional<std::reference_wrapper<const Thumb16Matcher<V>>> DecodeThumb16(u16
// Branch instructions // Branch instructions
INST(&V::thumb16_BX, "BX", "010001110mmmm000"), // v4T INST(&V::thumb16_BX, "BX", "010001110mmmm000"), // v4T
INST(&V::thumb16_BLX_reg, "BLX (reg)", "010001111mmmm000"), // v5T INST(&V::thumb16_BLX_reg, "BLX (reg)", "010001111mmmm000"), // v5T
INST(&V::thumb16_CBZ_CBNZ, "CBZ/CBNZ", "1011o0i1iiiiinnn"), // v6T2
INST(&V::thumb16_UDF, "UDF", "11011110--------"), INST(&V::thumb16_UDF, "UDF", "11011110--------"),
INST(&V::thumb16_SVC, "SVC", "11011111xxxxxxxx"), INST(&V::thumb16_SVC, "SVC", "11011111xxxxxxxx"),
INST(&V::thumb16_B_t1, "B (T1)", "1101ccccvvvvvvvv"), INST(&V::thumb16_B_t1, "B (T1)", "1101ccccvvvvvvvv"),

View file

@ -337,6 +337,13 @@ public:
return fmt::format("blx {}", m); return fmt::format("blx {}", m);
} }
std::string thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm5, Reg n) {
const char* const name = nonzero ? "cbnz" : "cbz";
const u32 imm = concatenate(i, imm5, Imm<1>{0}).ZeroExtend();
return fmt::format("{} {}, #{}", name, n, imm);
}
std::string thumb16_UDF() { std::string thumb16_UDF() {
return fmt::format("udf"); return fmt::format("udf");
} }

View file

@ -884,6 +884,29 @@ struct ThumbTranslatorVisitor final {
return true; return true;
} }
// CB{N}Z <Rn>, <label>
bool thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm5, Reg n) {
const u32 imm = concatenate(i, imm5, Imm<1>{0}).ZeroExtend();
const IR::U32 rn = ir.GetRegister(n);
ir.SetCheckBit(ir.IsZero(rn));
const auto [cond_pass, cond_fail] = [this, imm, nonzero] {
const u32 target = ir.PC() + imm;
const auto skip = IR::Term::LinkBlock{ir.current_location.AdvancePC(2)};
const auto branch = IR::Term::LinkBlock{ir.current_location.AdvancePC(target)};
if (nonzero) {
return std::make_pair(skip, branch);
} else {
return std::make_pair(branch, skip);
}
}();
ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail});
return false;
}
bool thumb16_UDF() { bool thumb16_UDF() {
return InterpretThisInstruction(); return InterpretThisInstruction();
} }

View file

@ -291,6 +291,7 @@ TEST_CASE("Fuzz Thumb instructions set 2 (affects PC)", "[JitX64][Thumb]") {
const u32 c = Dynarmic::Common::Bits<9, 12>(inst); const u32 c = Dynarmic::Common::Bits<9, 12>(inst);
return c < 0b1110; // Don't want SWI or undefined instructions. return c < 0b1110; // Don't want SWI or undefined instructions.
}), }),
ThumbInstGen("1011o0i1iiiiinnn"), // CBZ/CBNZ
ThumbInstGen("10110110011x0xxx"), // CPS ThumbInstGen("10110110011x0xxx"), // CPS
// TODO: We currently have no control over the generated // TODO: We currently have no control over the generated