diff --git a/ARMeilleure/Decoders/OpCode32SimdRegLong.cs b/ARMeilleure/Decoders/OpCode32SimdRegLong.cs
index 24ae42d80a..144824b312 100644
--- a/ARMeilleure/Decoders/OpCode32SimdRegLong.cs
+++ b/ARMeilleure/Decoders/OpCode32SimdRegLong.cs
@@ -8,7 +8,14 @@
         {
             Q = false;
             RegisterSize = RegisterSize.Simd64;
+
             Polynomial = ((opCode >> 9) & 0x1) != 0;
+
+            // Subclasses have their own handling of Vx to account for before checking.
+            if (GetType() == typeof(OpCode32SimdRegLong) && DecoderHelper.VectorArgumentsInvalid(true, Vd))
+            {
+                Instruction = InstDescriptor.Undefined;
+            }
         }
     }
 }
diff --git a/ARMeilleure/Decoders/OpCode32SimdRegWide.cs b/ARMeilleure/Decoders/OpCode32SimdRegWide.cs
index 55384b2bd8..93ef69496f 100644
--- a/ARMeilleure/Decoders/OpCode32SimdRegWide.cs
+++ b/ARMeilleure/Decoders/OpCode32SimdRegWide.cs
@@ -1,6 +1,6 @@
 namespace ARMeilleure.Decoders
 {
-    sealed class OpCode32SimdRegWide : OpCode32SimdReg
+    class OpCode32SimdRegWide : OpCode32SimdReg
     {
         public OpCode32SimdRegWide(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
         {
diff --git a/ARMeilleure/Decoders/OpCode32SimdShImm.cs b/ARMeilleure/Decoders/OpCode32SimdShImm.cs
index 53da6bfb0e..e40107a27c 100644
--- a/ARMeilleure/Decoders/OpCode32SimdShImm.cs
+++ b/ARMeilleure/Decoders/OpCode32SimdShImm.cs
@@ -2,34 +2,33 @@
 {
     class OpCode32SimdShImm : OpCode32Simd
     {
-        public int Immediate { get; private set; }
         public int Shift { get; private set; }
 
         public OpCode32SimdShImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
         {
-            Immediate = (opCode >> 16) & 0x3f;
-            var limm = ((opCode >> 1) & 0x40) | Immediate;
+            int imm6 = (opCode >> 16) & 0x3f;
+            int limm6 = ((opCode >> 1) & 0x40) | imm6;
 
-            if ((limm & 0x40) == 0b1000000)
+            if ((limm6 & 0x40) == 0b1000000)
             {
                 Size = 3;
-                Shift = Immediate;
-            } 
-            else if ((limm & 0x60) == 0b0100000)
+                Shift = imm6;
+            }
+            else if ((limm6 & 0x60) == 0b0100000)
             {
                 Size = 2;
-                Shift = Immediate - 32;
+                Shift = imm6 - 32;
             }
-            else if ((limm & 0x70) == 0b0010000)
+            else if ((limm6 & 0x70) == 0b0010000)
             {
                 Size = 1;
-                Shift = Immediate - 16;
+                Shift = imm6 - 16;
             }
-            else if ((limm & 0x78) == 0b0001000)
+            else if ((limm6 & 0x78) == 0b0001000)
             {
                 Size = 0;
-                Shift = Immediate - 8;
-            } 
+                Shift = imm6 - 8;
+            }
             else
             {
                 Instruction = InstDescriptor.Undefined;
diff --git a/ARMeilleure/Decoders/OpCode32SimdShImmLong.cs b/ARMeilleure/Decoders/OpCode32SimdShImmLong.cs
new file mode 100644
index 0000000000..1e77b950ab
--- /dev/null
+++ b/ARMeilleure/Decoders/OpCode32SimdShImmLong.cs
@@ -0,0 +1,40 @@
+namespace ARMeilleure.Decoders
+{
+    class OpCode32SimdShImmLong : OpCode32Simd
+    {
+        public int Shift { get; private set; }
+
+        public OpCode32SimdShImmLong(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
+        {
+            Q = false;
+            RegisterSize = RegisterSize.Simd64;
+
+            int imm6 = (opCode >> 16) & 0x3f;
+
+            if ((imm6 & 0x20) == 0b100000)
+            {
+                Size = 2;
+                Shift = imm6 - 32;
+            }
+            else if ((imm6 & 0x30) == 0b010000)
+            {
+                Size = 1;
+                Shift = imm6 - 16;
+            }
+            else if ((imm6 & 0x38) == 0b001000)
+            {
+                Size = 0;
+                Shift = imm6 - 8;
+            }
+            else
+            {
+                Instruction = InstDescriptor.Undefined;
+            }
+
+            if (GetType() == typeof(OpCode32SimdShImmLong) && DecoderHelper.VectorArgumentsInvalid(true, Vd))
+            {
+                Instruction = InstDescriptor.Undefined;
+            }
+        }
+    }
+}
diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs
index 1575981480..903eaebdba 100644
--- a/ARMeilleure/Decoders/OpCodeTable.cs
+++ b/ARMeilleure/Decoders/OpCodeTable.cs
@@ -787,6 +787,7 @@ namespace ARMeilleure.Decoders
             SetA32("<<<<00010001xxxx0000xxxx0xx1xxxx", InstName.Tst,     InstEmit32.Tst,     typeof(OpCode32AluRsReg));
             SetA32("<<<<0111111xxxxxxxxxxxxxx101xxxx", InstName.Ubfx,    InstEmit32.Ubfx,    typeof(OpCode32AluBf));
             SetA32("<<<<01110011xxxx1111xxxx0001xxxx", InstName.Udiv,    InstEmit32.Udiv,    typeof(OpCode32AluMla));
+            SetA32("<<<<00000100xxxxxxxxxxxx1001xxxx", InstName.Umaal,   InstEmit32.Umaal,   typeof(OpCode32AluUmull));
             SetA32("<<<<0000101xxxxxxxxxxxxx1001xxxx", InstName.Umlal,   InstEmit32.Umlal,   typeof(OpCode32AluUmull));
             SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull,   InstEmit32.Umull,   typeof(OpCode32AluUmull));
             SetA32("<<<<0110111xxxxxxxxxxxxxxx01xxxx", InstName.Usat,    InstEmit32.Usat,    typeof(OpCode32Sat));
@@ -800,12 +801,15 @@ namespace ARMeilleure.Decoders
             SetA32("111100111x110000xxx0001100x0xxx0", InstName.Aese_V,   InstEmit32.Aese_V,   typeof(OpCode32Simd));
             SetA32("111100111x110000xxx0001111x0xxx0", InstName.Aesimc_V, InstEmit32.Aesimc_V, typeof(OpCode32Simd));
             SetA32("111100111x110000xxx0001110x0xxx0", InstName.Aesmc_V,  InstEmit32.Aesmc_V,  typeof(OpCode32Simd));
+            SetA32("1111001x0x<<xxxxxxxx0111xxx0xxxx", InstName.Vabd,     InstEmit32.Vabd_I,   typeof(OpCode32SimdReg));
+            SetA32("1111001x1x<<xxxxxxxx0111x0x0xxxx", InstName.Vabdl,    InstEmit32.Vabdl_I,  typeof(OpCode32SimdRegLong));
             SetA32("<<<<11101x110000xxxx101x11x0xxxx", InstName.Vabs,     InstEmit32.Vabs_S,   typeof(OpCode32SimdS));
             SetA32("111100111x11<<01xxxx00110xx0xxxx", InstName.Vabs,     InstEmit32.Vabs_V,   typeof(OpCode32SimdCmpZ));
             SetA32("111100111x111001xxxx01110xx0xxxx", InstName.Vabs,     InstEmit32.Vabs_V,   typeof(OpCode32SimdCmpZ));
             SetA32("111100100xxxxxxxxxxx1000xxx0xxxx", InstName.Vadd,     InstEmit32.Vadd_I,   typeof(OpCode32SimdReg));
             SetA32("<<<<11100x11xxxxxxxx101xx0x0xxxx", InstName.Vadd,     InstEmit32.Vadd_S,   typeof(OpCode32SimdRegS));
             SetA32("111100100x00xxxxxxxx1101xxx0xxxx", InstName.Vadd,     InstEmit32.Vadd_V,   typeof(OpCode32SimdReg));
+            SetA32("1111001x1x<<xxxxxxxx0000x0x0xxxx", InstName.Vaddl,    InstEmit32.Vaddl_I,  typeof(OpCode32SimdRegLong));
             SetA32("1111001x1x<<xxxxxxxx0001x0x0xxxx", InstName.Vaddw,    InstEmit32.Vaddw_I,  typeof(OpCode32SimdRegWide));
             SetA32("111100100x00xxxxxxxx0001xxx1xxxx", InstName.Vand,     InstEmit32.Vand_I,   typeof(OpCode32SimdBinary));
             SetA32("111100100x01xxxxxxxx0001xxx1xxxx", InstName.Vbic,     InstEmit32.Vbic_I,   typeof(OpCode32SimdBinary));
@@ -838,6 +842,7 @@ namespace ARMeilleure.Decoders
             SetA32("111100101x11xxxxxxxxxxxxxxx0xxxx", InstName.Vext,     InstEmit32.Vext,     typeof(OpCode32SimdExt));
             SetA32("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma,     InstEmit32.Vfma_S,   typeof(OpCode32SimdRegS));
             SetA32("<<<<11101x10xxxxxxxx101xx1x0xxxx", InstName.Vfms,     InstEmit32.Vfms_S,   typeof(OpCode32SimdRegS));
+            SetA32("1111001x0x<<xxxxxxxx0000xxx0xxxx", InstName.Vhadd,    InstEmit32.Vhadd,    typeof(OpCode32SimdReg));
             SetA32("111101001x10xxxxxxxxxx00xxxxxxxx", InstName.Vld1,     InstEmit32.Vld1,     typeof(OpCode32SimdMemSingle));
             SetA32("111101000x10xxxxxxxx0111xxxxxxxx", InstName.Vld1,     InstEmit32.Vld1,     typeof(OpCode32SimdMemPair)); // Regs = 1.
             SetA32("111101000x10xxxxxxxx1010xxxxxxxx", InstName.Vld1,     InstEmit32.Vld1,     typeof(OpCode32SimdMemPair)); // Regs = 2.
@@ -919,6 +924,7 @@ namespace ARMeilleure.Decoders
             SetA32("111100110x10xxxxxxxx1111x0x0xxxx", InstName.Vpmin,    InstEmit32.Vpmin_V,  typeof(OpCode32SimdReg));
             SetA32("1111001x1x>>>xxxxxxx100101x1xxx0", InstName.Vqrshrn,  InstEmit32.Vqrshrn,  typeof(OpCode32SimdShImmNarrow));
             SetA32("111100111x>>>xxxxxxx100001x1xxx0", InstName.Vqrshrun, InstEmit32.Vqrshrun, typeof(OpCode32SimdShImmNarrow));
+            SetA32("1111001x1x>>>xxxxxxx100100x1xxx0", InstName.Vqshrn,   InstEmit32.Vqshrn,   typeof(OpCode32SimdShImmNarrow));
             SetA32("111100111x111011xxxx010x0xx0xxxx", InstName.Vrecpe,   InstEmit32.Vrecpe,   typeof(OpCode32SimdSqrte));
             SetA32("111100100x00xxxxxxxx1111xxx1xxxx", InstName.Vrecps,   InstEmit32.Vrecps,   typeof(OpCode32SimdReg));
             SetA32("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev,     InstEmit32.Vrev,     typeof(OpCode32SimdRev));
@@ -930,6 +936,7 @@ namespace ARMeilleure.Decoders
             SetA32("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel,     InstEmit32.Vsel,     typeof(OpCode32SimdSel));
             SetA32("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl,     InstEmit32.Vshl,     typeof(OpCode32SimdShImm));
             SetA32("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl,     InstEmit32.Vshl_I,   typeof(OpCode32SimdReg));
+            SetA32("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll,    InstEmit32.Vshll,    typeof(OpCode32SimdShImmLong)); // A1 encoding.
             SetA32("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr,     InstEmit32.Vshr,     typeof(OpCode32SimdShImm));
             SetA32("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn,    InstEmit32.Vshrn,    typeof(OpCode32SimdShImmNarrow));
             SetA32("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt,    InstEmit32.Vsqrt_S,  typeof(OpCode32SimdS));
diff --git a/ARMeilleure/Instructions/InstEmitMul32.cs b/ARMeilleure/Instructions/InstEmitMul32.cs
index 6714c5fd0d..454d44a460 100644
--- a/ARMeilleure/Instructions/InstEmitMul32.cs
+++ b/ARMeilleure/Instructions/InstEmitMul32.cs
@@ -283,6 +283,26 @@ namespace ARMeilleure.Instructions
             EmitGenericAluStoreA32(context, op.Rd, false, res);
         }
 
+        public static void Umaal(ArmEmitterContext context)
+        {
+            OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
+
+            Operand n   = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rn));
+            Operand m   = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rm));
+            Operand dHi = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdHi));
+            Operand dLo = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdLo));
+
+            Operand res = context.Multiply(n, m);
+                    res = context.Add(res, dHi);
+                    res = context.Add(res, dLo);
+
+            Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
+            Operand lo = context.ConvertI64ToI32(res);
+
+            EmitGenericAluStoreA32(context, op.RdHi, false, hi);
+            EmitGenericAluStoreA32(context, op.RdLo, false, lo);
+        }
+
         public static void Umlal(ArmEmitterContext context)
         {
             EmitMlal(context, false);
diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
index 57176794b9..0eeed5bb94 100644
--- a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
@@ -14,6 +14,20 @@ namespace ARMeilleure.Instructions
 {
     static partial class InstEmit32
     {
+        public static void Vabd_I(ArmEmitterContext context)
+        {
+            OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
+
+            EmitVectorBinaryOpI32(context, (op1, op2) => EmitAbs(context, context.Subtract(op1, op2)), !op.U);
+        }
+
+        public static void Vabdl_I(ArmEmitterContext context)
+        {
+            OpCode32SimdRegLong op = (OpCode32SimdRegLong)context.CurrOp;
+
+            EmitVectorBinaryLongOpI32(context, (op1, op2) => EmitAbs(context, context.Subtract(op1, op2)), !op.U);
+        }
+
         public static void Vabs_S(ArmEmitterContext context)
         {
             OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
@@ -107,6 +121,13 @@ namespace ARMeilleure.Instructions
             }
         }
 
+        public static void Vaddl_I(ArmEmitterContext context)
+        {
+            OpCode32SimdRegLong op = (OpCode32SimdRegLong)context.CurrOp;
+
+            EmitVectorBinaryLongOpI32(context, (op1, op2) => context.Add(op1, op2), !op.U);
+        }
+
         public static void Vaddw_I(ArmEmitterContext context)
         {
             OpCode32SimdRegWide op = (OpCode32SimdRegWide)context.CurrOp;
@@ -263,6 +284,20 @@ namespace ARMeilleure.Instructions
             }
         }
 
+        public static void Vhadd(ArmEmitterContext context)
+        {
+            OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
+
+            if (op.U)
+            {
+                EmitVectorBinaryOpZx32(context, (op1, op2) => context.ShiftRightUI(context.Add(op1, op2), Const(1)));
+            }
+            else
+            {
+                EmitVectorBinaryOpSx32(context, (op1, op2) => context.ShiftRightSI(context.Add(op1, op2), Const(1)));
+            }
+        }
+
         public static void Vmov_S(ArmEmitterContext context)
         {
             if (Optimizations.FastFP && Optimizations.UseSse2)
diff --git a/ARMeilleure/Instructions/InstEmitSimdShift32.cs b/ARMeilleure/Instructions/InstEmitSimdShift32.cs
index f3c002db9f..c904c0ee55 100644
--- a/ARMeilleure/Instructions/InstEmitSimdShift32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdShift32.cs
@@ -5,6 +5,8 @@ using System;
 using System.Diagnostics;
 using System.Reflection;
 
+using static ARMeilleure.Instructions.InstEmitHelper;
+using static ARMeilleure.Instructions.InstEmitSimdHelper;
 using static ARMeilleure.Instructions.InstEmitSimdHelper32;
 using static ARMeilleure.IntermediateRepresentation.OperandHelper;
 
@@ -24,6 +26,13 @@ namespace ARMeilleure.Instructions
             EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxZx);
         }
 
+        public static void Vqshrn(ArmEmitterContext context)
+        {
+            OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
+
+            EmitShrImmSaturatingNarrowOp(context, op.U ? ShrImmSaturatingNarrowFlags.VectorZxZx : ShrImmSaturatingNarrowFlags.VectorSxSx);
+        }
+
         public static void Vrshr(ArmEmitterContext context)
         {
             OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
@@ -105,6 +114,38 @@ namespace ARMeilleure.Instructions
             }
         }
 
+        public static void Vshll(ArmEmitterContext context)
+        {
+            OpCode32SimdShImmLong op = (OpCode32SimdShImmLong)context.CurrOp;
+
+            Operand res = context.VectorZero();
+
+            int elems = op.GetBytesCount() >> op.Size;
+
+            for (int index = 0; index < elems; index++)
+            {
+                Operand me = EmitVectorExtract32(context, op.Qm, op.Im + index, op.Size, !op.U);
+
+                if (op.Size == 2)
+                {
+                    if (op.U)
+                    {
+                        me = context.ZeroExtend32(OperandType.I64, me);
+                    }
+                    else
+                    {
+                        me = context.SignExtend32(OperandType.I64, me);
+                    }
+                }
+
+                me = context.ShiftLeft(me, Const(op.Shift));
+
+                res = EmitVectorInsert(context, res, me, index, op.Size + 1);
+            }
+
+            context.Copy(GetVecA32(op.Qd), res);
+        }
+
         public static void Vshr(ArmEmitterContext context)
         {
             OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
diff --git a/ARMeilleure/Instructions/InstName.cs b/ARMeilleure/Instructions/InstName.cs
index 0d0c12645a..c694bb06f9 100644
--- a/ARMeilleure/Instructions/InstName.cs
+++ b/ARMeilleure/Instructions/InstName.cs
@@ -536,6 +536,7 @@ namespace ARMeilleure.Instructions
         Trap,
         Tst,
         Ubfx,
+        Umaal,
         Umlal,
         Umull,
         Usat,
@@ -545,8 +546,11 @@ namespace ARMeilleure.Instructions
         Uxth,
 
         // FP & SIMD (AArch32)
+        Vabd,
+        Vabdl,
         Vabs,
         Vadd,
+        Vaddl,
         Vaddw,
         Vand,
         Vbic,
@@ -567,6 +571,7 @@ namespace ARMeilleure.Instructions
         Vext,
         Vfma,
         Vfms,
+        Vhadd,
         Vld1,
         Vld2,
         Vld3,
@@ -598,11 +603,13 @@ namespace ARMeilleure.Instructions
         Vpmin,
         Vqrshrn,
         Vqrshrun,
+        Vqshrn,
         Vrev,
         Vrint,
         Vrshr,
         Vsel,
         Vshl,
+        Vshll,
         Vshr,
         Vshrn,
         Vst1,
diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs
index 26b0046934..bf5fd8389e 100644
--- a/ARMeilleure/Translation/PTC/Ptc.cs
+++ b/ARMeilleure/Translation/PTC/Ptc.cs
@@ -21,7 +21,7 @@ namespace ARMeilleure.Translation.PTC
     {
         private const string HeaderMagic = "PTChd";
 
-        private const int InternalVersion = 1447; //! To be incremented manually for each change to the ARMeilleure project.
+        private const int InternalVersion = 1577; //! To be incremented manually for each change to the ARMeilleure project.
 
         private const string ActualDir = "0";
         private const string BackupDir = "1";