Просмотр исходного кода

ARMeilleure: Thumb support (All T16 instructions) (#3105)

* Decoders: Add InITBlock argument

* OpCodeTable: Minor cleanup

* OpCodeTable: Remove existing thumb instruction implementations

* OpCodeTable: Prepare for thumb instructions

* OpCodeTables: Improve thumb fast lookup

* Tests: Prepare for thumb tests

* T16: Implement BX

* T16: Implement LSL/LSR/ASR (imm)

* T16: Implement ADDS, SUBS (reg)

* T16: Implement ADDS, SUBS (3-bit immediate)

* T16: Implement MOVS, CMP, ADDS, SUBS (8-bit immediate)

* T16: Implement ANDS, EORS, LSLS, LSRS, ASRS, ADCS, SBCS, RORS, TST, NEGS, CMP, CMN, ORRS, MULS, BICS, MVNS (low registers)

* T16: Implement ADD, CMP, MOV (high reg)

* T16: Implement BLX (reg)

* T16: Implement LDR (literal)

* T16: Implement {LDR,STR}{,H,B,SB,SH} (register)

* T16: Implement {LDR,STR}{,B,H} (immediate)

* T16: Implement LDR/STR (SP)

* T16: Implement ADR

* T16: Implement Add to SP (immediate)

* T16: Implement ADD/SUB (SP)

* T16: Implement SXTH, SXTB, UXTH, UTXB

* T16: Implement CBZ, CBNZ

* T16: Implement PUSH, POP

* T16: Implement REV, REV16, REVSH

* T16: Implement NOP

* T16: Implement LDM, STM

* T16: Implement SVC

* T16: Implement B (conditional)

* T16: Implement B (unconditional)

* T16: Implement IT

* fixup! T16: Implement ADD/SUB (SP)

* fixup! T16: Implement Add to SP (immediate)

* fixup! T16: Implement IT

* CpuTestThumb: Add randomized tests

* Remove inITBlock argument

* Address nits

* Use index to handle IfThenBlockState

* Reduce line noise

* fixup

* nit
merry 4 лет назад
Родитель
Сommit
98e05ee4b7
57 измененных файлов с 1251 добавлено и 102 удалено
  1. 19 2
      ARMeilleure/Decoders/Decoder.cs
  2. 9 0
      ARMeilleure/Decoders/IOpCode32Adr.cs
  3. 1 1
      ARMeilleure/Decoders/IOpCode32Alu.cs
  4. 9 0
      ARMeilleure/Decoders/IOpCode32AluImm.cs
  5. 10 0
      ARMeilleure/Decoders/IOpCode32AluRsImm.cs
  6. 10 0
      ARMeilleure/Decoders/IOpCode32AluRsReg.cs
  7. 6 0
      ARMeilleure/Decoders/IOpCode32Exception.cs
  8. 4 0
      ARMeilleure/Decoders/IOpCode32Mem.cs
  9. 2 0
      ARMeilleure/Decoders/IOpCode32MemMult.cs
  10. 7 0
      ARMeilleure/Decoders/IOpCode32MemReg.cs
  11. 2 3
      ARMeilleure/Decoders/OpCode.cs
  12. 1 1
      ARMeilleure/Decoders/OpCode32Alu.cs
  13. 1 1
      ARMeilleure/Decoders/OpCode32AluImm.cs
  14. 1 1
      ARMeilleure/Decoders/OpCode32AluMla.cs
  15. 1 1
      ARMeilleure/Decoders/OpCode32AluRsImm.cs
  16. 1 1
      ARMeilleure/Decoders/OpCode32AluRsReg.cs
  17. 1 1
      ARMeilleure/Decoders/OpCode32AluUmull.cs
  18. 1 1
      ARMeilleure/Decoders/OpCode32Exception.cs
  19. 1 1
      ARMeilleure/Decoders/OpCode32MemReg.cs
  20. 24 0
      ARMeilleure/Decoders/OpCodeT16AddSubImm3.cs
  21. 20 0
      ARMeilleure/Decoders/OpCodeT16AddSubReg.cs
  22. 23 0
      ARMeilleure/Decoders/OpCodeT16AddSubSp.cs
  23. 20 0
      ARMeilleure/Decoders/OpCodeT16Adr.cs
  24. 12 10
      ARMeilleure/Decoders/OpCodeT16AluImm8.cs
  25. 24 0
      ARMeilleure/Decoders/OpCodeT16AluImmZero.cs
  26. 20 0
      ARMeilleure/Decoders/OpCodeT16AluRegHigh.cs
  27. 20 0
      ARMeilleure/Decoders/OpCodeT16AluRegLow.cs
  28. 22 0
      ARMeilleure/Decoders/OpCodeT16AluUx.cs
  29. 15 0
      ARMeilleure/Decoders/OpCodeT16BImm11.cs
  30. 17 0
      ARMeilleure/Decoders/OpCodeT16BImm8.cs
  31. 19 0
      ARMeilleure/Decoders/OpCodeT16BImmCmp.cs
  32. 2 2
      ARMeilleure/Decoders/OpCodeT16BReg.cs
  33. 14 0
      ARMeilleure/Decoders/OpCodeT16Exception.cs
  34. 34 0
      ARMeilleure/Decoders/OpCodeT16IfThen.cs
  35. 58 0
      ARMeilleure/Decoders/OpCodeT16MemImm5.cs
  36. 26 0
      ARMeilleure/Decoders/OpCodeT16MemLit.cs
  37. 34 0
      ARMeilleure/Decoders/OpCodeT16MemMult.cs
  38. 27 0
      ARMeilleure/Decoders/OpCodeT16MemReg.cs
  39. 28 0
      ARMeilleure/Decoders/OpCodeT16MemSp.cs
  40. 42 0
      ARMeilleure/Decoders/OpCodeT16MemStack.cs
  41. 24 0
      ARMeilleure/Decoders/OpCodeT16ShiftImm.cs
  42. 27 0
      ARMeilleure/Decoders/OpCodeT16ShiftReg.cs
  43. 24 0
      ARMeilleure/Decoders/OpCodeT16SpRel.cs
  44. 103 31
      ARMeilleure/Decoders/OpCodeTable.cs
  45. 14 14
      ARMeilleure/Instructions/InstEmitAlu32.cs
  46. 20 10
      ARMeilleure/Instructions/InstEmitAluHelper.cs
  47. 2 2
      ARMeilleure/Instructions/InstEmitException32.cs
  48. 28 1
      ARMeilleure/Instructions/InstEmitFlow32.cs
  49. 9 3
      ARMeilleure/Instructions/InstEmitMemory32.cs
  50. 2 2
      ARMeilleure/Instructions/InstEmitMemoryHelper.cs
  51. 10 10
      ARMeilleure/Instructions/InstEmitMul32.cs
  52. 3 0
      ARMeilleure/Instructions/InstName.cs
  53. 19 0
      ARMeilleure/Translation/ArmEmitterContext.cs
  54. 12 0
      ARMeilleure/Translation/Translator.cs
  55. 12 2
      Ryujinx.Tests.Unicorn/UnicornAArch32.cs
  56. 40 1
      Ryujinx.Tests/Cpu/CpuTest32.cs
  57. 314 0
      Ryujinx.Tests/Cpu/CpuTestThumb.cs

+ 19 - 2
ARMeilleure/Decoders/Decoder.cs

@@ -195,12 +195,13 @@ namespace ARMeilleure.Decoders
             ulong          limitAddress)
         {
             ulong address = block.Address;
+            int itBlockSize = 0;
 
             OpCode opCode;
 
             do
             {
-                if (address >= limitAddress)
+                if (address >= limitAddress && itBlockSize == 0)
                 {
                     break;
                 }
@@ -210,6 +211,15 @@ namespace ARMeilleure.Decoders
                 block.OpCodes.Add(opCode);
 
                 address += (ulong)opCode.OpCodeSizeInBytes;
+
+                if (opCode is OpCodeT16IfThen it)
+                {
+                    itBlockSize = it.IfThenBlockSize;
+                }
+                else if (itBlockSize > 0)
+                {
+                    itBlockSize--;
+                }
             }
             while (!(IsBranch(opCode) || IsException(opCode)));
 
@@ -345,7 +355,14 @@ namespace ARMeilleure.Decoders
             }
             else
             {
-                return new OpCode(inst, address, opCode);
+                if (mode == ExecutionMode.Aarch32Thumb)
+                {
+                    return new OpCodeT16(inst, address, opCode);
+                }
+                else
+                {
+                    return new OpCode(inst, address, opCode);
+                }
             }
         }
     }

+ 9 - 0
ARMeilleure/Decoders/IOpCode32Adr.cs

@@ -0,0 +1,9 @@
+namespace ARMeilleure.Decoders
+{
+    interface IOpCode32Adr
+    {
+        int Rd { get; }
+
+        int Immediate { get; }
+    }
+}

+ 1 - 1
ARMeilleure/Decoders/IOpCode32Alu.cs

@@ -5,6 +5,6 @@ namespace ARMeilleure.Decoders
         int Rd { get; }
         int Rn { get; }
 
-        bool SetFlags { get; }
+        bool? SetFlags { get; }
     }
 }

+ 9 - 0
ARMeilleure/Decoders/IOpCode32AluImm.cs

@@ -0,0 +1,9 @@
+namespace ARMeilleure.Decoders
+{
+    interface IOpCode32AluImm : IOpCode32Alu
+    {
+        int Immediate { get; }
+
+        bool IsRotated { get; }
+    }
+}

+ 10 - 0
ARMeilleure/Decoders/IOpCode32AluRsImm.cs

@@ -0,0 +1,10 @@
+namespace ARMeilleure.Decoders
+{
+    interface IOpCode32AluRsImm : IOpCode32Alu
+    {
+        int Rm { get; }
+        int Immediate { get; }
+
+        ShiftType ShiftType { get; }
+    }
+}

+ 10 - 0
ARMeilleure/Decoders/IOpCode32AluRsReg.cs

@@ -0,0 +1,10 @@
+namespace ARMeilleure.Decoders
+{
+    interface IOpCode32AluRsReg : IOpCode32Alu
+    {
+        int Rm { get; }
+        int Rs { get; }
+
+        ShiftType ShiftType { get; }
+    }
+}

+ 6 - 0
ARMeilleure/Decoders/IOpCode32Exception.cs

@@ -0,0 +1,6 @@
+namespace ARMeilleure.Decoders;
+
+interface IOpCode32Exception
+{
+    int Id { get; }
+}

+ 4 - 0
ARMeilleure/Decoders/IOpCode32Mem.cs

@@ -7,5 +7,9 @@ namespace ARMeilleure.Decoders
 
         bool WBack { get; }
         bool IsLoad { get; }
+        bool Index { get; }
+        bool Add { get; }
+
+        int Immediate { get; }
     }
 }

+ 2 - 0
ARMeilleure/Decoders/IOpCode32MemMult.cs

@@ -9,5 +9,7 @@ namespace ARMeilleure.Decoders
         int PostOffset { get; }
 
         bool IsLoad { get; }
+
+        int Offset { get; }
     }
 }

+ 7 - 0
ARMeilleure/Decoders/IOpCode32MemReg.cs

@@ -0,0 +1,7 @@
+namespace ARMeilleure.Decoders
+{
+    interface IOpCode32MemReg : IOpCode32Mem
+    {
+        int Rm { get; }
+    }
+}

+ 2 - 3
ARMeilleure/Decoders/OpCode.cs

@@ -18,10 +18,9 @@ namespace ARMeilleure.Decoders
 
         public OpCode(InstDescriptor inst, ulong address, int opCode)
         {
-            Address   = address;
-            RawOpCode = opCode;
-
             Instruction = inst;
+            Address     = address;
+            RawOpCode   = opCode;
 
             RegisterSize = RegisterSize.Int64;
         }

+ 1 - 1
ARMeilleure/Decoders/OpCode32Alu.cs

@@ -5,7 +5,7 @@ namespace ARMeilleure.Decoders
         public int Rd { get; }
         public int Rn { get; }
 
-        public bool SetFlags { get; }
+        public bool? SetFlags { get; }
 
         public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Alu(inst, address, opCode);
 

+ 1 - 1
ARMeilleure/Decoders/OpCode32AluImm.cs

@@ -2,7 +2,7 @@ using ARMeilleure.Common;
 
 namespace ARMeilleure.Decoders
 {
-    class OpCode32AluImm : OpCode32Alu
+    class OpCode32AluImm : OpCode32Alu, IOpCode32AluImm
     {
         public int Immediate { get; }
 

+ 1 - 1
ARMeilleure/Decoders/OpCode32AluMla.cs

@@ -10,7 +10,7 @@
         public bool NHigh { get; }
         public bool MHigh { get; }
         public bool R { get; }
-        public bool SetFlags { get; }
+        public bool? SetFlags { get; }
 
         public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluMla(inst, address, opCode);
 

+ 1 - 1
ARMeilleure/Decoders/OpCode32AluRsImm.cs

@@ -1,6 +1,6 @@
 namespace ARMeilleure.Decoders
 {
-    class OpCode32AluRsImm : OpCode32Alu
+    class OpCode32AluRsImm : OpCode32Alu, IOpCode32AluRsImm
     {
         public int Rm        { get; }
         public int Immediate { get; }

+ 1 - 1
ARMeilleure/Decoders/OpCode32AluRsReg.cs

@@ -1,6 +1,6 @@
 namespace ARMeilleure.Decoders
 {
-    class OpCode32AluRsReg : OpCode32Alu
+    class OpCode32AluRsReg : OpCode32Alu, IOpCode32AluRsReg
     {
         public int Rm { get; }
         public int Rs { get; }

+ 1 - 1
ARMeilleure/Decoders/OpCode32AluUmull.cs

@@ -10,7 +10,7 @@
         public bool NHigh { get; }
         public bool MHigh { get; }
 
-        public bool SetFlags { get; }
+        public bool? SetFlags { get; }
         public DataOp DataOp { get; }
 
         public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluUmull(inst, address, opCode);

+ 1 - 1
ARMeilleure/Decoders/OpCode32Exception.cs

@@ -1,6 +1,6 @@
 namespace ARMeilleure.Decoders
 {
-    class OpCode32Exception : OpCode32
+    class OpCode32Exception : OpCode32, IOpCode32Exception
     {
         public int Id { get; }
 

+ 1 - 1
ARMeilleure/Decoders/OpCode32MemReg.cs

@@ -1,6 +1,6 @@
 namespace ARMeilleure.Decoders
 {
-    class OpCode32MemReg : OpCode32Mem
+    class OpCode32MemReg : OpCode32Mem, IOpCode32MemReg
     {
         public int Rm { get; }
 

+ 24 - 0
ARMeilleure/Decoders/OpCodeT16AddSubImm3.cs

@@ -0,0 +1,24 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16AddSubImm3: OpCodeT16, IOpCode32AluImm
+    {
+        public int Rd { get; }
+        public int Rn { get; }
+
+        public bool? SetFlags => null;
+
+        public int Immediate { get; }
+
+        public bool IsRotated { get; }
+
+        public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubImm3(inst, address, opCode);
+
+        public OpCodeT16AddSubImm3(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rd        = (opCode >> 0) & 0x7;
+            Rn        = (opCode >> 3) & 0x7;
+            Immediate = (opCode >> 6) & 0x7;
+            IsRotated = false;
+        }
+    }
+}

+ 20 - 0
ARMeilleure/Decoders/OpCodeT16AddSubReg.cs

@@ -0,0 +1,20 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16AddSubReg : OpCodeT16, IOpCode32AluReg
+    {
+        public int Rm { get; }
+        public int Rd { get; }
+        public int Rn { get; }
+
+        public bool? SetFlags => null;
+
+        public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubReg(inst, address, opCode);
+
+        public OpCodeT16AddSubReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rd = (opCode >> 0) & 0x7;
+            Rn = (opCode >> 3) & 0x7;
+            Rm = (opCode >> 6) & 0x7;
+        }
+    }
+}

+ 23 - 0
ARMeilleure/Decoders/OpCodeT16AddSubSp.cs

@@ -0,0 +1,23 @@
+using ARMeilleure.State;
+
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16AddSubSp : OpCodeT16, IOpCode32AluImm
+    {
+        public int Rd => RegisterAlias.Aarch32Sp;
+        public int Rn => RegisterAlias.Aarch32Sp;
+
+        public bool? SetFlags => false;
+
+        public int Immediate { get; }
+
+        public bool IsRotated => false;
+
+        public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubSp(inst, address, opCode);
+
+        public OpCodeT16AddSubSp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Immediate = ((opCode >> 0) & 0x7f) << 2;
+        }
+    }
+}

+ 20 - 0
ARMeilleure/Decoders/OpCodeT16Adr.cs

@@ -0,0 +1,20 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16Adr : OpCodeT16, IOpCode32Adr
+    {
+        public int Rd { get; }
+
+        public bool Add => true;
+        public int Immediate { get; }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Adr(inst, address, opCode);
+
+        public OpCodeT16Adr(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rd  = (opCode >> 8) & 7;
+
+            int imm = (opCode & 0xff) << 2;
+            Immediate = (int)(GetPc() & 0xfffffffc) + imm;
+        }
+    }
+}

+ 12 - 10
ARMeilleure/Decoders/OpCodeT16AluImm8.cs

@@ -1,22 +1,24 @@
-namespace ARMeilleure.Decoders
+namespace ARMeilleure.Decoders
 {
-    class OpCodeT16AluImm8 : OpCodeT16, IOpCode32Alu
+    class OpCodeT16AluImm8 : OpCodeT16, IOpCode32AluImm
     {
-        private int _rdn;
+        public int Rd { get; }
+        public int Rn { get; }
 
-        public int Rd => _rdn;
-        public int Rn => _rdn;
-
-        public bool SetFlags => false;
+        public bool? SetFlags => null;
 
         public int Immediate { get; }
 
-        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImm8(inst, address, opCode);
+        public bool IsRotated { get; }
+
+        public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImm8(inst, address, opCode);
 
         public OpCodeT16AluImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
         {
+            Rd = (opCode >> 8) & 0x7;
+            Rn = (opCode >> 8) & 0x7;
             Immediate = (opCode >> 0) & 0xff;
-            _rdn      = (opCode >> 8) & 0x7;
+            IsRotated = false;
         }
     }
-}
+}

+ 24 - 0
ARMeilleure/Decoders/OpCodeT16AluImmZero.cs

@@ -0,0 +1,24 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16AluImmZero : OpCodeT16, IOpCode32AluImm
+    {
+        public int Rd { get; }
+        public int Rn { get; }
+
+        public bool? SetFlags => null;
+
+        public int Immediate { get; }
+
+        public bool IsRotated { get; }
+
+        public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImmZero(inst, address, opCode);
+
+        public OpCodeT16AluImmZero(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rd = (opCode >> 0) & 0x7;
+            Rn = (opCode >> 3) & 0x7;
+            Immediate = 0;
+            IsRotated = false;
+        }
+    }
+}

+ 20 - 0
ARMeilleure/Decoders/OpCodeT16AluRegHigh.cs

@@ -0,0 +1,20 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16AluRegHigh : OpCodeT16, IOpCode32AluReg
+    {
+        public int Rm { get; }
+        public int Rd { get; }
+        public int Rn { get; }
+
+        public bool? SetFlags => false;
+
+        public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluRegHigh(inst, address, opCode);
+
+        public OpCodeT16AluRegHigh(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rd = ((opCode >> 0) & 0x7) | ((opCode >> 4) & 0x8);
+            Rn = ((opCode >> 0) & 0x7) | ((opCode >> 4) & 0x8);
+            Rm = (opCode >> 3) & 0xf;
+        }
+    }
+}

+ 20 - 0
ARMeilleure/Decoders/OpCodeT16AluRegLow.cs

@@ -0,0 +1,20 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16AluRegLow : OpCodeT16, IOpCode32AluReg
+    {
+        public int Rm { get; }
+        public int Rd { get; }
+        public int Rn { get; }
+
+        public bool? SetFlags => null;
+
+        public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluRegLow(inst, address, opCode);
+
+        public OpCodeT16AluRegLow(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rd = (opCode >> 0) & 0x7;
+            Rn = (opCode >> 0) & 0x7;
+            Rm = (opCode >> 3) & 0x7;
+        }
+    }
+}

+ 22 - 0
ARMeilleure/Decoders/OpCodeT16AluUx.cs

@@ -0,0 +1,22 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16AluUx : OpCodeT16, IOpCode32AluUx
+    {
+        public int Rm { get; }
+        public int Rd { get; }
+        public int Rn { get; }
+
+        public bool? SetFlags => false;
+
+        public int RotateBits => 0;
+        public bool Add => false;
+
+        public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluUx(inst, address, opCode);
+
+        public OpCodeT16AluUx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rd = (opCode >> 0) & 0x7;
+            Rm = (opCode >> 3) & 0x7;
+        }
+    }
+}

+ 15 - 0
ARMeilleure/Decoders/OpCodeT16BImm11.cs

@@ -0,0 +1,15 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16BImm11 : OpCode32, IOpCode32BImm
+    {
+        public long Immediate { get; }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImm11(inst, address, opCode);
+
+        public OpCodeT16BImm11(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            int imm = (opCode << 21) >> 20; 
+            Immediate = GetPc() + imm;
+        }
+    }
+}

+ 17 - 0
ARMeilleure/Decoders/OpCodeT16BImm8.cs

@@ -0,0 +1,17 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16BImm8 : OpCode32, IOpCode32BImm
+    {
+        public long Immediate { get; }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImm8(inst, address, opCode);
+
+        public OpCodeT16BImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Cond = (Condition)((opCode >> 8) & 0xf);
+
+            int imm = (opCode << 24) >> 23; 
+            Immediate = GetPc() + imm;
+        }
+    }
+}

+ 19 - 0
ARMeilleure/Decoders/OpCodeT16BImmCmp.cs

@@ -0,0 +1,19 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16BImmCmp : OpCodeT16
+    {
+        public int Rn { get; }
+
+        public int Immediate { get; }
+
+        public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImmCmp(inst, address, opCode);
+
+        public OpCodeT16BImmCmp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rn = (opCode >> 0) & 0x7;
+
+            int imm = ((opCode >> 2) & 0x3e) | ((opCode >> 3) & 0x40);
+            Immediate = (int)GetPc() + imm;
+        }
+    }
+}

+ 2 - 2
ARMeilleure/Decoders/OpCodeT16BReg.cs

@@ -1,4 +1,4 @@
-namespace ARMeilleure.Decoders
+namespace ARMeilleure.Decoders
 {
     class OpCodeT16BReg : OpCodeT16, IOpCode32BReg
     {
@@ -11,4 +11,4 @@ namespace ARMeilleure.Decoders
             Rm = (opCode >> 3) & 0xf;
         }
     }
-}
+}

+ 14 - 0
ARMeilleure/Decoders/OpCodeT16Exception.cs

@@ -0,0 +1,14 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16Exception : OpCodeT16, IOpCode32Exception
+    {
+        public int Id { get; }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Exception(inst, address, opCode);
+
+        public OpCodeT16Exception(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Id = opCode & 0xFF;
+        }
+    }
+}

+ 34 - 0
ARMeilleure/Decoders/OpCodeT16IfThen.cs

@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+using System.Reflection.Emit;
+
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16IfThen : OpCodeT16
+    {
+        public Condition[] IfThenBlockConds { get; }
+
+        public int IfThenBlockSize { get { return IfThenBlockConds.Length; } }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16IfThen(inst, address, opCode);
+
+        public OpCodeT16IfThen(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            List<Condition> conds = new();
+
+            int cond = (opCode >> 4) & 0xf;
+            int mask = opCode & 0xf;
+
+            conds.Add((Condition)cond);
+
+            while ((mask & 7) != 0)
+            {
+                int newLsb = (mask >> 3) & 1;
+                cond = (cond & 0xe) | newLsb;
+                mask <<= 1;
+                conds.Add((Condition)cond);
+            }
+
+            IfThenBlockConds = conds.ToArray();
+        }
+    }
+}

+ 58 - 0
ARMeilleure/Decoders/OpCodeT16MemImm5.cs

@@ -0,0 +1,58 @@
+using ARMeilleure.Instructions;
+using System;
+
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16MemImm5 : OpCodeT16, IOpCode32Mem
+    {
+        public int Rt { get; }
+        public int Rn { get; }
+
+        public bool WBack => false;
+        public bool IsLoad { get; }
+        public bool Index => true;
+        public bool Add => true;
+
+        public int Immediate { get; }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemImm5(inst, address, opCode);
+
+        public OpCodeT16MemImm5(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rt = (opCode >> 0) & 7;
+            Rn = (opCode >> 3) & 7;
+
+            switch (inst.Name)
+            {
+                case InstName.Ldr:
+                case InstName.Ldrb:
+                case InstName.Ldrh:
+                    IsLoad = true;
+                    break;
+                case InstName.Str:
+                case InstName.Strb:
+                case InstName.Strh:
+                    IsLoad = false;
+                    break;
+            }
+
+            switch (inst.Name)
+            {
+                case InstName.Str:
+                case InstName.Ldr:
+                    Immediate = ((opCode >> 6) & 0x1f) << 2;
+                    break;
+                case InstName.Strb:
+                case InstName.Ldrb:
+                    Immediate = ((opCode >> 6) & 0x1f);
+                    break;
+                case InstName.Strh:
+                case InstName.Ldrh:
+                    Immediate = ((opCode >> 6) & 0x1f) << 1;
+                    break;
+                default:
+                    throw new InvalidOperationException();
+            }
+        }
+    }
+}

+ 26 - 0
ARMeilleure/Decoders/OpCodeT16MemLit.cs

@@ -0,0 +1,26 @@
+using ARMeilleure.State;
+
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16MemLit : OpCodeT16, IOpCode32Mem
+    {
+        public int Rt { get; }
+        public int Rn => RegisterAlias.Aarch32Pc;
+
+        public bool WBack => false;
+        public bool IsLoad => true;
+        public bool Index => true;
+        public bool Add => true;
+
+        public int Immediate { get; }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemLit(inst, address, opCode);
+
+        public OpCodeT16MemLit(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rt = (opCode >> 8) & 7;
+
+            Immediate = (opCode & 0xff) << 2;
+        }
+    }
+}

+ 34 - 0
ARMeilleure/Decoders/OpCodeT16MemMult.cs

@@ -0,0 +1,34 @@
+using ARMeilleure.Instructions;
+using System;
+using System.Numerics;
+
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16MemMult : OpCodeT16, IOpCode32MemMult
+    {
+        public int Rn { get; }
+        public int RegisterMask { get; }
+        public int PostOffset { get; }
+        public bool IsLoad { get; }
+        public int Offset { get; }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemMult(inst, address, opCode);
+
+        public OpCodeT16MemMult(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            RegisterMask = opCode & 0xff;
+            Rn = (opCode >> 8) & 7;
+
+            int regCount = BitOperations.PopCount((uint)RegisterMask);
+
+            Offset = 0;
+            PostOffset = 4 * regCount;
+            IsLoad = inst.Name switch
+            {
+                InstName.Ldm => true,
+                InstName.Stm => false,
+                _ => throw new InvalidOperationException()
+            };
+        }
+    }
+}

+ 27 - 0
ARMeilleure/Decoders/OpCodeT16MemReg.cs

@@ -0,0 +1,27 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16MemReg : OpCodeT16, IOpCode32MemReg
+    {
+        public int Rm { get; }
+        public int Rt { get; }
+        public int Rn { get; }
+
+        public bool WBack => false;
+        public bool IsLoad { get; }
+        public bool Index => true;
+        public bool Add => true;
+
+        public int Immediate => throw new System.InvalidOperationException();
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemReg(inst, address, opCode);
+
+        public OpCodeT16MemReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rt = (opCode >> 0) & 7;
+            Rn = (opCode >> 3) & 7;
+            Rm = (opCode >> 6) & 7;
+
+            IsLoad = ((opCode >> 9) & 7) >= 3;
+        }
+    }
+}

+ 28 - 0
ARMeilleure/Decoders/OpCodeT16MemSp.cs

@@ -0,0 +1,28 @@
+using ARMeilleure.State;
+
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16MemSp : OpCodeT16, IOpCode32Mem
+    {
+        public int Rt { get; }
+        public int Rn => RegisterAlias.Aarch32Sp;
+
+        public bool WBack => false;
+        public bool IsLoad { get; }
+        public bool Index => true;
+        public bool Add => true;
+
+        public int Immediate { get; }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemSp(inst, address, opCode);
+
+        public OpCodeT16MemSp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rt = (opCode >> 8) & 7;
+
+            IsLoad = ((opCode >> 11) & 1) != 0;
+
+            Immediate = ((opCode >> 0) & 0xff) << 2;
+        }
+    }
+}

+ 42 - 0
ARMeilleure/Decoders/OpCodeT16MemStack.cs

@@ -0,0 +1,42 @@
+using ARMeilleure.Instructions;
+using ARMeilleure.State;
+using System;
+using System.Numerics;
+
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16MemStack : OpCodeT16, IOpCode32MemMult
+    {
+        public int Rn => RegisterAlias.Aarch32Sp;
+        public int RegisterMask { get; }
+        public int PostOffset { get; }
+        public bool IsLoad { get; }
+        public int Offset { get; }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemStack(inst, address, opCode);
+
+        public OpCodeT16MemStack(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            int extra = (opCode >> 8) & 1;
+            int regCount = BitOperations.PopCount((uint)opCode & 0x1ff);
+
+            switch (inst.Name)
+            {
+                case InstName.Push:
+                    RegisterMask = (opCode & 0xff) | (extra << 14);
+                    IsLoad = false;
+                    Offset = -4 * regCount;
+                    PostOffset = -4 * regCount;
+                    break;
+                case InstName.Pop:
+                    RegisterMask = (opCode & 0xff) | (extra << 15);
+                    IsLoad = true;
+                    Offset = 0;
+                    PostOffset = 4 * regCount;
+                    break;
+                default:
+                    throw new InvalidOperationException();
+            }
+        }
+    }
+}

+ 24 - 0
ARMeilleure/Decoders/OpCodeT16ShiftImm.cs

@@ -0,0 +1,24 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16ShiftImm : OpCodeT16, IOpCode32AluRsImm
+    {
+        public int Rd { get; }
+        public int Rn { get; }
+        public int Rm { get; }
+
+        public int Immediate { get; }
+        public ShiftType ShiftType { get; }
+
+        public bool? SetFlags => null;
+
+        public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16ShiftImm(inst, address, opCode);
+
+        public OpCodeT16ShiftImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rd        = (opCode >> 0) & 0x7;
+            Rm        = (opCode >> 3) & 0x7;
+            Immediate = (opCode >> 6) & 0x1F;
+            ShiftType = (ShiftType)((opCode >> 11) & 3);
+        }
+    }
+}

+ 27 - 0
ARMeilleure/Decoders/OpCodeT16ShiftReg.cs

@@ -0,0 +1,27 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16ShiftReg : OpCodeT16, IOpCode32AluRsReg
+    {
+        public int Rm { get; }
+        public int Rs { get; }
+        public int Rd { get; }
+
+        public int Rn { get; }
+
+        public ShiftType ShiftType { get; }
+
+        public bool? SetFlags => null;
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16ShiftReg(inst, address, opCode);
+
+        public OpCodeT16ShiftReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rd = (opCode >> 0) & 7;
+            Rm = (opCode >> 0) & 7;
+            Rn = (opCode >> 3) & 7;
+            Rs = (opCode >> 3) & 7;
+
+            ShiftType = (ShiftType)(((opCode >> 6) & 1) | ((opCode >> 7) & 2));
+        }
+    }
+}

+ 24 - 0
ARMeilleure/Decoders/OpCodeT16SpRel.cs

@@ -0,0 +1,24 @@
+using ARMeilleure.State;
+
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT16SpRel : OpCodeT16, IOpCode32AluImm
+    {
+        public int Rd { get; }
+        public int Rn => RegisterAlias.Aarch32Sp;
+
+        public bool? SetFlags => false;
+
+        public int Immediate { get; }
+
+        public bool IsRotated => false;
+
+        public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16SpRel(inst, address, opCode);
+
+        public OpCodeT16SpRel(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rd = (opCode >> 8) & 0x7;
+            Immediate = ((opCode >> 0) & 0xff) << 2;
+        }
+    }
+}

+ 103 - 31
ARMeilleure/Decoders/OpCodeTable.cs

@@ -1,5 +1,4 @@
 using ARMeilleure.Instructions;
-using ARMeilleure.State;
 using System;
 using System.Collections.Generic;
 
@@ -29,9 +28,9 @@ namespace ARMeilleure.Decoders
             }
         }
 
-        private static List<InstInfo> AllInstA32 = new List<InstInfo>();
-        private static List<InstInfo> AllInstT32 = new List<InstInfo>();
-        private static List<InstInfo> AllInstA64 = new List<InstInfo>();
+        private static List<InstInfo> AllInstA32 = new();
+        private static List<InstInfo> AllInstT32 = new();
+        private static List<InstInfo> AllInstA64 = new();
 
         private static InstInfo[][] InstA32FastLookup = new InstInfo[FastLookupSize][];
         private static InstInfo[][] InstT32FastLookup = new InstInfo[FastLookupSize][];
@@ -628,7 +627,7 @@ namespace ARMeilleure.Decoders
             SetA64("0>001110<<0xxxxx011110xxxxxxxxxx", InstName.Zip2_V,          InstEmit.Zip2_V,          OpCodeSimdReg.Create);
 #endregion
 
-#region "OpCode Table (AArch32)"
+#region "OpCode Table (AArch32, A32)"
             // Base
             SetA32("<<<<0010101xxxxxxxxxxxxxxxxxxxxx", InstName.Adc,     InstEmit32.Adc,     OpCode32AluImm.Create);
             SetA32("<<<<0000101xxxxxxxxxxxxxxxx0xxxx", InstName.Adc,     InstEmit32.Adc,     OpCode32AluRsImm.Create);
@@ -649,7 +648,6 @@ namespace ARMeilleure.Decoders
             SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Blx,     InstEmit32.Blx,     OpCode32BImm.Create);
             SetA32("<<<<000100101111111111110011xxxx", InstName.Blx,     InstEmit32.Blxr,    OpCode32BReg.Create);
             SetA32("<<<<000100101111111111110001xxxx", InstName.Bx,      InstEmit32.Bx,      OpCode32BReg.Create);
-            SetT32("xxxxxxxxxxxxxxxx010001110xxxx000", InstName.Bx,      InstEmit32.Bx,      OpCodeT16BReg.Create);
             SetA32("11110101011111111111000000011111", InstName.Clrex,   InstEmit32.Clrex,   OpCode32.Create);
             SetA32("<<<<000101101111xxxx11110001xxxx", InstName.Clz,     InstEmit32.Clz,     OpCode32AluReg.Create);
             SetA32("<<<<00110111xxxx0000xxxxxxxxxxxx", InstName.Cmn,     InstEmit32.Cmn,     OpCode32AluImm.Create);
@@ -702,7 +700,6 @@ namespace ARMeilleure.Decoders
             SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov,     InstEmit32.Mov,     OpCode32AluRsImm.Create);
             SetA32("<<<<0001101x0000xxxxxxxx0xx1xxxx", InstName.Mov,     InstEmit32.Mov,     OpCode32AluRsReg.Create);
             SetA32("<<<<00110000xxxxxxxxxxxxxxxxxxxx", InstName.Mov,     InstEmit32.Mov,     OpCode32AluImm16.Create);
-            SetT32("xxxxxxxxxxxxxxxx00100xxxxxxxxxxx", InstName.Mov,     InstEmit32.Mov,     OpCodeT16AluImm8.Create);
             SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt,    InstEmit32.Movt,    OpCode32AluImm16.Create);
             SetA32("<<<<1110xxx1xxxxxxxx111xxxx1xxxx", InstName.Mrc,     InstEmit32.Mrc,     OpCode32System.Create);
             SetA32("<<<<11000101xxxxxxxx111xxxxxxxxx", InstName.Mrrc,    InstEmit32.Mrrc,    OpCode32System.Create);
@@ -975,12 +972,85 @@ namespace ARMeilleure.Decoders
             SetA32("111100111x11<<10xxxx00011xx0xxxx", InstName.Vzip,     InstEmit32.Vzip,     OpCode32SimdCmpZ.Create);
 #endregion
 
-            FillFastLookupTable(InstA32FastLookup, AllInstA32);
-            FillFastLookupTable(InstT32FastLookup, AllInstT32);
-            FillFastLookupTable(InstA64FastLookup, AllInstA64);
+#region "OpCode Table (AArch32, T16/T32)"
+            // T16
+            SetT16("000<<xxxxxxxxxxx", InstName.Mov,    InstEmit32.Mov,     OpCodeT16ShiftImm.Create);
+            SetT16("0001100xxxxxxxxx", InstName.Add,    InstEmit32.Add,     OpCodeT16AddSubReg.Create);
+            SetT16("0001101xxxxxxxxx", InstName.Sub,    InstEmit32.Sub,     OpCodeT16AddSubReg.Create);
+            SetT16("0001110xxxxxxxxx", InstName.Add,    InstEmit32.Add,     OpCodeT16AddSubImm3.Create);
+            SetT16("0001111xxxxxxxxx", InstName.Sub,    InstEmit32.Sub,     OpCodeT16AddSubImm3.Create);
+            SetT16("00100xxxxxxxxxxx", InstName.Mov,    InstEmit32.Mov,     OpCodeT16AluImm8.Create);
+            SetT16("00101xxxxxxxxxxx", InstName.Cmp,    InstEmit32.Cmp,     OpCodeT16AluImm8.Create);
+            SetT16("00110xxxxxxxxxxx", InstName.Add,    InstEmit32.Add,     OpCodeT16AluImm8.Create);
+            SetT16("00111xxxxxxxxxxx", InstName.Sub,    InstEmit32.Sub,     OpCodeT16AluImm8.Create);
+            SetT16("0100000000xxxxxx", InstName.And,    InstEmit32.And,     OpCodeT16AluRegLow.Create);
+            SetT16("0100000001xxxxxx", InstName.Eor,    InstEmit32.Eor,     OpCodeT16AluRegLow.Create);
+            SetT16("0100000010xxxxxx", InstName.Mov,    InstEmit32.Mov,     OpCodeT16ShiftReg.Create);
+            SetT16("0100000011xxxxxx", InstName.Mov,    InstEmit32.Mov,     OpCodeT16ShiftReg.Create);
+            SetT16("0100000100xxxxxx", InstName.Mov,    InstEmit32.Mov,     OpCodeT16ShiftReg.Create);
+            SetT16("0100000101xxxxxx", InstName.Adc,    InstEmit32.Adc,     OpCodeT16AluRegLow.Create);
+            SetT16("0100000110xxxxxx", InstName.Sbc,    InstEmit32.Sbc,     OpCodeT16AluRegLow.Create);
+            SetT16("0100000111xxxxxx", InstName.Mov,    InstEmit32.Mov,     OpCodeT16ShiftReg.Create);
+            SetT16("0100001000xxxxxx", InstName.Tst,    InstEmit32.Tst,     OpCodeT16AluRegLow.Create);
+            SetT16("0100001001xxxxxx", InstName.Rsb,    InstEmit32.Rsb,     OpCodeT16AluImmZero.Create);
+            SetT16("0100001010xxxxxx", InstName.Cmp,    InstEmit32.Cmp,     OpCodeT16AluRegLow.Create);
+            SetT16("0100001011xxxxxx", InstName.Cmn,    InstEmit32.Cmn,     OpCodeT16AluRegLow.Create);
+            SetT16("0100001100xxxxxx", InstName.Orr,    InstEmit32.Orr,     OpCodeT16AluRegLow.Create);
+            SetT16("0100001101xxxxxx", InstName.Mul,    InstEmit32.Mul,     OpCodeT16AluRegLow.Create);
+            SetT16("0100001110xxxxxx", InstName.Bic,    InstEmit32.Bic,     OpCodeT16AluRegLow.Create);
+            SetT16("0100001111xxxxxx", InstName.Mvn,    InstEmit32.Mvn,     OpCodeT16AluRegLow.Create);
+            SetT16("01000100xxxxxxxx", InstName.Add,    InstEmit32.Add,     OpCodeT16AluRegHigh.Create);
+            SetT16("01000101xxxxxxxx", InstName.Cmp,    InstEmit32.Cmp,     OpCodeT16AluRegHigh.Create);
+            SetT16("01000110xxxxxxxx", InstName.Mov,    InstEmit32.Mov,     OpCodeT16AluRegHigh.Create);
+            SetT16("010001110xxxx000", InstName.Bx,     InstEmit32.Bx,      OpCodeT16BReg.Create);
+            SetT16("010001111xxxx000", InstName.Blx,    InstEmit32.Blx,     OpCodeT16BReg.Create);
+            SetT16("01001xxxxxxxxxxx", InstName.Ldr,    InstEmit32.Ldr,     OpCodeT16MemLit.Create);
+            SetT16("0101000xxxxxxxxx", InstName.Str,    InstEmit32.Str,     OpCodeT16MemReg.Create);
+            SetT16("0101001xxxxxxxxx", InstName.Strh,   InstEmit32.Strh,    OpCodeT16MemReg.Create);
+            SetT16("0101010xxxxxxxxx", InstName.Strb,   InstEmit32.Strb,    OpCodeT16MemReg.Create);
+            SetT16("0101011xxxxxxxxx", InstName.Ldrsb,  InstEmit32.Ldrsb,   OpCodeT16MemReg.Create);
+            SetT16("0101100xxxxxxxxx", InstName.Ldr,    InstEmit32.Ldr,     OpCodeT16MemReg.Create);
+            SetT16("0101101xxxxxxxxx", InstName.Ldrh,   InstEmit32.Ldrh,    OpCodeT16MemReg.Create);
+            SetT16("0101110xxxxxxxxx", InstName.Ldrb,   InstEmit32.Ldrb,    OpCodeT16MemReg.Create);
+            SetT16("0101111xxxxxxxxx", InstName.Ldrsh,  InstEmit32.Ldrsh,   OpCodeT16MemReg.Create);
+            SetT16("01100xxxxxxxxxxx", InstName.Str,    InstEmit32.Str,     OpCodeT16MemImm5.Create);
+            SetT16("01101xxxxxxxxxxx", InstName.Ldr,    InstEmit32.Ldr,     OpCodeT16MemImm5.Create);
+            SetT16("01110xxxxxxxxxxx", InstName.Strb,   InstEmit32.Strb,    OpCodeT16MemImm5.Create);
+            SetT16("01111xxxxxxxxxxx", InstName.Ldrb,   InstEmit32.Ldrb,    OpCodeT16MemImm5.Create);
+            SetT16("10000xxxxxxxxxxx", InstName.Strh,   InstEmit32.Strh,    OpCodeT16MemImm5.Create);
+            SetT16("10001xxxxxxxxxxx", InstName.Ldrh,   InstEmit32.Ldrh,    OpCodeT16MemImm5.Create);
+            SetT16("10010xxxxxxxxxxx", InstName.Str,    InstEmit32.Str,     OpCodeT16MemSp.Create);
+            SetT16("10011xxxxxxxxxxx", InstName.Ldr,    InstEmit32.Ldr,     OpCodeT16MemSp.Create);
+            SetT16("10100xxxxxxxxxxx", InstName.Adr,    InstEmit32.Adr,     OpCodeT16Adr.Create);
+            SetT16("10101xxxxxxxxxxx", InstName.Add,    InstEmit32.Add,     OpCodeT16SpRel.Create);
+            SetT16("101100000xxxxxxx", InstName.Add,    InstEmit32.Add,     OpCodeT16AddSubSp.Create);
+            SetT16("101100001xxxxxxx", InstName.Sub,    InstEmit32.Sub,     OpCodeT16AddSubSp.Create);
+            SetT16("1011001000xxxxxx", InstName.Sxth,   InstEmit32.Sxth,    OpCodeT16AluUx.Create);
+            SetT16("1011001001xxxxxx", InstName.Sxtb,   InstEmit32.Sxtb,    OpCodeT16AluUx.Create);
+            SetT16("1011001010xxxxxx", InstName.Uxth,   InstEmit32.Uxth,    OpCodeT16AluUx.Create);
+            SetT16("1011001011xxxxxx", InstName.Uxtb,   InstEmit32.Uxtb,    OpCodeT16AluUx.Create);
+            SetT16("101100x1xxxxxxxx", InstName.Cbz,    InstEmit32.Cbz,     OpCodeT16BImmCmp.Create);
+            SetT16("1011010xxxxxxxxx", InstName.Push,   InstEmit32.Stm,     OpCodeT16MemStack.Create);
+            SetT16("1011101000xxxxxx", InstName.Rev,    InstEmit32.Rev,     OpCodeT16AluRegLow.Create);
+            SetT16("1011101001xxxxxx", InstName.Rev16,  InstEmit32.Rev16,   OpCodeT16AluRegLow.Create);
+            SetT16("1011101011xxxxxx", InstName.Revsh,  InstEmit32.Revsh,   OpCodeT16AluRegLow.Create);
+            SetT16("101110x1xxxxxxxx", InstName.Cbnz,   InstEmit32.Cbnz,    OpCodeT16BImmCmp.Create);
+            SetT16("1011110xxxxxxxxx", InstName.Pop,    InstEmit32.Ldm,     OpCodeT16MemStack.Create);
+            SetT16("10111111xxxx0000", InstName.Nop,    InstEmit32.Nop,     OpCodeT16.Create);
+            SetT16("10111111xxxx>>>>", InstName.It,     InstEmit32.It,      OpCodeT16IfThen.Create);
+            SetT16("11000xxxxxxxxxxx", InstName.Stm,    InstEmit32.Stm,     OpCodeT16MemMult.Create);
+            SetT16("11001xxxxxxxxxxx", InstName.Ldm,    InstEmit32.Ldm,     OpCodeT16MemMult.Create);
+            SetT16("1101<<<xxxxxxxxx", InstName.B,      InstEmit32.B,       OpCodeT16BImm8.Create);
+            SetT16("11011111xxxxxxxx", InstName.Svc,    InstEmit32.Svc,     OpCodeT16Exception.Create);
+            SetT16("11100xxxxxxxxxxx", InstName.B,      InstEmit32.B,       OpCodeT16BImm11.Create);
+#endregion
+
+            FillFastLookupTable(InstA32FastLookup, AllInstA32, ToFastLookupIndexA);
+            FillFastLookupTable(InstT32FastLookup, AllInstT32, ToFastLookupIndexT);
+            FillFastLookupTable(InstA64FastLookup, AllInstA64, ToFastLookupIndexA);
         }
 
-        private static void FillFastLookupTable(InstInfo[][] table, List<InstInfo> allInsts)
+        private static void FillFastLookupTable(InstInfo[][] table, List<InstInfo> allInsts, Func<int, int> ToFastLookupIndex)
         {
             List<InstInfo>[] temp = new List<InstInfo>[FastLookupSize];
 
@@ -1011,20 +1081,27 @@ namespace ARMeilleure.Decoders
 
         private static void SetA32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
         {
-            Set(encoding, ExecutionMode.Aarch32Arm, new InstDescriptor(name, emitter), makeOp);
+            Set(encoding, AllInstA32, new InstDescriptor(name, emitter), makeOp);
+        }
+
+        private static void SetT16(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
+        {
+            encoding = "xxxxxxxxxxxxxxxx" + encoding;
+            Set(encoding, AllInstT32, new InstDescriptor(name, emitter), makeOp);
         }
 
         private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
         {
-            Set(encoding, ExecutionMode.Aarch32Thumb, new InstDescriptor(name, emitter), makeOp);
+            encoding = encoding.Substring(16) + encoding.Substring(0, 16);
+            Set(encoding, AllInstT32, new InstDescriptor(name, emitter), makeOp);
         }
 
         private static void SetA64(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
         {
-            Set(encoding, ExecutionMode.Aarch64, new InstDescriptor(name, emitter), makeOp);
+            Set(encoding, AllInstA64, new InstDescriptor(name, emitter), makeOp);
         }
 
-        private static void Set(string encoding, ExecutionMode mode, InstDescriptor inst, MakeOp makeOp)
+        private static void Set(string encoding, List<InstInfo> list, InstDescriptor inst, MakeOp makeOp)
         {
             int bit   = encoding.Length - 1;
             int value = 0;
@@ -1073,7 +1150,7 @@ namespace ARMeilleure.Decoders
 
             if (xBits == 0)
             {
-                InsertInst(new InstInfo(xMask, value, inst, makeOp), mode);
+                list.Add(new InstInfo(xMask, value, inst, makeOp));
 
                 return;
             }
@@ -1089,34 +1166,24 @@ namespace ARMeilleure.Decoders
 
                 if (mask != blacklisted)
                 {
-                    InsertInst(new InstInfo(xMask, value | mask, inst, makeOp), mode);
+                    list.Add(new InstInfo(xMask, value | mask, inst, makeOp));
                 }
             }
         }
 
-        private static void InsertInst(InstInfo info, ExecutionMode mode)
-        {
-            switch (mode)
-            {
-                case ExecutionMode.Aarch32Arm:   AllInstA32.Add(info); break;
-                case ExecutionMode.Aarch32Thumb: AllInstT32.Add(info); break;
-                case ExecutionMode.Aarch64:      AllInstA64.Add(info); break;
-            }
-        }
-
         public static (InstDescriptor inst, MakeOp makeOp) GetInstA32(int opCode)
         {
-            return GetInstFromList(InstA32FastLookup[ToFastLookupIndex(opCode)], opCode);
+            return GetInstFromList(InstA32FastLookup[ToFastLookupIndexA(opCode)], opCode);
         }
 
         public static (InstDescriptor inst, MakeOp makeOp) GetInstT32(int opCode)
         {
-            return GetInstFromList(InstT32FastLookup[ToFastLookupIndex(opCode)], opCode);
+            return GetInstFromList(InstT32FastLookup[ToFastLookupIndexT(opCode)], opCode);
         }
 
         public static (InstDescriptor inst, MakeOp makeOp) GetInstA64(int opCode)
         {
-            return GetInstFromList(InstA64FastLookup[ToFastLookupIndex(opCode)], opCode);
+            return GetInstFromList(InstA64FastLookup[ToFastLookupIndexA(opCode)], opCode);
         }
 
         private static (InstDescriptor inst, MakeOp makeOp) GetInstFromList(InstInfo[] insts, int opCode)
@@ -1132,9 +1199,14 @@ namespace ARMeilleure.Decoders
             return (new InstDescriptor(InstName.Und, InstEmit.Und), null);
         }
 
-        private static int ToFastLookupIndex(int value)
+        private static int ToFastLookupIndexA(int value)
         {
             return ((value >> 10) & 0x00F) | ((value >> 18) & 0xFF0);
         }
+
+        private static int ToFastLookupIndexT(int value)
+        {
+            return (value >> 4) & 0xFFF;
+        }
     }
 }

+ 14 - 14
ARMeilleure/Instructions/InstEmitAlu32.cs

@@ -20,7 +20,7 @@ namespace ARMeilleure.Instructions
 
             Operand res = context.Add(n, m);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
 
@@ -44,7 +44,7 @@ namespace ARMeilleure.Instructions
 
             res = context.Add(res, carry);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
 
@@ -64,7 +64,7 @@ namespace ARMeilleure.Instructions
 
             Operand res = context.BitwiseAnd(n, m);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
             }
@@ -110,7 +110,7 @@ namespace ARMeilleure.Instructions
 
             Operand res = context.BitwiseAnd(n, context.BitwiseNot(m));
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
             }
@@ -161,7 +161,7 @@ namespace ARMeilleure.Instructions
 
             Operand res = context.BitwiseExclusiveOr(n, m);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
             }
@@ -175,7 +175,7 @@ namespace ARMeilleure.Instructions
 
             Operand m = GetAluM(context);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, m);
             }
@@ -204,7 +204,7 @@ namespace ARMeilleure.Instructions
 
             Operand res = context.Multiply(n, m);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
             }
@@ -219,7 +219,7 @@ namespace ARMeilleure.Instructions
 
             Operand res = context.BitwiseNot(m);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
             }
@@ -236,7 +236,7 @@ namespace ARMeilleure.Instructions
 
             Operand res = context.BitwiseOr(n, m);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
             }
@@ -315,7 +315,7 @@ namespace ARMeilleure.Instructions
 
             res = context.Subtract(res, borrow);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
 
@@ -335,7 +335,7 @@ namespace ARMeilleure.Instructions
 
             Operand res = context.Subtract(m, n);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
 
@@ -359,7 +359,7 @@ namespace ARMeilleure.Instructions
 
             res = context.Subtract(res, borrow);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
 
@@ -420,7 +420,7 @@ namespace ARMeilleure.Instructions
 
             Operand res = context.Subtract(n, m);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
 
@@ -836,7 +836,7 @@ namespace ARMeilleure.Instructions
         {
             IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
 
-            EmitGenericAluStoreA32(context, op.Rd, op.SetFlags, value);
+            EmitGenericAluStoreA32(context, op.Rd, ShouldSetFlags(context), value);
         }
     }
 }

+ 20 - 10
ARMeilleure/Instructions/InstEmitAluHelper.cs

@@ -12,6 +12,18 @@ namespace ARMeilleure.Instructions
 {
     static class InstEmitAluHelper
     {
+        public static bool ShouldSetFlags(ArmEmitterContext context)
+        {
+            IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
+
+            if (op.SetFlags == null)
+            {
+                return !context.IsInIfThenBlock;
+            }
+
+            return op.SetFlags.Value;
+        }
+
         public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d)
         {
             SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0)));
@@ -183,9 +195,9 @@ namespace ARMeilleure.Instructions
             switch (context.CurrOp)
             {
                 // ARM32.
-                case OpCode32AluImm op:
+                case IOpCode32AluImm op:
                 {
-                    if (op.SetFlags && op.IsRotated)
+                    if (ShouldSetFlags(context) && op.IsRotated)
                     {
                         SetFlag(context, PState.CFlag, Const((uint)op.Immediate >> 31));
                     }
@@ -195,10 +207,8 @@ namespace ARMeilleure.Instructions
 
                 case OpCode32AluImm16 op: return Const(op.Immediate);
 
-                case OpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
-                case OpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
-
-                case OpCodeT16AluImm8 op: return Const(op.Immediate);
+                case IOpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
+                case IOpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
 
                 case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
 
@@ -249,7 +259,7 @@ namespace ARMeilleure.Instructions
         }
 
         // ARM32 helpers.
-        public static Operand GetMShiftedByImmediate(ArmEmitterContext context, OpCode32AluRsImm op, bool setCarry)
+        public static Operand GetMShiftedByImmediate(ArmEmitterContext context, IOpCode32AluRsImm op, bool setCarry)
         {
             Operand m = GetIntA32(context, op.Rm);
 
@@ -267,7 +277,7 @@ namespace ARMeilleure.Instructions
 
             if (shift != 0)
             {
-                setCarry &= op.SetFlags;
+                setCarry &= ShouldSetFlags(context);
 
                 switch (op.ShiftType)
                 {
@@ -305,7 +315,7 @@ namespace ARMeilleure.Instructions
             return shift;
         }
 
-        public static Operand GetMShiftedByReg(ArmEmitterContext context, OpCode32AluRsReg op, bool setCarry)
+        public static Operand GetMShiftedByReg(ArmEmitterContext context, IOpCode32AluRsReg op, bool setCarry)
         {
             Operand m = GetIntA32(context, op.Rm);
             Operand s = context.ZeroExtend8(OperandType.I32, GetIntA32(context, op.Rs));
@@ -314,7 +324,7 @@ namespace ARMeilleure.Instructions
             Operand zeroResult = m;
             Operand shiftResult = m;
 
-            setCarry &= op.SetFlags;
+            setCarry &= ShouldSetFlags(context);
 
             switch (op.ShiftType)
             {

+ 2 - 2
ARMeilleure/Instructions/InstEmitException32.cs

@@ -20,11 +20,11 @@ namespace ARMeilleure.Instructions
 
         private static void EmitExceptionCall(ArmEmitterContext context, string name)
         {
-            OpCode32Exception op = (OpCode32Exception)context.CurrOp;
+            IOpCode32Exception op = (IOpCode32Exception)context.CurrOp;
 
             context.StoreToContext();
 
-            context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
+            context.Call(typeof(NativeInterface).GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
 
             context.LoadFromContext();
 

+ 28 - 1
ARMeilleure/Instructions/InstEmitFlow32.cs

@@ -64,7 +64,7 @@ namespace ARMeilleure.Instructions
             bool isThumb = IsThumb(context.CurrOp);
 
             uint currentPc = isThumb
-                ? pc | 1
+                ? (pc - 2) | 1
                 : pc - 4;
 
             SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
@@ -80,5 +80,32 @@ namespace ARMeilleure.Instructions
 
             EmitBxWritePc(context, GetIntA32(context, op.Rm), op.Rm);
         }
+
+        public static void Cbnz(ArmEmitterContext context) => EmitCb(context, onNotZero: true);
+        public static void Cbz(ArmEmitterContext context)  => EmitCb(context, onNotZero: false);
+
+        private static void EmitCb(ArmEmitterContext context, bool onNotZero)
+        {
+            OpCodeT16BImmCmp op = (OpCodeT16BImmCmp)context.CurrOp;
+
+            Operand value = GetIntOrZR(context, op.Rn);
+            Operand lblTarget = context.GetLabel((ulong)op.Immediate);
+
+            if (onNotZero)
+            {
+                context.BranchIfTrue(lblTarget, value);
+            }
+            else
+            {
+                context.BranchIfFalse(lblTarget, value);
+            }
+        }
+
+        public static void It(ArmEmitterContext context)
+        {
+            OpCodeT16IfThen op = (OpCodeT16IfThen)context.CurrOp;
+
+            context.SetIfThenBlockState(op.IfThenBlockConds);
+        }
     }
 }

+ 9 - 3
ARMeilleure/Instructions/InstEmitMemory32.cs

@@ -32,7 +32,7 @@ namespace ARMeilleure.Instructions
 
         public static void Ldm(ArmEmitterContext context)
         {
-            OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
+            IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
 
             Operand n = GetIntA32(context, op.Rn);
 
@@ -95,7 +95,7 @@ namespace ARMeilleure.Instructions
 
         public static void Stm(ArmEmitterContext context)
         {
-            OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
+            IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
 
             Operand n = context.Copy(GetIntA32(context, op.Rn));
 
@@ -151,7 +151,7 @@ namespace ARMeilleure.Instructions
 
         private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType)
         {
-            OpCode32Mem op = (OpCode32Mem)context.CurrOp;
+            IOpCode32Mem op = (IOpCode32Mem)context.CurrOp;
 
             Operand n = context.Copy(GetIntA32AlignedPC(context, op.Rn));
             Operand m = GetMemM(context, setCarry: false);
@@ -255,5 +255,11 @@ namespace ARMeilleure.Instructions
                 }
             }
         }
+
+        public static void Adr(ArmEmitterContext context)
+        {
+            IOpCode32Adr op = (IOpCode32Adr)context.CurrOp;
+            SetIntA32(context, op.Rd, Const(op.Immediate));
+        }
     }
 }

+ 2 - 2
ARMeilleure/Instructions/InstEmitMemoryHelper.cs

@@ -549,9 +549,9 @@ namespace ARMeilleure.Instructions
             {
                 case OpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
 
-                case OpCode32MemReg op: return GetIntA32(context, op.Rm);
+                case IOpCode32MemReg op: return GetIntA32(context, op.Rm);
 
-                case OpCode32Mem op: return Const(op.Immediate);
+                case IOpCode32Mem op: return Const(op.Immediate);
 
                 case OpCode32SimdMemImm op: return Const(op.Immediate);
 

+ 10 - 10
ARMeilleure/Instructions/InstEmitMul32.cs

@@ -33,7 +33,7 @@ namespace ARMeilleure.Instructions
 
             Operand res = context.Add(a, context.Multiply(n, m));
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
             }
@@ -250,13 +250,13 @@ namespace ARMeilleure.Instructions
             Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
             Operand lo = context.ConvertI64ToI32(res);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
             }
 
-            EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
-            EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
+            EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
+            EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
         }
 
         public static void Smulw_(ArmEmitterContext context)
@@ -320,13 +320,13 @@ namespace ARMeilleure.Instructions
             Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
             Operand lo = context.ConvertI64ToI32(res);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
             }
 
-            EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
-            EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
+            EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
+            EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
         }
 
         private static void EmitMlal(ArmEmitterContext context, bool signed)
@@ -356,13 +356,13 @@ namespace ARMeilleure.Instructions
             Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
             Operand lo = context.ConvertI64ToI32(res);
 
-            if (op.SetFlags)
+            if (ShouldSetFlags(context))
             {
                 EmitNZFlagsCheck(context, res);
             }
 
-            EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
-            EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
+            EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
+            EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
         }
 
         private static void UpdateQFlag(ArmEmitterContext context, Operand q)

+ 3 - 0
ARMeilleure/Instructions/InstName.cs

@@ -48,6 +48,7 @@ namespace ARMeilleure.Instructions
         Extr,
         Hint,
         Isb,
+        It,
         Ldar,
         Ldaxp,
         Ldaxr,
@@ -512,6 +513,8 @@ namespace ARMeilleure.Instructions
         Mvn,
         Pkh,
         Pld,
+        Pop,
+        Push,
         Rev,
         Revsh,
         Rsb,

+ 19 - 0
ARMeilleure/Translation/ArmEmitterContext.cs

@@ -54,6 +54,11 @@ namespace ARMeilleure.Translation
         public bool HighCq { get; }
         public Aarch32Mode Mode { get; }
 
+        private int _ifThenBlockStateIndex = 0;
+        private Condition[] _ifThenBlockState = { };
+        public bool IsInIfThenBlock => _ifThenBlockStateIndex < _ifThenBlockState.Length;
+        public Condition CurrentIfThenBlockCond => _ifThenBlockState[_ifThenBlockStateIndex];
+
         public ArmEmitterContext(
             IMemoryManager memory,
             EntryTable<uint> countTable,
@@ -196,5 +201,19 @@ namespace ARMeilleure.Translation
 
             return default;
         }
+
+        public void SetIfThenBlockState(Condition[] state)
+        {
+            _ifThenBlockState = state;
+            _ifThenBlockStateIndex = 0;
+        }
+
+        public void AdvanceIfThenBlockState()
+        {
+            if (IsInIfThenBlock)
+            {
+                _ifThenBlockStateIndex++;
+            }
+        }
     }
 }

+ 12 - 0
ARMeilleure/Translation/Translator.cs

@@ -380,6 +380,13 @@ namespace ARMeilleure.Translation
 
                         Operand lblPredicateSkip = default;
 
+                        if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
+                        {
+                            lblPredicateSkip = Label();
+
+                            InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Invert());
+                        }
+
                         if (opCode is OpCode32 op && op.Cond < Condition.Al)
                         {
                             lblPredicateSkip = Label();
@@ -400,6 +407,11 @@ namespace ARMeilleure.Translation
                         {
                             context.MarkLabel(lblPredicateSkip);
                         }
+
+                        if (context.IsInIfThenBlock && opCode.Instruction.Name != InstName.It)
+                        {
+                            context.AdvanceIfThenBlockState();
+                        }
                     }
                 }
             }

+ 12 - 2
Ryujinx.Tests.Unicorn/UnicornAArch32.cs

@@ -41,8 +41,8 @@ namespace Ryujinx.Tests.Unicorn
 
         public uint PC
         {
-            get => GetRegister(Arm32Register.PC);
-            set => SetRegister(Arm32Register.PC, value);
+            get => GetRegister(Arm32Register.PC) & 0xfffffffeu;
+            set => SetRegister(Arm32Register.PC, (value & 0xfffffffeu) | (ThumbFlag ? 1u : 0u));
         }
 
         public uint CPSR
@@ -87,6 +87,16 @@ namespace Ryujinx.Tests.Unicorn
             set => CPSR = (CPSR & ~0x80000000u) | (value ? 0x80000000u : 0u);
         }
 
+        public bool ThumbFlag
+        {
+            get => (CPSR & 0x00000020u) != 0;
+            set
+            {
+                CPSR = (CPSR & ~0x00000020u) | (value ? 0x00000020u : 0u);
+                SetRegister(Arm32Register.PC, (GetRegister(Arm32Register.PC) & 0xfffffffeu) | (value ? 1u : 0u));
+            }
+        }
+
         public UnicornAArch32()
         {
             Interface.Checked(Interface.uc_open(UnicornArch.UC_ARCH_ARM, UnicornMode.UC_MODE_LITTLE_ENDIAN, out uc));

+ 40 - 1
Ryujinx.Tests/Cpu/CpuTest32.cs

@@ -106,6 +106,18 @@ namespace Ryujinx.Tests.Cpu
             _currAddress += 4;
         }
 
+        protected void ThumbOpcode(ushort opcode)
+        {
+            _memory.Write(_currAddress, opcode);
+
+            if (_unicornAvailable)
+            {
+                _unicornEmu.MemoryWrite16(_currAddress, opcode);
+            }
+
+            _currAddress += 2;
+        }
+
         protected ExecutionContext GetContext() => _context;
 
         protected void SetContext(uint r0 = 0,
@@ -126,7 +138,8 @@ namespace Ryujinx.Tests.Cpu
                                   bool carry = false,
                                   bool zero = false,
                                   bool negative = false,
-                                  int fpscr = 0)
+                                  int fpscr = 0,
+                                  bool thumb = false)
         {
             _context.SetX(0, r0);
             _context.SetX(1, r1);
@@ -151,6 +164,8 @@ namespace Ryujinx.Tests.Cpu
 
             SetFpscr((uint)fpscr);
 
+            _context.SetPstateFlag(PState.TFlag, thumb);
+
             if (_unicornAvailable)
             {
                 _unicornEmu.R[0] = r0;
@@ -175,6 +190,8 @@ namespace Ryujinx.Tests.Cpu
                 _unicornEmu.NegativeFlag = negative;
 
                 _unicornEmu.Fpscr = fpscr;
+
+                _unicornEmu.ThumbFlag = thumb;
             }
         }
 
@@ -218,6 +235,28 @@ namespace Ryujinx.Tests.Cpu
             return GetContext();
         }
 
+        protected ExecutionContext SingleThumbOpcode(ushort opcode,
+                                                     uint r0 = 0,
+                                                     uint r1 = 0,
+                                                     uint r2 = 0,
+                                                     uint r3 = 0,
+                                                     uint sp = 0,
+                                                     bool saturation = false,
+                                                     bool overflow = false,
+                                                     bool carry = false,
+                                                     bool zero = false,
+                                                     bool negative = false,
+                                                     int fpscr = 0,
+                                                     bool runUnicorn = true)
+        {
+            ThumbOpcode(opcode);
+            ThumbOpcode(0x4770); // BX LR
+            SetContext(r0, r1, r2, r3, sp, default, default, default, default, default, default, default, default, saturation, overflow, carry, zero, negative, fpscr, thumb: true);
+            ExecuteOpcodes(runUnicorn);
+
+            return GetContext();
+        }
+
         protected void SetWorkingMemory(uint offset, byte[] data)
         {
             _memory.Write(DataBaseAddress + offset, data);

Разница между файлами не показана из-за своего большого размера
+ 314 - 0
Ryujinx.Tests/Cpu/CpuTestThumb.cs


Некоторые файлы не были показаны из-за большого количества измененных файлов