diff --git a/src/core/arm/decoder/arm.cpp b/src/core/arm/decoder/arm.cpp index bcbe8ec41..afef775bc 100644 --- a/src/core/arm/decoder/arm.cpp +++ b/src/core/arm/decoder/arm.cpp @@ -190,8 +190,8 @@ static const std::array arm_instruction_table = {{ { "TST (rsr)", MakeMatcher<5>("cccc00010001nnnn0000ssss0rr1mmmm", &Visitor::TST_rsr) }, // all // Exception Generating instructions - { "BKPT", MakeMatcher<0>("----00010010------------0111----", &Visitor::BKPT) }, // ARMv5 - { "SVC", MakeMatcher<0>("----1111------------------------", &Visitor::SVC) }, // all + { "BKPT", MakeMatcher<3>("cccc00010010vvvvvvvvvvvv0111vvvv", &Visitor::BKPT) }, // ARMv5 + { "SVC", MakeMatcher<2>("cccc1111vvvvvvvvvvvvvvvvvvvvvvvv", &Visitor::SVC) }, // all { "UDF", MakeMatcher<0>("111001111111------------1111----", &Visitor::UDF) }, // all // Extension instructions diff --git a/src/core/arm/decoder/decoder.h b/src/core/arm/decoder/decoder.h index 3becf6f76..4800c4bcd 100644 --- a/src/core/arm/decoder/decoder.h +++ b/src/core/arm/decoder/decoder.h @@ -133,8 +133,8 @@ public: virtual void TST_rsr(Cond cond, Register Rn, Register Rs, ShiftType shift, Register Rm) = 0; // Exception generation instructions - virtual void BKPT() = 0; - virtual void SVC() = 0; + virtual void BKPT(Cond cond, Imm12 imm12, Imm4 imm4) = 0; + virtual void SVC(Cond cond, Imm24 imm24) = 0; virtual void UDF() = 0; // Extension functions diff --git a/src/core/arm/decoder/thumb.cpp b/src/core/arm/decoder/thumb.cpp index 8fb960f54..b5dec06d2 100644 --- a/src/core/arm/decoder/thumb.cpp +++ b/src/core/arm/decoder/thumb.cpp @@ -395,7 +395,7 @@ static const std::array thumb_instruction_table = { { { "BKPT", MakeMatcher("10111110xxxxxxxx", [](Visitor* v, u32 instruction) { // BKPT #imm8 Imm8 imm8 = bits<0, 7>(instruction); - v->BKPT(); + v->BKPT(0xE, imm8 >> 4, imm8 & 0xF); })}, { "STMIA/LDMIA", MakeMatcher("1100xxxxxxxxxxxx", [](Visitor* v, u32 instruction) { bool L = bits<11, 11>(instruction); @@ -418,7 +418,7 @@ static const std::array thumb_instruction_table = { { { "SWI", MakeMatcher("11011111xxxxxxxx", [](Visitor* v, u32 instruction) { // SWI #imm8 Imm8 imm8 = bits<0, 7>(instruction); - v->SVC(/*imm8*/); + v->SVC(0xE, imm8); })}, { "B", MakeMatcher("11100xxxxxxxxxxx", [](Visitor* v, u32 instruction) { // B diff --git a/src/core/arm/jit_x64/instructions/exception_generating.cpp b/src/core/arm/jit_x64/instructions/exception_generating.cpp index 07ae2faa0..4f76eb3d7 100644 --- a/src/core/arm/jit_x64/instructions/exception_generating.cpp +++ b/src/core/arm/jit_x64/instructions/exception_generating.cpp @@ -2,12 +2,67 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/x64/abi.h" + #include "core/arm/jit_x64/jit_x64.h" +#include "core/hle/svc.h" namespace JitX64 { -void JitX64::BKPT() { CompileInterpretInstruction(); } -void JitX64::SVC() { CompileInterpretInstruction(); } -void JitX64::UDF() { CompileInterpretInstruction(); } +using namespace Gen; + +static void Breakpoint(u32 imm) { + LOG_DEBUG(Core_ARM11, "Breakpoint instruction hit. Immediate: 0x%08X", imm); +} + +void JitX64::BKPT(Cond cond, ArmImm12 imm12, ArmImm4 imm4) { + cond_manager.CompileCond((ConditionCode) cond); + + ASSERT_MSG(false, "BKPT instruction @ pc=0x%08X", current.arm_pc); + + reg_alloc.FlushX64(ABI_PARAM1); + reg_alloc.LockX64(ABI_PARAM1); + + code->MOV(32, R(ABI_PARAM1), Imm32((imm12 << 4) | imm4)); + CompileCallHost(reinterpret_cast(&Breakpoint)); + + reg_alloc.UnlockX64(ABI_PARAM1); + + current.arm_pc += GetInstSize(); +} + +static void ServiceCall(u64 imm) { + SVC::CallSVC(imm & 0xFFFF); +} + +void JitX64::SVC(Cond cond, ArmImm24 imm24) { + cond_manager.CompileCond((ConditionCode)cond); + + // Flush and write out absolutely everything. + code->MOV(32, MJitStateArmPC(), Imm32(current.arm_pc)); + reg_alloc.FlushEverything(); + + reg_alloc.LockX64(ABI_PARAM1); + code->MOV(64, R(ABI_PARAM1), Imm32(imm24)); + CompileCallHost(reinterpret_cast(&ServiceCall)); + reg_alloc.UnlockX64(ABI_PARAM1); + + // Some service calls require a task switch, so go back to the dispatcher to check. + current.arm_pc += GetInstSize(); + code->ADD(32, MJitStateArmPC(), Imm32(GetInstSize())); + CompileReturnToDispatch(); + + stop_compilation = true; +} + +void JitX64::UDF() { + cond_manager.Always(); + + ASSERT_MSG(false, "UDF instruction @ pc=0x%08X", current.arm_pc); + + current.arm_pc += GetInstSize(); +} } diff --git a/src/core/arm/jit_x64/jit_x64.h b/src/core/arm/jit_x64/jit_x64.h index 7997d232f..a880284ad 100644 --- a/src/core/arm/jit_x64/jit_x64.h +++ b/src/core/arm/jit_x64/jit_x64.h @@ -221,8 +221,8 @@ private: void TST_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) override; // Exception generation instructions - void BKPT() override; - void SVC() override; + void BKPT(Cond cond, ArmImm12 imm12, ArmImm4 imm4) override; + void SVC(Cond cond, ArmImm24 imm24) override; void UDF() override; // Extension functions