From 43a1a523f64403c75c9ab5a9400e32903b1f7b33 Mon Sep 17 00:00:00 2001
From: sunho <ksunhokim123@naver.com>
Date: Fri, 14 Aug 2020 06:45:47 +0900
Subject: [PATCH] A32: Fix thumb32 BL and BLX

More fields required
---
 src/frontend/A32/decoder/thumb32.inc           | 17 ++++-------------
 .../A32/translate/impl/thumb32_branch.cpp      | 18 +++++++++++++-----
 .../A32/translate/impl/translate_thumb.h       |  8 +++++---
 3 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc
index e03e2712..32ce0960 100644
--- a/src/frontend/A32/decoder/thumb32.inc
+++ b/src/frontend/A32/decoder/thumb32.inc
@@ -120,10 +120,11 @@
 //INST(thumb32_MRS_reg_2,      "MRS (reg)",                "111100111110----10-0------0-----")
 //INST(thumb32_HVC,            "HVC",                      "111101111110----1000------------")
 //INST(thumb32_SMC,            "SMC",                      "111101111111----1000000000000000")
-//INST(thumb32_UDF,            "UDF",                      "111101111111----1010------------")
+INST(thumb32_UDF,            "UDF",                      "111101111111----1010------------") // v6T2
 
-//INST(thumb32_BL,             "BL",                       "11110-----------11-1------------")
-//INST(thumb32_BLX,            "BLX",                      "11110-----------11-0------------")
+// Branch instructions
+INST(thumb32_BL_imm,         "BL (imm)",                 "11110Svvvvvvvvvv11j1jvvvvvvvvvvv") // v4T
+INST(thumb32_BLX_imm,        "BLX (imm)",                "11110Svvvvvvvvvv11j0jvvvvvvvvvvv") // v5T
 //INST(thumb32_B,              "B",                        "11110-----------10-1------------")
 //INST(thumb32_B_cond,         "B (cond)",                 "11110-----------10-0------------")
 
@@ -187,9 +188,6 @@
 //INST(thumb32_LDR_imm8,       "LDR (imm8)",               "111110000101--------1-----------")
 //INST(thumb32_LDR_imm12,      "LDR (imm12)",              "111110001101--------------------")
 
-// Undefined
-//INST(thumb32_UDF,            "UDF",                      "1111100--111--------------------")
-
 // Data Processing (register)
 //INST(thumb32_LSL_reg,        "LSL (reg)",                "11111010000-----1111----0000----")
 //INST(thumb32_LSR_reg,        "LSR (reg)",                "11111010001-----1111----0000----")
@@ -307,10 +305,3 @@ INST(thumb32_UMAAL,          "UMAAL",                    "111110111110nnnnllllhh
 //INST(thumb32_MCR,            "MCR",                      "11101110---0---------------1----")
 //INST(thumb32_MRC2,           "MRC2",                     "11111110---1---------------1----")
 //INST(thumb32_MRC,            "MRC",                      "11101110---1---------------1----")
-
-// Branch instructions
-INST(thumb32_BL_imm,         "BL (imm)",                 "11110vvvvvvvvvvv11111vvvvvvvvvvv") // v4T
-INST(thumb32_BLX_imm,        "BLX (imm)",                "11110vvvvvvvvvvv11101vvvvvvvvvvv") // v5T
-
-// Misc instructions
-INST(thumb32_UDF,            "UDF",                      "111101111111----1010------------") // v6T2
diff --git a/src/frontend/A32/translate/impl/thumb32_branch.cpp b/src/frontend/A32/translate/impl/thumb32_branch.cpp
index ebd82401..1a8e87e8 100644
--- a/src/frontend/A32/translate/impl/thumb32_branch.cpp
+++ b/src/frontend/A32/translate/impl/thumb32_branch.cpp
@@ -8,7 +8,10 @@
 namespace Dynarmic::A32 {
 
 // BL <label>
-bool ThumbTranslatorVisitor::thumb32_BL_imm(Imm<11> hi, Imm<11> lo) {
+bool ThumbTranslatorVisitor::thumb32_BL_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo) {
+    const Imm<1> i1{j1 == S};
+    const Imm<1> i2{j2 == S};
+
     if (ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock()) {
         return UnpredictableInstruction();
     }
@@ -16,14 +19,19 @@ bool ThumbTranslatorVisitor::thumb32_BL_imm(Imm<11> hi, Imm<11> lo) {
     ir.PushRSB(ir.current_location.AdvancePC(4));
     ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.PC() + 4) | 1));
 
-    const s32 imm32 = static_cast<s32>((concatenate(hi, lo).SignExtend<u32>() << 1) + 4);
-    const auto new_location = ir.current_location.AdvancePC(imm32).AdvanceIT();
+    const s32 imm32 = static_cast<s32>((concatenate(S, i1, i2, hi, lo).SignExtend<u32>() << 1) + 4);
+    const auto new_location = ir.current_location
+                                .AdvancePC(imm32)
+                                .AdvanceIT();
     ir.SetTerm(IR::Term::LinkBlock{new_location});
     return false;
 }
 
 // BLX <label>
-bool ThumbTranslatorVisitor::thumb32_BLX_imm(Imm<11> hi, Imm<11> lo) {
+bool ThumbTranslatorVisitor::thumb32_BLX_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo) {
+    const Imm<1> i1{j1 == S};
+    const Imm<1> i2{j2 == S};
+
     if (ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock()) {
         return UnpredictableInstruction();
     }
@@ -35,7 +43,7 @@ bool ThumbTranslatorVisitor::thumb32_BLX_imm(Imm<11> hi, Imm<11> lo) {
     ir.PushRSB(ir.current_location.AdvancePC(4));
     ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.PC() + 4) | 1));
 
-    const s32 imm32 = static_cast<s32>(concatenate(hi, lo).SignExtend<u32>() << 1);
+    const s32 imm32 = static_cast<s32>(concatenate(S, i1, i2, hi, lo).SignExtend<u32>() << 1);
     const auto new_location = ir.current_location
                                 .SetPC(ir.AlignPC(4) + imm32)
                                 .SetTFlag(false)
diff --git a/src/frontend/A32/translate/impl/translate_thumb.h b/src/frontend/A32/translate/impl/translate_thumb.h
index ceb54407..230a8121 100644
--- a/src/frontend/A32/translate/impl/translate_thumb.h
+++ b/src/frontend/A32/translate/impl/translate_thumb.h
@@ -116,11 +116,13 @@ struct ThumbTranslatorVisitor final {
     bool thumb16_B_t1(Cond cond, Imm<8> imm8);
     bool thumb16_B_t2(Imm<11> imm11);
 
-    // thumb32
-    bool thumb32_BL_imm(Imm<11> hi, Imm<11> lo);
-    bool thumb32_BLX_imm(Imm<11> hi, Imm<11> lo);
+    // thumb32 miscellaneous control instructions
     bool thumb32_UDF();
 
+    // thumb32 branch instructions
+    bool thumb32_BL_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo);
+    bool thumb32_BLX_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo);
+
     // thumb32 data processing (register) instructions
     bool thumb32_SXTB(Reg d, SignExtendRotation rotate, Reg m);
     bool thumb32_SXTB16(Reg d, SignExtendRotation rotate, Reg m);