diff --git a/include/dynarmic/A64/config.h b/include/dynarmic/A64/config.h index fb7728d8..5a3bc1c5 100644 --- a/include/dynarmic/A64/config.h +++ b/include/dynarmic/A64/config.h @@ -16,6 +16,17 @@ namespace A64 { using VAddr = std::uint64_t; +enum class Exception { + /// An UndefinedFault occured due to executing instruction with an unallocated encoding + UnallocatedEncoding, + /// An UndefinedFault occured due to executing instruction containing a reserved value + ReservedValue, + /// An unpredictable instruction is to be executed. Implementation-defined behaviour should now happen. + /// This behaviour is up to the user of this library to define. + /// Note: Constraints on unpredictable behaviour are specified in the ARMv8 ARM. + UnpredictableInstruction, +}; + struct UserCallbacks { virtual ~UserCallbacks() = default; @@ -47,6 +58,8 @@ struct UserCallbacks { // This callback is called whenever a SVC instruction is executed. virtual void CallSVC(std::uint32_t swi) = 0; + virtual void ExceptionRaised(VAddr pc, Exception exception) = 0; + // Timing-related callbacks // ticks ticks have passed virtual void AddTicks(std::uint64_t ticks) = 0; diff --git a/src/backend_x64/a64_emit_x64.cpp b/src/backend_x64/a64_emit_x64.cpp index faa284b8..9397c67e 100644 --- a/src/backend_x64/a64_emit_x64.cpp +++ b/src/backend_x64/a64_emit_x64.cpp @@ -228,6 +228,18 @@ void A64EmitX64::EmitA64CallSupervisor(A64EmitContext& ctx, IR::Inst* inst) { }); } +void A64EmitX64::EmitA64ExceptionRaised(A64EmitContext& ctx, IR::Inst* inst) { + ctx.reg_alloc.HostCall(nullptr); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + ASSERT(args[0].IsImmediate() && args[1].IsImmediate()); + u64 pc = args[0].GetImmediateU64(); + u64 exception = args[1].GetImmediateU64(); + DEVIRT(conf.callbacks, &A64::UserCallbacks::ExceptionRaised).EmitCall(code, [&](Xbyak::Reg64 param1, Xbyak::Reg64 param2) { + code->mov(param1, pc); + code->mov(param2, exception); + }); +} + void A64EmitX64::EmitA64ReadMemory8(A64EmitContext& ctx, IR::Inst* inst) { DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead8).EmitCall(code, [&](Xbyak::Reg64 vaddr) { ASSERT(vaddr == code->ABI_PARAM2); diff --git a/src/frontend/A64/ir_emitter.cpp b/src/frontend/A64/ir_emitter.cpp index 3a07bf74..cfc15cdf 100644 --- a/src/frontend/A64/ir_emitter.cpp +++ b/src/frontend/A64/ir_emitter.cpp @@ -38,6 +38,10 @@ void IREmitter::CallSupervisor(u32 imm) { Inst(Opcode::A64CallSupervisor, Imm32(imm)); } +void IREmitter::ExceptionRaised(Exception exception) { + Inst(Opcode::A64ExceptionRaised, Imm64(PC()), Imm64(static_cast(exception))); +} + IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr) { return Inst(Opcode::A64ReadMemory8, vaddr); } diff --git a/src/frontend/A64/ir_emitter.h b/src/frontend/A64/ir_emitter.h index 53f2d488..ff0a3dfe 100644 --- a/src/frontend/A64/ir_emitter.h +++ b/src/frontend/A64/ir_emitter.h @@ -8,6 +8,8 @@ #include +#include + #include "common/common_types.h" #include "frontend/A64/location_descriptor.h" #include "frontend/A64/types.h" @@ -36,6 +38,7 @@ public: void SetNZCV(const IR::NZCV& nzcv); void CallSupervisor(u32 imm); + void ExceptionRaised(Exception exception); IR::U8 ReadMemory8(const IR::U64& vaddr); IR::U16 ReadMemory16(const IR::U64& vaddr); diff --git a/src/frontend/A64/translate/impl/impl.cpp b/src/frontend/A64/translate/impl/impl.cpp index 57f8fdb2..b66386a0 100644 --- a/src/frontend/A64/translate/impl/impl.cpp +++ b/src/frontend/A64/translate/impl/impl.cpp @@ -17,17 +17,20 @@ bool TranslatorVisitor::InterpretThisInstruction() { } bool TranslatorVisitor::UnpredictableInstruction() { - ASSERT_MSG(false, "UNPREDICTABLE"); + ir.ExceptionRaised(Exception::UnpredictableInstruction); + ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}}); return false; } bool TranslatorVisitor::ReservedValue() { - ASSERT_MSG(false, "RESERVEDVALUE"); + ir.ExceptionRaised(Exception::ReservedValue); + ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}}); return false; } bool TranslatorVisitor::UnallocatedEncoding() { - ASSERT_MSG(false, "UNALLOCATEDENCODING"); + ir.ExceptionRaised(Exception::UnallocatedEncoding); + ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}}); return false; } diff --git a/src/frontend/ir/microinstruction.cpp b/src/frontend/ir/microinstruction.cpp index f1eff458..bd68255b 100644 --- a/src/frontend/ir/microinstruction.cpp +++ b/src/frontend/ir/microinstruction.cpp @@ -229,7 +229,8 @@ bool Inst::WritesToFPSCR() const { bool Inst::CausesCPUException() const { return op == Opcode::Breakpoint || op == Opcode::A32CallSupervisor || - op == Opcode::A64CallSupervisor; + op == Opcode::A64CallSupervisor || + op == Opcode::A64ExceptionRaised; } bool Inst::AltersExclusiveState() const { diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index af5055cf..fbb9f46b 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -46,6 +46,7 @@ A64OPC(SetX, T::Void, T::A64Reg, T::U64 A64OPC(SetSP, T::Void, T::U64 ) A64OPC(SetPC, T::Void, T::U64 ) A64OPC(CallSupervisor, T::Void, T::U32 ) +A64OPC(ExceptionRaised, T::Void, T::U64, T::U64 ) // Hints OPCODE(PushRSB, T::Void, T::U64 )