diff --git a/Ryujinx/Cpu/AOpCodeTable.cs b/Ryujinx/Cpu/AOpCodeTable.cs
index a7deb2c7f8..bf1ceec7da 100644
--- a/Ryujinx/Cpu/AOpCodeTable.cs
+++ b/Ryujinx/Cpu/AOpCodeTable.cs
@@ -153,6 +153,7 @@ namespace ChocolArm64
             Set("x0011110xx101000000000xxxxxxxxxx", AInstEmit.Fcvtps_S,      typeof(AOpCodeSimdCvt));
             Set("x0011110xx111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_S,      typeof(AOpCodeSimdCvt));
             Set("0x0011101x100001101110xxxxxxxxxx", AInstEmit.Fcvtzs_V,      typeof(AOpCodeSimd));
+            Set("0x0011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzs_V_Fix,  typeof(AOpCodeSimdShImm));
             Set("x0011110xx111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_S,      typeof(AOpCodeSimdCvt));
             Set("0x1011101x100001101110xxxxxxxxxx", AInstEmit.Fcvtzu_V,      typeof(AOpCodeSimd));
             Set("0x1011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzu_V_Fix,  typeof(AOpCodeSimdShImm));
@@ -186,8 +187,10 @@ namespace ChocolArm64
             Set("0x0011101x1xxxxx110101xxxxxxxxxx", AInstEmit.Fsub_V,        typeof(AOpCodeSimdReg));
             Set("01001110000xxxxx000111xxxxxxxxxx", AInstEmit.Ins_Gp,        typeof(AOpCodeSimdIns));
             Set("01101110000xxxxx0xxxx1xxxxxxxxxx", AInstEmit.Ins_V,         typeof(AOpCodeSimdIns));
-            Set("0x00110001000000xxxxxxxxxxxxxxxx", AInstEmit.Ld__V,         typeof(AOpCodeSimdMemMult));
-            Set("0x001100110xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ld__V,         typeof(AOpCodeSimdMemMult));
+            Set("0x00110001000000xxxxxxxxxxxxxxxx", AInstEmit.Ld__Vms,       typeof(AOpCodeSimdMemMs));
+            Set("0x001100110xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ld__Vms,       typeof(AOpCodeSimdMemMs));
+            Set("0x00110101000000xx0xxxxxxxxxxxxx", AInstEmit.Ld__Vss,       typeof(AOpCodeSimdMemSs));
+            Set("0x001101110xxxxxxx0xxxxxxxxxxxxx", AInstEmit.Ld__Vss,       typeof(AOpCodeSimdMemSs));
             Set("xx10110xx1xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldp,           typeof(AOpCodeSimdMemPair));
             Set("xx111100x10xxxxxxxxx00xxxxxxxxxx", AInstEmit.Ldr,           typeof(AOpCodeSimdMemImm));
             Set("xx111100x10xxxxxxxxx01xxxxxxxxxx", AInstEmit.Ldr,           typeof(AOpCodeSimdMemImm));
@@ -218,8 +221,8 @@ namespace ChocolArm64
             Set("0x00111100>>>xxx101001xxxxxxxxxx", AInstEmit.Sshll_V,       typeof(AOpCodeSimdShImm));
             Set("010111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_S,        typeof(AOpCodeSimdShImm));
             Set("0x0011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_V,        typeof(AOpCodeSimdShImm));
-            Set("0x00110000000000xxxxxxxxxxxxxxxx", AInstEmit.St__V,         typeof(AOpCodeSimdMemMult));
-            Set("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__V,         typeof(AOpCodeSimdMemMult));
+            Set("0x00110000000000xxxxxxxxxxxxxxxx", AInstEmit.St__V,         typeof(AOpCodeSimdMemMs));
+            Set("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__V,         typeof(AOpCodeSimdMemMs));
             Set("xx10110xx0xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Stp,           typeof(AOpCodeSimdMemPair));
             Set("xx111100x00xxxxxxxxx00xxxxxxxxxx", AInstEmit.Str,           typeof(AOpCodeSimdMemImm));
             Set("xx111100x00xxxxxxxxx01xxxxxxxxxx", AInstEmit.Str,           typeof(AOpCodeSimdMemImm));
diff --git a/Ryujinx/Cpu/AOptimizations.cs b/Ryujinx/Cpu/AOptimizations.cs
new file mode 100644
index 0000000000..cbfd1ce51b
--- /dev/null
+++ b/Ryujinx/Cpu/AOptimizations.cs
@@ -0,0 +1,4 @@
+public static class AOptimizations
+{
+
+}
\ No newline at end of file
diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMult.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs
similarity index 91%
rename from Ryujinx/Cpu/Decoder/AOpCodeSimdMemMult.cs
rename to Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs
index 9731c7e745..0e8480b03b 100644
--- a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMult.cs
+++ b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs
@@ -3,7 +3,7 @@ using ChocolArm64.State;
 
 namespace ChocolArm64.Decoder
 {
-    class AOpCodeSimdMemMult : AOpCode, IAOpCodeSimd
+    class AOpCodeSimdMemMs : AOpCode, IAOpCodeSimd
     {
         public int  Rt     { get; private set; }
         public int  Rn     { get; private set; }
@@ -14,7 +14,7 @@ namespace ChocolArm64.Decoder
         public int  Elems  { get; private set; }
         public bool WBack  { get; private set; }
 
-        public AOpCodeSimdMemMult(AInst Inst, long Position, int OpCode) : base(Inst, Position)
+        public AOpCodeSimdMemMs(AInst Inst, long Position, int OpCode) : base(Inst, Position)
         {
             switch ((OpCode >> 12) & 0xf)
             {
diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs
new file mode 100644
index 0000000000..c2917dfc8b
--- /dev/null
+++ b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs
@@ -0,0 +1,104 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.State;
+
+namespace ChocolArm64.Decoder
+{
+    class AOpCodeSimdMemSs : AOpCode, IAOpCodeSimd
+    {
+        public int  Rt        { get; private set; }
+        public int  Rn        { get; private set; }
+        public int  Size      { get; private set; }
+        public int  Rm        { get; private set; }
+        public int  SElems    { get; private set; }
+        public int  Index     { get; private set; }
+        public bool Replicate { get; private set; }
+        public bool WBack     { get; private set; }
+
+        public AOpCodeSimdMemSs(AInst Inst, long Position, int OpCode) : base(Inst, Position)
+        {
+            int Size   = (OpCode >> 10) & 3;
+            int S      = (OpCode >> 12) & 1;
+            int SElems = (OpCode >> 12) & 2;
+            int Scale  = (OpCode >> 14) & 3;
+            int L      = (OpCode >> 22) & 1;
+            int Q      = (OpCode >> 30) & 1;
+            
+            SElems |= (OpCode >> 21) & 1;
+
+            SElems++;
+
+            int Index = (Q << 3) | (S << 2) | Size;
+
+            switch (Scale)
+            {
+                case 0: Index >>= 0; break;
+
+                case 1:
+                {
+                    if ((Index & 1) != 0)
+                    {
+                        Inst = AInst.Undefined;
+
+                        return;
+                    }
+
+                    Index >>= 1;
+
+                    break;
+                }
+
+                case 2:
+                {
+                    if ((Index & 2) != 0 ||
+                       ((Index & 1) != 0 && S != 0))
+                    {
+                        Inst = AInst.Undefined;
+
+                        return;
+                    }
+
+                    if ((Index & 1) != 0)
+                    {
+                        Index >>= 3;
+                    }
+                    else
+                    {
+                        Index >>= 2;
+
+                        Scale = 3;
+                    }
+
+                    break;
+                }
+
+                case 3:
+                {
+                    if (L == 0 || S != 0)
+                    {
+                        Inst = AInst.Undefined;
+
+                        return;
+                    }
+
+                    Scale = Size;
+
+                    Replicate = true;
+
+                    break;
+                }
+            }
+
+            this.SElems = SElems;
+            this.Size   = Scale;
+
+            Rt    =  (OpCode >>  0) & 0x1f;
+            Rn    =  (OpCode >>  5) & 0x1f;
+            Rm    =  (OpCode >> 16) & 0x1f;
+            WBack = ((OpCode >> 23) & 0x1) != 0;
+
+            RegisterSize = Q != 0
+                ? ARegisterSize.SIMD128
+                : ARegisterSize.SIMD64;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs
index 8d4ade3a17..9ba75bc85a 100644
--- a/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs
+++ b/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs
@@ -122,6 +122,7 @@ namespace ChocolArm64.Instruction
             AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
 
             Context.EmitLdvec(Op.Rn);
+            Context.EmitLdc_I4(0);
             Context.EmitLdc_I4(Op.SizeF);
 
             ASoftFallback.EmitCall(Context,
@@ -131,6 +132,21 @@ namespace ChocolArm64.Instruction
             Context.EmitStvec(Op.Rd);
         }
 
+        public static void Fcvtzs_V_Fix(AILEmitterCtx Context)
+        {
+            AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+            Context.EmitLdvec(Op.Rn);
+            Context.EmitLdc_I4((8 << (Op.Size + 1)) - Op.Imm);
+            Context.EmitLdc_I4(Op.Size - 2);
+
+            ASoftFallback.EmitCall(Context,
+                nameof(ASoftFallback.Fcvtzs_V64),
+                nameof(ASoftFallback.Fcvtzs_V128));
+
+            Context.EmitStvec(Op.Rd);
+        }
+
         public static void Fcvtzu_V(AILEmitterCtx Context)
         {
             AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
@@ -283,7 +299,8 @@ namespace ChocolArm64.Instruction
             Context.EmitStvec(Op.Rd);
         }
 
-        public static void Ld__V(AILEmitterCtx Context) => EmitSimdMultLdSt(Context, IsLoad: true);
+        public static void Ld__Vms(AILEmitterCtx Context) => EmitSimdMemMs(Context, IsLoad: true);
+        public static void Ld__Vss(AILEmitterCtx Context) => EmitSimdMemSs(Context, IsLoad: true);
 
         public static void Mla_V(AILEmitterCtx Context) => EmitVectorMla(Context);
 
@@ -391,7 +408,7 @@ namespace ChocolArm64.Instruction
             EmitVectorImmBinarySx(Context, OpCodes.Shr, (8 << (Op.Size + 1)) - Op.Imm);
         }
 
-        public static void St__V(AILEmitterCtx Context) => EmitSimdMultLdSt(Context, IsLoad: false);
+        public static void St__V(AILEmitterCtx Context) => EmitSimdMemMs(Context, IsLoad: false);
 
         public static void Sub_V(AILEmitterCtx Context) => EmitVectorBinaryZx(Context, OpCodes.Sub);
 
@@ -571,9 +588,9 @@ namespace ChocolArm64.Instruction
             Context.EmitStvec(Op.Rd);
         }
 
-        private static void EmitSimdMultLdSt(AILEmitterCtx Context, bool IsLoad)
+        private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad)
         {
-            AOpCodeSimdMemMult Op = (AOpCodeSimdMemMult)Context.CurrOp;
+            AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)Context.CurrOp;
 
             int Offset = 0;
 
@@ -644,6 +661,79 @@ namespace ChocolArm64.Instruction
             }
         }
 
+        private static void EmitSimdMemSs(AILEmitterCtx Context, bool IsLoad)
+        {
+            AOpCodeSimdMemSs Op = (AOpCodeSimdMemSs)Context.CurrOp;
+
+            //TODO: Replicate mode.
+
+            int Offset = 0;
+
+            for (int SElem = 0; SElem < Op.SElems; SElem++)
+            {
+                int Rt = (Op.Rt + SElem) & 0x1f;
+
+                if (IsLoad)
+                {
+                    Context.EmitLdvec(Rt);
+                    Context.EmitLdc_I4(Op.Index);
+                    Context.EmitLdc_I4(Op.Size);
+                    Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
+                    Context.EmitLdint(Op.Rn);
+                    Context.EmitLdc_I8(Offset);
+
+                    Context.Emit(OpCodes.Add);
+
+                    EmitReadZxCall(Context, Op.Size);
+
+                    ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
+
+                    Context.EmitStvec(Rt);
+
+                    if (Op.RegisterSize == ARegisterSize.SIMD64)
+                    {
+                        EmitVectorZeroUpper(Context, Rt);
+                    }
+                }
+                else
+                {
+                    Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
+                    Context.EmitLdint(Op.Rn);
+                    Context.EmitLdc_I8(Offset);
+
+                    Context.Emit(OpCodes.Add);
+
+                    Context.EmitLdvec(Rt);
+                    Context.EmitLdc_I4(Op.Index);
+                    Context.EmitLdc_I4(Op.Size);
+
+                    ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec));
+
+                    EmitWriteCall(Context, Op.Size);
+                }
+
+                Offset += 1 << Op.Size;
+            }
+
+            if (Op.WBack)
+            {
+                Context.EmitLdint(Op.Rn);
+
+                if (Op.Rm != ARegisters.ZRIndex)
+                {
+                    Context.EmitLdint(Op.Rm);
+                }
+                else
+                {
+                    Context.EmitLdc_I8(Offset);
+                }
+
+                Context.Emit(OpCodes.Add);
+
+                Context.EmitStint(Op.Rn);
+            }
+        }
+
         private static void EmitVectorAddv(AILEmitterCtx Context)
         {
             AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
diff --git a/Ryujinx/Cpu/Instruction/ASoftFallback.cs b/Ryujinx/Cpu/Instruction/ASoftFallback.cs
index 0d52713208..caf3cfca74 100644
--- a/Ryujinx/Cpu/Instruction/ASoftFallback.cs
+++ b/Ryujinx/Cpu/Instruction/ASoftFallback.cs
@@ -405,17 +405,17 @@ namespace ChocolArm64.Instruction
             return Res;
         }
 
-        public static AVec Fcvtzs_V64(AVec Vector, int Size)
+        public static AVec Fcvtzs_V64(AVec Vector, int FBits, int Size)
         {
-            return Fcvtzs_V(Vector, Size, 2);
+            return Fcvtzs_V(Vector, FBits, Size, 2);
         }
 
-        public static AVec Fcvtzs_V128(AVec Vector, int Size)
+        public static AVec Fcvtzs_V128(AVec Vector, int FBits, int Size)
         {
-            return Fcvtzs_V(Vector, Size, 4);
+            return Fcvtzs_V(Vector, FBits, Size, 4);
         }
 
-        private static AVec Fcvtzs_V(AVec Vector, int Size, int Bytes)
+        private static AVec Fcvtzs_V(AVec Vector, int FBits, int Size, int Bytes)
         {
             AVec Res = new AVec();
 
@@ -427,7 +427,7 @@ namespace ChocolArm64.Instruction
                 {
                     float Value = Vector.ExtractSingle(Index);
 
-                    Res = InsertSVec(Res, Index, Size + 2, SatSingleToInt32(Value));
+                    Res = InsertSVec(Res, Index, Size + 2, SatSingleToInt32(Value, FBits));
                 }
             }
             else
@@ -436,7 +436,7 @@ namespace ChocolArm64.Instruction
                 {
                     double Value = Vector.ExtractDouble(Index);
 
-                    Res = InsertSVec(Res, Index, Size + 2, SatDoubleToInt64(Value));
+                    Res = InsertSVec(Res, Index, Size + 2, SatDoubleToInt64(Value, FBits));
                 }
             }
 
diff --git a/Ryujinx/Cpu/Memory/AMemory.cs b/Ryujinx/Cpu/Memory/AMemory.cs
index 8159b341ee..7952186d53 100644
--- a/Ryujinx/Cpu/Memory/AMemory.cs
+++ b/Ryujinx/Cpu/Memory/AMemory.cs
@@ -1,3 +1,4 @@
+using ChocolArm64.Exceptions;
 using ChocolArm64.State;
 using System;
 using System.Collections.Generic;
@@ -119,26 +120,46 @@ namespace ChocolArm64.Memory
 
         public byte ReadByte(long Position)
         {
+#if DEBUG
+            EnsureAccessIsValid(Position, AMemoryPerm.Read);
+#endif
+
             return *((byte*)(RamPtr + (uint)Position));
         }
 
         public ushort ReadUInt16(long Position)
         {
+#if DEBUG
+            EnsureAccessIsValid(Position, AMemoryPerm.Read);
+#endif
+
             return *((ushort*)(RamPtr + (uint)Position));
         }
 
         public uint ReadUInt32(long Position)
         {
+#if DEBUG
+            EnsureAccessIsValid(Position, AMemoryPerm.Read);
+#endif
+
             return *((uint*)(RamPtr + (uint)Position));
         }
 
         public ulong ReadUInt64(long Position)
         {
+#if DEBUG
+            EnsureAccessIsValid(Position, AMemoryPerm.Read);
+#endif
+
             return *((ulong*)(RamPtr + (uint)Position));
         }
 
         public AVec ReadVector128(long Position)
         {
+#if DEBUG
+            EnsureAccessIsValid(Position, AMemoryPerm.Read);
+#endif
+
             return new AVec()
             {
                 X0 = ReadUInt64(Position + 0),
@@ -153,33 +174,61 @@ namespace ChocolArm64.Memory
 
         public void WriteByte(long Position, byte Value)
         {
+#if DEBUG
+            EnsureAccessIsValid(Position, AMemoryPerm.Write);
+#endif
+
             *((byte*)(RamPtr + (uint)Position)) = Value;
         }
 
         public void WriteUInt16(long Position, ushort Value)
         {
+#if DEBUG
+            EnsureAccessIsValid(Position, AMemoryPerm.Write);
+#endif
+
             *((ushort*)(RamPtr + (uint)Position)) = Value;
         }
 
         public void WriteUInt32(long Position, uint Value)
         {
+#if DEBUG
+            EnsureAccessIsValid(Position, AMemoryPerm.Write);
+#endif
+
             *((uint*)(RamPtr + (uint)Position)) = Value;
         }
 
         public void WriteUInt64(long Position, ulong Value)
         {
+#if DEBUG
+            EnsureAccessIsValid(Position, AMemoryPerm.Write);
+#endif
+
             *((ulong*)(RamPtr + (uint)Position)) = Value;
         }
 
         public void WriteVector128(long Position, AVec Value)
         {
+#if DEBUG
+            EnsureAccessIsValid(Position, AMemoryPerm.Write);
+#endif
+
             WriteUInt64(Position + 0, Value.X0);
             WriteUInt64(Position + 8, Value.X1);
         }
 
-        private bool IsPageCrossed(long Position, int Size)
+        private void EnsureAccessIsValid(long Position, AMemoryPerm Perm)
         {
-            return (Position & AMemoryMgr.PageMask) + Size > AMemoryMgr.PageSize;
+            if (!Manager.IsMapped(Position))
+            {
+                throw new VmmPageFaultException(Position);
+            }
+
+            if (!Manager.HasPermission(Position, Perm))
+            {
+                throw new VmmAccessViolationException(Position, Perm);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx/Cpu/Memory/AMemoryMgr.cs b/Ryujinx/Cpu/Memory/AMemoryMgr.cs
index 0c2c5a50b8..cd983e78bd 100644
--- a/Ryujinx/Cpu/Memory/AMemoryMgr.cs
+++ b/Ryujinx/Cpu/Memory/AMemoryMgr.cs
@@ -163,7 +163,7 @@ namespace ChocolArm64.Memory
         {
             while (Size > 0)
             {
-                if (!HasPTEntry(Position))
+                if (!IsMapped(Position))
                 {
                     long PhysPos = Allocator.Alloc(PageSize);                   
 
@@ -254,8 +254,13 @@ namespace ChocolArm64.Memory
             return new AMemoryMapInfo(Start, Size, BaseEntry.Type, BaseEntry.Perm);
         }
 
+        public bool HasPermission(long Position, AMemoryPerm Perm)
+        {
+            return GetPTEntry(Position).Perm.HasFlag(Perm);
+        }
+
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private bool HasPTEntry(long Position)
+        public bool IsMapped(long Position)
         {
             if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
             {
diff --git a/Ryujinx/Loaders/Executable.cs b/Ryujinx/Loaders/Executable.cs
index 785a8c723f..6504365897 100644
--- a/Ryujinx/Loaders/Executable.cs
+++ b/Ryujinx/Loaders/Executable.cs
@@ -73,12 +73,14 @@ namespace Ryujinx.Loaders
             MemoryType  Type,
             AMemoryPerm Perm)
         {
-            Memory.Manager.MapPhys(Position, Data.Count, (int)Type, Perm);
+            Memory.Manager.MapPhys(Position, Data.Count, (int)Type, AMemoryPerm.Write);
 
             for (int Index = 0; Index < Data.Count; Index++)
             {
                 Memory.WriteByte(Position + Index, Data[Index]);
             }
+
+            Memory.Manager.Reprotect(Position, Data.Count, Perm);
         }
 
         private void MapBss(long Position, long Size)