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

Implement some 32-bit Thumb instructions (#3614)

* Implement some 32-bit Thumb instructions

* Optimize OpCode32MemMult using PopCount
gdkchan 3 лет назад
Родитель
Сommit
eba682b767

+ 8 - 0
ARMeilleure/Decoders/IOpCode32MemRsImm.cs

@@ -0,0 +1,8 @@
+namespace ARMeilleure.Decoders
+{
+    interface IOpCode32MemRsImm : IOpCode32Mem
+    {
+        int Rm { get; }
+        ShiftType ShiftType { get; }
+    }
+}

+ 3 - 8
ARMeilleure/Decoders/OpCode32MemMult.cs

@@ -1,3 +1,5 @@
+using System.Numerics;
+
 namespace ARMeilleure.Decoders
 {
     class OpCode32MemMult : OpCode32, IOpCode32MemMult
@@ -23,14 +25,7 @@ namespace ARMeilleure.Decoders
 
             RegisterMask = opCode & 0xffff;
 
-            int regsSize = 0;
-
-            for (int index = 0; index < 16; index++)
-            {
-                regsSize += (RegisterMask >> index) & 1;
-            }
-
-            regsSize *= 4;
+            int regsSize = BitOperations.PopCount((uint)RegisterMask) * 4;
 
             if (!u)
             {

+ 1 - 1
ARMeilleure/Decoders/OpCode32MemRsImm.cs

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

+ 2 - 2
ARMeilleure/Decoders/OpCodeT16BImmCmp.cs

@@ -1,10 +1,10 @@
 namespace ARMeilleure.Decoders
 {
-    class OpCodeT16BImmCmp : OpCodeT16
+    class OpCodeT16BImmCmp : OpCodeT16, IOpCode32BImm
     {
         public int Rn { get; }
 
-        public int Immediate { get; }
+        public long Immediate { get; }
 
         public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImmCmp(inst, address, opCode);
 

+ 31 - 0
ARMeilleure/Decoders/OpCodeT32MemImm8D.cs

@@ -0,0 +1,31 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT32MemImm8D : OpCodeT32, IOpCode32Mem
+    {
+        public int Rt { get; }
+        public int Rt2 { get; }
+        public int Rn { get; }
+        public bool WBack { get; }
+        public bool IsLoad { get; }
+        public bool Index { get; }
+        public bool Add { get; }
+        public int Immediate { get; }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MemImm8D(inst, address, opCode);
+
+        public OpCodeT32MemImm8D(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rt2 = (opCode >> 8) & 0xf;
+            Rt = (opCode >> 12) & 0xf;
+            Rn = (opCode >> 16) & 0xf;
+
+            Index = ((opCode >> 24) & 1) != 0;
+            Add   = ((opCode >> 23) & 1) != 0;
+            WBack = ((opCode >> 21) & 1) != 0;
+
+            Immediate = opCode & 0xff;
+
+            IsLoad = ((opCode >> 20) & 1) != 0;
+        }
+    }
+}

+ 24 - 0
ARMeilleure/Decoders/OpCodeT32MemLdEx.cs

@@ -0,0 +1,24 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT32MemLdEx : OpCodeT32, IOpCode32MemEx
+    {
+        public int Rd => 0;
+        public int Rt { get; }
+        public int Rn { get; }
+
+        public bool WBack => false;
+        public bool IsLoad => true;
+        public bool Index => false;
+        public bool Add => false;
+
+        public int Immediate => 0;
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MemLdEx(inst, address, opCode);
+
+        public OpCodeT32MemLdEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rt = (opCode >> 12) & 0xf;
+            Rn = (opCode >> 16) & 0xf;
+        }
+    }
+}

+ 52 - 0
ARMeilleure/Decoders/OpCodeT32MemMult.cs

@@ -0,0 +1,52 @@
+using System.Numerics;
+
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT32MemMult : OpCodeT32, IOpCode32MemMult
+    {
+        public int Rn { get; }
+
+        public int RegisterMask { get; }
+        public int Offset       { get; }
+        public int PostOffset   { get; }
+
+        public bool IsLoad { get; }
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MemMult(inst, address, opCode);
+
+        public OpCodeT32MemMult(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rn = (opCode >> 16) & 0xf;
+
+            bool isLoad = (opCode & (1 << 20)) != 0;
+            bool w      = (opCode & (1 << 21)) != 0;
+            bool u      = (opCode & (1 << 23)) != 0;
+            bool p      = (opCode & (1 << 24)) != 0;
+
+            RegisterMask = opCode & 0xffff;
+
+            int regsSize = BitOperations.PopCount((uint)RegisterMask) * 4;
+
+            if (!u)
+            {
+                Offset -= regsSize;
+            }
+
+            if (u == p)
+            {
+                Offset += 4;
+            }
+
+            if (w)
+            {
+                PostOffset = u ? regsSize : -regsSize;
+            }
+            else
+            {
+                PostOffset = 0;
+            }
+
+            IsLoad = isLoad;
+        }
+    }
+}

+ 30 - 0
ARMeilleure/Decoders/OpCodeT32MemRsImm.cs

@@ -0,0 +1,30 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT32MemRsImm : OpCodeT32, IOpCode32MemRsImm
+    {
+        public int Rt { get; }
+        public int Rn { get; }
+        public int Rm { get; }
+        public ShiftType ShiftType => ShiftType.Lsl;
+
+        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 OpCodeT32MemRsImm(inst, address, opCode);
+
+        public OpCodeT32MemRsImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rm = (opCode >> 0) & 0xf;
+            Rt = (opCode >> 12) & 0xf;
+            Rn = (opCode >> 16) & 0xf;
+
+            IsLoad = (opCode & (1 << 20)) != 0;
+
+            Immediate = (opCode >> 4) & 3;
+        }
+    }
+}

+ 25 - 0
ARMeilleure/Decoders/OpCodeT32MemStEx.cs

@@ -0,0 +1,25 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCodeT32MemStEx : OpCodeT32, IOpCode32MemEx
+    {
+        public int Rd { get; }
+        public int Rt { get; }
+        public int Rn { get; }
+
+        public bool WBack => false;
+        public bool IsLoad => false;
+        public bool Index => false;
+        public bool Add => false;
+
+        public int Immediate => 0;
+
+        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MemStEx(inst, address, opCode);
+
+        public OpCodeT32MemStEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Rd = (opCode >> 0) & 0xf;
+            Rt = (opCode >> 12) & 0xf;
+            Rn = (opCode >> 16) & 0xf;
+        }
+    }
+}

+ 10 - 0
ARMeilleure/Decoders/OpCodeTable.cs

@@ -1070,14 +1070,19 @@ namespace ARMeilleure.Decoders
             SetT32("11110x011011xxxx0xxx1111xxxxxxxx", InstName.Cmp,      InstEmit32.Cmp,      OpCodeT32AluImm.Create);
             SetT32("11101010100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor,      InstEmit32.Eor,      OpCodeT32AluRsImm.Create);
             SetT32("11110x00100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor,      InstEmit32.Eor,      OpCodeT32AluImm.Create);
+            SetT32("111010001101xxxxxxxx111111101111", InstName.Ldaex,    InstEmit32.Ldaex,    OpCodeT32MemLdEx.Create);
+            SetT32("1110100010x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm,      InstEmit32.Ldm,      OpCodeT32MemMult.Create);
+            SetT32("1110100100x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm,      InstEmit32.Ldm,      OpCodeT32MemMult.Create);
             SetT32("111110000101xxxx<<<<10x1xxxxxxxx", InstName.Ldr,      InstEmit32.Ldr,      OpCodeT32MemImm8.Create);
             SetT32("111110000101xxxx<<<<1100xxxxxxxx", InstName.Ldr,      InstEmit32.Ldr,      OpCodeT32MemImm8.Create);
             SetT32("111110000101xxxx<<<<11x1xxxxxxxx", InstName.Ldr,      InstEmit32.Ldr,      OpCodeT32MemImm8.Create);
             SetT32("111110001101xxxxxxxxxxxxxxxxxxxx", InstName.Ldr,      InstEmit32.Ldr,      OpCodeT32MemImm12.Create);
+            SetT32("111110000101<<<<xxxx000000xxxxxx", InstName.Ldr,      InstEmit32.Ldr,      OpCodeT32MemRsImm.Create);
             SetT32("111110000001xxxx<<<<10x1xxxxxxxx", InstName.Ldrb,     InstEmit32.Ldrb,     OpCodeT32MemImm8.Create);
             SetT32("111110000001xxxx<<<<1100xxxxxxxx", InstName.Ldrb,     InstEmit32.Ldrb,     OpCodeT32MemImm8.Create);
             SetT32("111110000001xxxx<<<<11x1xxxxxxxx", InstName.Ldrb,     InstEmit32.Ldrb,     OpCodeT32MemImm8.Create);
             SetT32("111110001001xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb,     InstEmit32.Ldrb,     OpCodeT32MemImm12.Create);
+            SetT32("1110100>x1>1<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd,     InstEmit32.Ldrd,     OpCodeT32MemImm8D.Create);
             SetT32("111110000011xxxx<<<<10x1xxxxxxxx", InstName.Ldrh,     InstEmit32.Ldrh,     OpCodeT32MemImm8.Create);
             SetT32("111110000011xxxx<<<<1100xxxxxxxx", InstName.Ldrh,     InstEmit32.Ldrh,     OpCodeT32MemImm8.Create);
             SetT32("111110000011xxxx<<<<11x1xxxxxxxx", InstName.Ldrh,     InstEmit32.Ldrh,     OpCodeT32MemImm8.Create);
@@ -1102,10 +1107,15 @@ namespace ARMeilleure.Decoders
             SetT32("11110x01110xxxxx0xxxxxxxxxxxxxxx", InstName.Rsb,      InstEmit32.Rsb,      OpCodeT32AluImm.Create);
             SetT32("11101011011xxxxx0xxxxxxxxxxxxxxx", InstName.Sbc,      InstEmit32.Sbc,      OpCodeT32AluRsImm.Create);
             SetT32("11110x01011xxxxx0xxxxxxxxxxxxxxx", InstName.Sbc,      InstEmit32.Sbc,      OpCodeT32AluImm.Create);
+            SetT32("111010001100xxxxxxxx11111110xxxx", InstName.Stlex,    InstEmit32.Stlex,    OpCodeT32MemStEx.Create);
+            SetT32("1110100010x0xxxx0xxxxxxxxxxxxxxx", InstName.Stm,      InstEmit32.Stm,      OpCodeT32MemMult.Create);
+            SetT32("1110100100x0xxxx0xxxxxxxxxxxxxxx", InstName.Stm,      InstEmit32.Stm,      OpCodeT32MemMult.Create);
             SetT32("111110000100xxxxxxxx1<<>xxxxxxxx", InstName.Str,      InstEmit32.Str,      OpCodeT32MemImm8.Create);
             SetT32("111110001100xxxxxxxxxxxxxxxxxxxx", InstName.Str,      InstEmit32.Str,      OpCodeT32MemImm12.Create);
+            SetT32("111110000100<<<<xxxx000000xxxxxx", InstName.Str,      InstEmit32.Str,      OpCodeT32MemRsImm.Create);
             SetT32("111110000000xxxxxxxx1<<>xxxxxxxx", InstName.Strb,     InstEmit32.Strb,     OpCodeT32MemImm8.Create);
             SetT32("111110001000xxxxxxxxxxxxxxxxxxxx", InstName.Strb,     InstEmit32.Strb,     OpCodeT32MemImm12.Create);
+            SetT32("1110100>x1>0<<<<xxxxxxxxxxxxxxxx", InstName.Strd,     InstEmit32.Strd,     OpCodeT32MemImm8D.Create);
             SetT32("111110000010xxxxxxxx1<<>xxxxxxxx", InstName.Strh,     InstEmit32.Strh,     OpCodeT32MemImm8.Create);
             SetT32("111110001010xxxxxxxxxxxxxxxxxxxx", InstName.Strh,     InstEmit32.Strh,     OpCodeT32MemImm12.Create);
             SetT32("11101011101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub,      InstEmit32.Sub,      OpCodeT32AluRsImm.Create);

+ 1 - 1
ARMeilleure/Instructions/InstEmitFlow32.cs

@@ -88,7 +88,7 @@ namespace ARMeilleure.Instructions
         {
             OpCodeT16BImmCmp op = (OpCodeT16BImmCmp)context.CurrOp;
 
-            Operand value = GetIntOrZR(context, op.Rn);
+            Operand value = GetIntA32(context, op.Rn);
             Operand lblTarget = context.GetLabel((ulong)op.Immediate);
 
             if (onNotZero)

+ 2 - 2
ARMeilleure/Instructions/InstEmitMemoryHelper.cs

@@ -547,7 +547,7 @@ namespace ARMeilleure.Instructions
         {
             switch (context.CurrOp)
             {
-                case OpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
+                case IOpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
 
                 case IOpCode32MemReg op: return GetIntA32(context, op.Rm);
 
@@ -564,7 +564,7 @@ namespace ARMeilleure.Instructions
             return new InvalidOperationException($"Invalid OpCode type \"{opCode?.GetType().Name ?? "null"}\".");
         }
 
-        public static Operand GetMShiftedByImmediate(ArmEmitterContext context, OpCode32MemRsImm op, bool setCarry)
+        public static Operand GetMShiftedByImmediate(ArmEmitterContext context, IOpCode32MemRsImm op, bool setCarry)
         {
             Operand m = GetIntA32(context, op.Rm);
 

+ 1 - 1
ARMeilleure/Translation/ControlFlowGraph.cs

@@ -14,7 +14,7 @@ namespace ARMeilleure.Translation
         public BasicBlock Entry { get; }
         public IntrusiveList<BasicBlock> Blocks { get; }
         public BasicBlock[] PostOrderBlocks => _postOrderBlocks;
-        public int[] PostOrderMap => _postOrderMap; 
+        public int[] PostOrderMap => _postOrderMap;
 
         public ControlFlowGraph(BasicBlock entry, IntrusiveList<BasicBlock> blocks, int localsCount)
         {