diff --git a/src/backend/x64/a32_emit_x64.cpp b/src/backend/x64/a32_emit_x64.cpp index 8552b1a2..91cf3f13 100644 --- a/src/backend/x64/a32_emit_x64.cpp +++ b/src/backend/x64/a32_emit_x64.cpp @@ -501,6 +501,12 @@ void A32EmitX64::EmitA32SetZFlag(A32EmitContext& ctx, IR::Inst* inst) { } } +void A32EmitX64::EmitA32SetCheckBit(A32EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + const Xbyak::Reg8 to_store = ctx.reg_alloc.UseGpr(args[0]).cvt8(); + code.mov(code.byte[r15 + offsetof(A32JitState, check_bit)], to_store); +} + void A32EmitX64::EmitA32GetCFlag(A32EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); code.mov(result, dword[r15 + offsetof(A32JitState, CPSR_nzcv)]); @@ -1320,8 +1326,13 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor EmitTerminal(terminal.then_, initial_location); } -void A32EmitX64::EmitTerminalImpl(IR::Term::CheckBit, IR::LocationDescriptor) { - ASSERT_MSG(false, "Term::CheckBit should never be emitted by the A32 frontend"); +void A32EmitX64::EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location) { + Xbyak::Label fail; + code.cmp(code.byte[r15 + offsetof(A32JitState, check_bit)], u8(0)); + code.jz(fail); + EmitTerminal(terminal.then_, initial_location); + code.L(fail); + EmitTerminal(terminal.else_, initial_location); } void A32EmitX64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location) { diff --git a/src/backend/x64/a32_jitstate.h b/src/backend/x64/a32_jitstate.h index 9f6a23b7..46591af1 100644 --- a/src/backend/x64/a32_jitstate.h +++ b/src/backend/x64/a32_jitstate.h @@ -53,6 +53,7 @@ struct A32JitState { s64 cycles_to_run = 0; s64 cycles_remaining = 0; bool halt_requested = false; + bool check_bit = false; // Exclusive state static constexpr u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8; diff --git a/src/frontend/A32/decoder/thumb16.h b/src/frontend/A32/decoder/thumb16.h index e93a7556..87662396 100644 --- a/src/frontend/A32/decoder/thumb16.h +++ b/src/frontend/A32/decoder/thumb16.h @@ -116,6 +116,7 @@ std::optional>> DecodeThumb16(u16 // Branch instructions INST(&V::thumb16_BX, "BX", "010001110mmmm000"), // v4T 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_SVC, "SVC", "11011111xxxxxxxx"), INST(&V::thumb16_B_t1, "B (T1)", "1101ccccvvvvvvvv"), diff --git a/src/frontend/A32/disassembler/disassembler_thumb.cpp b/src/frontend/A32/disassembler/disassembler_thumb.cpp index a53475db..12c444da 100644 --- a/src/frontend/A32/disassembler/disassembler_thumb.cpp +++ b/src/frontend/A32/disassembler/disassembler_thumb.cpp @@ -337,6 +337,13 @@ public: 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() { return fmt::format("udf"); } diff --git a/src/frontend/A32/ir_emitter.cpp b/src/frontend/A32/ir_emitter.cpp index 11a9058c..ac540f92 100644 --- a/src/frontend/A32/ir_emitter.cpp +++ b/src/frontend/A32/ir_emitter.cpp @@ -106,6 +106,10 @@ void IREmitter::SetCpsrNZCVQ(const IR::U32& value) { Inst(Opcode::A32SetCpsrNZCVQ, value); } +void IREmitter::SetCheckBit(const IR::U1& value) { + Inst(Opcode::A32SetCheckBit, value); +} + IR::U1 IREmitter::GetCFlag() { return Inst(Opcode::A32GetCFlag); } diff --git a/src/frontend/A32/ir_emitter.h b/src/frontend/A32/ir_emitter.h index 3b4c9067..8798eea4 100644 --- a/src/frontend/A32/ir_emitter.h +++ b/src/frontend/A32/ir_emitter.h @@ -51,6 +51,7 @@ public: void SetCpsr(const IR::U32& value); void SetCpsrNZCV(const IR::U32& value); void SetCpsrNZCVQ(const IR::U32& value); + void SetCheckBit(const IR::U1& value); IR::U1 GetCFlag(); void SetNFlag(const IR::U1& value); void SetZFlag(const IR::U1& value); diff --git a/src/frontend/A32/translate/translate_thumb.cpp b/src/frontend/A32/translate/translate_thumb.cpp index fae7ccf5..f008e493 100644 --- a/src/frontend/A32/translate/translate_thumb.cpp +++ b/src/frontend/A32/translate/translate_thumb.cpp @@ -884,6 +884,29 @@ struct ThumbTranslatorVisitor final { return true; } + // CB{N}Z ,