From f023bbb893aa8da3ee47ec5c3c91db6338bebe88 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sun, 28 Jan 2018 12:55:47 +0000
Subject: [PATCH] A32: Add ExceptionRaised IR instruction and use it

---
 src/backend_x64/a32_emit_x64.cpp                     | 12 ++++++++++++
 src/frontend/A32/ir_emitter.cpp                      |  4 ++++
 src/frontend/A32/ir_emitter.h                        |  4 ++++
 src/frontend/A32/translate/translate_arm.cpp         | 10 +++++++++-
 .../translate/translate_arm/exception_generating.cpp |  2 +-
 .../A32/translate/translate_arm/translate_arm.h      |  1 +
 src/frontend/ir/opcodes.inc                          |  1 +
 7 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/src/backend_x64/a32_emit_x64.cpp b/src/backend_x64/a32_emit_x64.cpp
index 7f2f3784..9df22d48 100644
--- a/src/backend_x64/a32_emit_x64.cpp
+++ b/src/backend_x64/a32_emit_x64.cpp
@@ -584,6 +584,18 @@ void A32EmitX64::EmitA32CallSupervisor(A32EmitContext& ctx, IR::Inst* inst) {
     code->SwitchMxcsrOnEntry();
 }
 
+void A32EmitX64::EmitA32ExceptionRaised(A32EmitContext& ctx, IR::Inst* inst) {
+    ctx.reg_alloc.HostCall(nullptr);
+    auto args = ctx.reg_alloc.GetArgumentInfo(inst);
+    ASSERT(args[0].IsImmediate() && args[1].IsImmediate());
+    u32 pc = args[0].GetImmediateU32();
+    u64 exception = args[1].GetImmediateU64();
+    DEVIRT(config.callbacks, &A32::UserCallbacks::ExceptionRaised).EmitCall(code, [&](Xbyak::Reg64 param1, Xbyak::Reg64 param2) {
+        code->mov(param1, pc);
+        code->mov(param2, exception);
+    });
+}
+
 static u32 GetFpscrImpl(A32JitState* jit_state) {
     return jit_state->Fpscr();
 }
diff --git a/src/frontend/A32/ir_emitter.cpp b/src/frontend/A32/ir_emitter.cpp
index 38428403..e1ac917f 100644
--- a/src/frontend/A32/ir_emitter.cpp
+++ b/src/frontend/A32/ir_emitter.cpp
@@ -86,6 +86,10 @@ void IREmitter::CallSupervisor(const IR::U32& value) {
     Inst(Opcode::A32CallSupervisor, value);
 }
 
+void IREmitter::ExceptionRaised(const Exception exception) {
+    Inst(Opcode::A64ExceptionRaised, Imm32(PC()), Imm64(static_cast<u64>(exception)));
+}
+
 IR::U32 IREmitter::GetCpsr() {
     return Inst<IR::U32>(Opcode::A32GetCpsr);
 }
diff --git a/src/frontend/A32/ir_emitter.h b/src/frontend/A32/ir_emitter.h
index 821f35dc..88793372 100644
--- a/src/frontend/A32/ir_emitter.h
+++ b/src/frontend/A32/ir_emitter.h
@@ -18,6 +18,8 @@
 
 namespace Dynarmic::A32 {
 
+enum class Exception;
+
 /**
  * Convenience class to construct a basic block of the intermediate representation.
  * `block` is the resulting block.
@@ -41,7 +43,9 @@ public:
     void BranchWritePC(const IR::U32& value);
     void BXWritePC(const IR::U32& value);
     void LoadWritePC(const IR::U32& value);
+
     void CallSupervisor(const IR::U32& value);
+    void ExceptionRaised(Exception exception);
 
     IR::U32 GetCpsr();
     void SetCpsr(const IR::U32& value);
diff --git a/src/frontend/A32/translate/translate_arm.cpp b/src/frontend/A32/translate/translate_arm.cpp
index af1da5ad..09a03ee2 100644
--- a/src/frontend/A32/translate/translate_arm.cpp
+++ b/src/frontend/A32/translate/translate_arm.cpp
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "common/assert.h"
+#include "dynarmic/A32/config.h"
 #include "frontend/A32/decoder/arm.h"
 #include "frontend/A32/decoder/vfp2.h"
 #include "frontend/A32/location_descriptor.h"
@@ -117,7 +118,14 @@ bool ArmTranslatorVisitor::InterpretThisInstruction() {
 }
 
 bool ArmTranslatorVisitor::UnpredictableInstruction() {
-    ASSERT_MSG(false, "UNPREDICTABLE");
+    ir.ExceptionRaised(Exception::UnpredictableInstruction);
+    ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
+    return false;
+}
+
+bool ArmTranslatorVisitor::UndefinedInstruction() {
+    ir.ExceptionRaised(Exception::UndefinedInstruction);
+    ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
     return false;
 }
 
diff --git a/src/frontend/A32/translate/translate_arm/exception_generating.cpp b/src/frontend/A32/translate/translate_arm/exception_generating.cpp
index 69c412eb..cbdae36c 100644
--- a/src/frontend/A32/translate/translate_arm/exception_generating.cpp
+++ b/src/frontend/A32/translate/translate_arm/exception_generating.cpp
@@ -26,7 +26,7 @@ bool ArmTranslatorVisitor::arm_SVC(Cond cond, Imm24 imm24) {
 }
 
 bool ArmTranslatorVisitor::arm_UDF() {
-    return InterpretThisInstruction();
+    return UndefinedInstruction();
 }
 
 } // namespace Dynarmic::A32
diff --git a/src/frontend/A32/translate/translate_arm/translate_arm.h b/src/frontend/A32/translate/translate_arm/translate_arm.h
index 6d63c55c..f137dc93 100644
--- a/src/frontend/A32/translate/translate_arm/translate_arm.h
+++ b/src/frontend/A32/translate/translate_arm/translate_arm.h
@@ -35,6 +35,7 @@ struct ArmTranslatorVisitor final {
     bool ConditionPassed(Cond cond);
     bool InterpretThisInstruction();
     bool UnpredictableInstruction();
+    bool UndefinedInstruction();
 
     static u32 rotr(u32 x, int shift) {
         shift &= 31;
diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc
index f408a44b..81b958f2 100644
--- a/src/frontend/ir/opcodes.inc
+++ b/src/frontend/ir/opcodes.inc
@@ -29,6 +29,7 @@ A32OPC(SetGEFlags,              T::Void,        T::U32
 A32OPC(SetGEFlagsCompressed,    T::Void,        T::U32                                          )
 A32OPC(BXWritePC,               T::Void,        T::U32                                          )
 A32OPC(CallSupervisor,          T::Void,        T::U32                                          )
+A32OPC(ExceptionRaised,         T::Void,        T::U32,         T::U64                          )
 A32OPC(GetFpscr,                T::U32,                                                         )
 A32OPC(SetFpscr,                T::Void,        T::U32,                                         )
 A32OPC(GetFpscrNZCV,            T::U32,                                                         )