From 5f8eb7c51c604b1cae50e03803da8ee65d788b21 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Mon, 6 May 2019 00:18:13 +0100
Subject: [PATCH] A32/location_descriptor: Add CPSR.IT to
 A32::LocationDescriptor

---
 src/backend/x64/a32_emit_x64.cpp       |  2 +-
 src/backend/x64/a32_jitstate.cpp       | 41 +++++++++++++++-----------
 src/backend/x64/a32_jitstate.h         |  7 +++--
 src/frontend/A32/location_descriptor.h | 15 ++++++++--
 4 files changed, 42 insertions(+), 23 deletions(-)

diff --git a/src/backend/x64/a32_emit_x64.cpp b/src/backend/x64/a32_emit_x64.cpp
index a9871870..43fc30a4 100644
--- a/src/backend/x64/a32_emit_x64.cpp
+++ b/src/backend/x64/a32_emit_x64.cpp
@@ -222,7 +222,7 @@ void A32EmitX64::GenTerminalHandlers() {
         // This calculation has to match up with IREmitter::PushRSB
         constexpr size_t offsetof_pc = offsetof(A32JitState, Reg) + 15 * sizeof(u32);
         static_assert(offsetof_pc + 4 == offsetof(A32JitState, cpsr_et));
-        static_assert(offsetof_pc + 5 == offsetof(A32JitState, padding));
+        static_assert(offsetof_pc + 5 == offsetof(A32JitState, cpsr_it));
         static_assert(offsetof_pc + 6 == offsetof(A32JitState, fpcr_mode));
         code.mov(rbx, qword[r15 + offsetof_pc]);
     };
diff --git a/src/backend/x64/a32_jitstate.cpp b/src/backend/x64/a32_jitstate.cpp
index cb469424..2676cbc8 100644
--- a/src/backend/x64/a32_jitstate.cpp
+++ b/src/backend/x64/a32_jitstate.cpp
@@ -19,19 +19,21 @@ namespace Dynarmic::BackendX64 {
  *
  * ARM CPSR flags
  * --------------
- * N    bit 31       Negative flag
- * Z    bit 30       Zero flag
- * C    bit 29       Carry flag
- * V    bit 28       oVerflow flag
- * Q    bit 27       Saturation flag
- * J    bit 24       Jazelle instruction set flag
- * GE   bits 16-19   Greater than or Equal flags
- * E    bit 9        Data Endianness flag
- * A    bit 8        Disable imprecise Aborts
- * I    bit 7        Disable IRQ interrupts
- * F    bit 6        Disable FIQ interrupts
- * T    bit 5        Thumb instruction set flag
- * M    bits 0-4     Processor Mode bits
+ * N        bit 31       Negative flag
+ * Z        bit 30       Zero flag
+ * C        bit 29       Carry flag
+ * V        bit 28       oVerflow flag
+ * Q        bit 27       Saturation flag
+ * IT[1:0]  bits 25-26   If-Then execution state (lower 2 bits)
+ * J        bit 24       Jazelle instruction set flag
+ * GE       bits 16-19   Greater than or Equal flags
+ * IT[7:2]  bits 10-15   If-Then execution state (upper 6 bits)
+ * E        bit 9        Data Endianness flag
+ * A        bit 8        Disable imprecise Aborts
+ * I        bit 7        Disable IRQ interrupts
+ * F        bit 6        Disable FIQ interrupts
+ * T        bit 5        Thumb instruction set flag
+ * M        bits 0-4     Processor Mode bits
  *
  * x64 LAHF+SETO flags
  * -------------------
@@ -62,6 +64,9 @@ u32 A32JitState::Cpsr() const {
     cpsr |= Common::Bit<7>(cpsr_ge) ? 1 << 16 : 0;
     // E flag, T flag
     cpsr |= static_cast<u32>(cpsr_et) << 5;
+    // IT state
+    cpsr |= static_cast<u32>(cpsr_it & 0b11111100) << 8;
+    cpsr |= static_cast<u32>(cpsr_it & 0b00000011) << 25;
     // Other flags
     cpsr |= cpsr_jaifm;
 
@@ -81,8 +86,12 @@ void A32JitState::SetCpsr(u32 cpsr) {
     cpsr_ge |= Common::Bit<16>(cpsr) ? 0x000000FF : 0;
     // E flag, T flag
     cpsr_et = static_cast<u8>((cpsr >> 5) & 0x11);
+    // IT state
+    cpsr_it = 0;
+    cpsr_it |= static_cast<u8>((cpsr >> 8) & 0b11111100);
+    cpsr_it |= static_cast<u8>((cpsr >> 25) & 0b00000011);
     // Other flags
-    cpsr_jaifm = cpsr & 0x07F0FDDF;
+    cpsr_jaifm = cpsr & 0x010001DF;
 }
 
 void A32JitState::ResetRSB() {
@@ -186,8 +195,4 @@ void A32JitState::SetFpscr(u32 FPSCR) {
     }
 }
 
-u64 A32JitState::GetUniqueHash() const noexcept {
-    return (static_cast<u64>(cpsr_et) << 32) | (static_cast<u64>(fpcr_mode) << 48) | Reg[15];
-}
-
 } // namespace Dynarmic::BackendX64
diff --git a/src/backend/x64/a32_jitstate.h b/src/backend/x64/a32_jitstate.h
index 732bdccc..f59e8831 100644
--- a/src/backend/x64/a32_jitstate.h
+++ b/src/backend/x64/a32_jitstate.h
@@ -31,9 +31,12 @@ struct A32JitState {
 
     // Location Descriptor related (the order of fields is important)
     u8 cpsr_et = 0; ///< Format: 000E000T
-    u8 padding = 0;
+    u8 cpsr_it = 0; ///< Format: ccccmmmm
     u16 fpcr_mode = 0; ///< Top 16 bits of FPCR
-    u64 GetUniqueHash() const noexcept;
+    u64 GetUniqueHash() const noexcept {
+        const u64 upper_half = u64(cpsr_et) | (u64(cpsr_it) << 8) | (u64(fpcr_mode) << 16);
+        return (upper_half << 32) | Reg[15];
+    }
 
     // CPSR fields
     u32 cpsr_ge = 0;
diff --git a/src/frontend/A32/location_descriptor.h b/src/frontend/A32/location_descriptor.h
index 842e44bd..d484638d 100644
--- a/src/frontend/A32/location_descriptor.h
+++ b/src/frontend/A32/location_descriptor.h
@@ -12,6 +12,7 @@
 #include "common/common_types.h"
 #include "frontend/A32/FPSCR.h"
 #include "frontend/A32/PSR.h"
+#include "frontend/A32/ITState.h"
 #include "frontend/ir/location_descriptor.h"
 
 namespace Dynarmic::A32 {
@@ -25,7 +26,7 @@ namespace Dynarmic::A32 {
 class LocationDescriptor {
 public:
     // Indicates bits that should be preserved within descriptors.
-    static constexpr u32 CPSR_MODE_MASK  = 0x00000220;
+    static constexpr u32 CPSR_MODE_MASK  = 0x0600FE20;
     static constexpr u32 FPSCR_MODE_MASK = 0x07F70000;
 
     LocationDescriptor(u32 arm_pc, PSR cpsr, FPSCR fpscr)
@@ -35,12 +36,14 @@ public:
         arm_pc = static_cast<u32>(o.Value());
         cpsr.T(o.Value() & (u64(0x01) << 32));
         cpsr.E(o.Value() & (u64(0x10) << 32));
+        cpsr.IT(ITState{static_cast<u8>(o.Value() >> 40)});
         fpscr = static_cast<u32>(o.Value() >> 32) & FPSCR_MODE_MASK;
     }
 
     u32 PC() const { return arm_pc; }
     bool TFlag() const { return cpsr.T(); }
     bool EFlag() const { return cpsr.E(); }
+    ITState IT() const { return cpsr.IT(); }
 
     A32::PSR CPSR() const { return cpsr; }
     A32::FPSCR FPSCR() const { return fpscr; }
@@ -79,14 +82,22 @@ public:
         return LocationDescriptor(arm_pc, cpsr, A32::FPSCR{new_fpscr & FPSCR_MODE_MASK});
     }
 
+    LocationDescriptor AdvanceIT() const {
+        PSR new_cpsr = cpsr;
+        new_cpsr.IT(new_cpsr.IT().Advance());
+
+        return LocationDescriptor(arm_pc, new_cpsr, fpscr);
+    }
+
     u64 UniqueHash() const noexcept {
         // This value MUST BE UNIQUE.
         // This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
         const u64 pc_u64 = u64(arm_pc);
         const u64 fpscr_u64 = u64(fpscr.Value()) << 32;
+        const u64 it_u64 = u64(cpsr.IT().Value()) << 40;
         const u64 t_u64 = cpsr.T() ? u64(0x01) << 32 : 0;
         const u64 e_u64 = cpsr.E() ? u64(0x10) << 32 : 0;
-        return pc_u64 | fpscr_u64 | t_u64 | e_u64;
+        return pc_u64 | fpscr_u64 | it_u64 | t_u64 | e_u64;
     }
 
     operator IR::LocationDescriptor() const {