diff --git a/Ryujinx/Cpu/AOpCodeTable.cs b/Ryujinx/Cpu/AOpCodeTable.cs index ffdf30a95..c9678fb56 100644 --- a/Ryujinx/Cpu/AOpCodeTable.cs +++ b/Ryujinx/Cpu/AOpCodeTable.cs @@ -151,14 +151,14 @@ namespace ChocolArm64 Set("00011110xx1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg)); Set("00011110xx1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond)); Set("00011110xx10001xx10000xxxxxxxxxx", AInstEmit.Fcvt_S, typeof(AOpCodeSimd)); - Set("x0011110xx110000000000xxxxxxxxxx", AInstEmit.Fcvtms_S, typeof(AOpCodeSimdCvt)); - Set("x0011110xx101000000000xxxxxxxxxx", AInstEmit.Fcvtps_S, typeof(AOpCodeSimdCvt)); - Set("x0011110xx111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_S, typeof(AOpCodeSimdCvt)); - Set("x0011110xx011000xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzs_Fix, typeof(AOpCodeSimdCvt)); + Set("x0011110xx110000000000xxxxxxxxxx", AInstEmit.Fcvtms_Gp, typeof(AOpCodeSimdCvt)); + Set("x0011110xx101000000000xxxxxxxxxx", AInstEmit.Fcvtps_Gp, typeof(AOpCodeSimdCvt)); + Set("x0011110xx111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_Gp, typeof(AOpCodeSimdCvt)); + Set("x0011110xx011000xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzs_Gp_Fix, typeof(AOpCodeSimdCvt)); Set("0x0011101x100001101110xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimd)); Set("0x0011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimdShImm)); - Set("x0011110xx111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_S, typeof(AOpCodeSimdCvt)); - Set("x0011110xx011001xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzu_Fix, typeof(AOpCodeSimdCvt)); + Set("x0011110xx111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_Gp, typeof(AOpCodeSimdCvt)); + Set("x0011110xx011001xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzu_Gp_Fix, typeof(AOpCodeSimdCvt)); Set("0x1011101x100001101110xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimd)); Set("0x1011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimdShImm)); Set("00011110xx1xxxxx000110xxxxxxxxxx", AInstEmit.Fdiv_S, typeof(AOpCodeSimdReg)); diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs index 7c285b28d..9ea979ba7 100644 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs +++ b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs @@ -37,6 +37,8 @@ namespace ChocolArm64.Decoder return; } + Extend64 = false; + RegisterSize = Q ? ARegisterSize.SIMD128 : ARegisterSize.SIMD64; diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs index 5782d54bd..52b8e4708 100644 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs +++ b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs @@ -87,6 +87,8 @@ namespace ChocolArm64.Decoder this.SElems = SElems; this.Size = Scale; + Extend64 = false; + WBack = ((OpCode >> 23) & 0x1) != 0; RegisterSize = Q != 0 diff --git a/Ryujinx/Cpu/Instruction/AInstEmitMemory.cs b/Ryujinx/Cpu/Instruction/AInstEmitMemory.cs index ca0c82a37..af7de3ba6 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitMemory.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitMemory.cs @@ -20,7 +20,7 @@ namespace ChocolArm64.Instruction { AOpCodeAdr Op = (AOpCodeAdr)Context.CurrOp; - Context.EmitLdc_I((Op.Position & ~0xfff) + (Op.Imm << 12)); + Context.EmitLdc_I((Op.Position & ~0xfffL) + (Op.Imm << 12)); Context.EmitStintzr(Op.Rd); } diff --git a/Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs b/Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs index e05153d99..d5a0051b5 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs @@ -1,3 +1,4 @@ +using ChocolArm64.Decoder; using ChocolArm64.Memory; using ChocolArm64.Translation; using System; @@ -31,67 +32,107 @@ namespace ChocolArm64.Instruction private static void EmitReadCall(AILEmitterCtx Context, Extension Ext, int Size) { - if (Size < 0 || Size > 4) + bool IsSimd = GetIsSimd(Context); + + string Name = null; + + if (Size < 0 || Size > (IsSimd ? 4 : 3)) { throw new ArgumentOutOfRangeException(nameof(Size)); } - string Name = null; - - switch (Size) - { - case 0: Name = nameof(AMemory.ReadByte); break; - case 1: Name = nameof(AMemory.ReadUInt16); break; - case 2: Name = nameof(AMemory.ReadUInt32); break; - case 3: Name = nameof(AMemory.ReadUInt64); break; - case 4: Name = nameof(AMemory.ReadVector128); break; - } - - Context.EmitCall(typeof(AMemory), Name); - - if (Ext == Extension.Sx32 || - Ext == Extension.Sx64) + if (IsSimd) { switch (Size) { - case 0: Context.Emit(OpCodes.Conv_I1); break; - case 1: Context.Emit(OpCodes.Conv_I2); break; - case 2: Context.Emit(OpCodes.Conv_I4); break; + case 0: Name = nameof(AMemory.ReadVector8); break; + case 1: Name = nameof(AMemory.ReadVector16); break; + case 2: Name = nameof(AMemory.ReadVector32); break; + case 3: Name = nameof(AMemory.ReadVector64); break; + case 4: Name = nameof(AMemory.ReadVector128); break; + } + } + else + { + switch (Size) + { + case 0: Name = nameof(AMemory.ReadByte); break; + case 1: Name = nameof(AMemory.ReadUInt16); break; + case 2: Name = nameof(AMemory.ReadUInt32); break; + case 3: Name = nameof(AMemory.ReadUInt64); break; } } - if (Size < 3) + Context.EmitCall(typeof(AMemory), Name); + + if (!IsSimd) { - Context.Emit(Ext == Extension.Sx64 - ? OpCodes.Conv_I8 - : OpCodes.Conv_U8); + if (Ext == Extension.Sx32 || + Ext == Extension.Sx64) + { + switch (Size) + { + case 0: Context.Emit(OpCodes.Conv_I1); break; + case 1: Context.Emit(OpCodes.Conv_I2); break; + case 2: Context.Emit(OpCodes.Conv_I4); break; + } + } + + if (Size < 3) + { + Context.Emit(Ext == Extension.Sx64 + ? OpCodes.Conv_I8 + : OpCodes.Conv_U8); + } } } public static void EmitWriteCall(AILEmitterCtx Context, int Size) { - if (Size < 0 || Size > 4) + bool IsSimd = GetIsSimd(Context); + + string Name = null; + + if (Size < 0 || Size > (IsSimd ? 4 : 3)) { throw new ArgumentOutOfRangeException(nameof(Size)); - } + } - if (Size < 3) + if (Size < 3 && !IsSimd) { Context.Emit(OpCodes.Conv_I4); } - string Name = null; - - switch (Size) + if (IsSimd) { - case 0: Name = nameof(AMemory.WriteByte); break; - case 1: Name = nameof(AMemory.WriteUInt16); break; - case 2: Name = nameof(AMemory.WriteUInt32); break; - case 3: Name = nameof(AMemory.WriteUInt64); break; - case 4: Name = nameof(AMemory.WriteVector128); break; + switch (Size) + { + case 0: Name = nameof(AMemory.WriteVector8); break; + case 1: Name = nameof(AMemory.WriteVector16); break; + case 2: Name = nameof(AMemory.WriteVector32); break; + case 3: Name = nameof(AMemory.WriteVector64); break; + case 4: Name = nameof(AMemory.WriteVector128); break; + } + } + else + { + switch (Size) + { + case 0: Name = nameof(AMemory.WriteByte); break; + case 1: Name = nameof(AMemory.WriteUInt16); break; + case 2: Name = nameof(AMemory.WriteUInt32); break; + case 3: Name = nameof(AMemory.WriteUInt64); break; + } } Context.EmitCall(typeof(AMemory), Name); } + + private static bool GetIsSimd(AILEmitterCtx Context) + { + return Context.CurrOp is IAOpCodeSimd && + !(Context.CurrOp is AOpCodeSimdMemMs || + Context.CurrOp is AOpCodeSimdMemSs); + } } } \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitScalar.cs b/Ryujinx/Cpu/Instruction/AInstEmitScalar.cs deleted file mode 100644 index cb97d40f8..000000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitScalar.cs +++ /dev/null @@ -1,745 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection; -using System.Reflection.Emit; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Addp_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - Context.EmitLdvec(Op.Rn); - Context.EmitLdc_I4(Op.Size); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Addp_S)); - - Context.EmitStvec(Op.Rd); - } - - public static void Dup_S(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - Context.EmitLdvec(Op.Rn); - Context.EmitLdc_I4(Op.DstIndex); - Context.EmitLdc_I4(Op.Size); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Dup_S)); - - Context.EmitStvec(Op.Rd); - } - - public static void Fabs_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - - MethodInfo MthdInfo; - - if (Op.Size == 0) - { - MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Abs), new Type[] { typeof(float) }); - } - else if (Op.Size == 1) - { - MthdInfo = typeof(Math).GetMethod(nameof(Math.Abs), new Type[] { typeof(double) }); - } - else - { - throw new InvalidOperationException(); - } - - Context.EmitCall(MthdInfo); - - Context.EmitStvecsf(Op.Rd); - } - - public static void Fadd_S(AILEmitterCtx Context) => EmitScalarOp(Context, OpCodes.Add); - - public static void Fccmp_S(AILEmitterCtx Context) - { - AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; - - AILLabel LblTrue = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - Context.EmitCondBranch(LblTrue, Op.Cond); - - //TODO: Share this logic with Ccmp. - Context.EmitLdc_I4((Op.NZCV >> 0) & 1); - - Context.EmitStflg((int)APState.VBit); - - Context.EmitLdc_I4((Op.NZCV >> 1) & 1); - - Context.EmitStflg((int)APState.CBit); - - Context.EmitLdc_I4((Op.NZCV >> 2) & 1); - - Context.EmitStflg((int)APState.ZBit); - - Context.EmitLdc_I4((Op.NZCV >> 3) & 1); - - Context.EmitStflg((int)APState.NBit); - - Context.Emit(OpCodes.Br_S, LblEnd); - - Context.MarkLabel(LblTrue); - - Fcmp_S(Context); - - Context.MarkLabel(LblEnd); - } - - public static void Fcmp_S(AILEmitterCtx Context) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false; - - //todo - //Context.TryMarkCondWithoutCmp(); - - void EmitLoadOpers() - { - Context.EmitLdvecsf(Op.Rn); - - if (CmpWithZero) - { - EmitLdcImmF(Context, 0, Op.Size); - } - else - { - Context.EmitLdvecsf(Op.Rm); - } - } - - //Z = Rn == Rm - EmitLoadOpers(); - - Context.Emit(OpCodes.Ceq); - Context.Emit(OpCodes.Dup); - - Context.EmitStflg((int)APState.ZBit); - - //C = Rn >= Rm - EmitLoadOpers(); - - Context.Emit(OpCodes.Cgt); - Context.Emit(OpCodes.Or); - - Context.EmitStflg((int)APState.CBit); - - //N = Rn < Rm - EmitLoadOpers(); - - Context.Emit(OpCodes.Clt); - - Context.EmitStflg((int)APState.NBit); - - //Handle NaN case. If any number is NaN, then NZCV = 0011. - AILLabel LblNotNaN = new AILLabel(); - - if (CmpWithZero) - { - EmitNaNCheck(Context, Op.Rn); - } - else - { - EmitNaNCheck(Context, Op.Rn); - EmitNaNCheck(Context, Op.Rm); - - Context.Emit(OpCodes.Or); - } - - Context.Emit(OpCodes.Brfalse_S, LblNotNaN); - - Context.EmitLdc_I4(1); - Context.EmitLdc_I4(1); - - Context.EmitStflg((int)APState.CBit); - Context.EmitStflg((int)APState.VBit); - - Context.MarkLabel(LblNotNaN); - } - - public static void Fcmpe_S(AILEmitterCtx Context) - { - //TODO: Raise exception if value is NaN, how to handle exceptions? - Fcmp_S(Context); - } - - public static void Fcsel_S(AILEmitterCtx Context) - { - AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; - - AILLabel LblTrue = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - Context.EmitCondBranch(LblTrue, Op.Cond); - Context.EmitLdvecsf(Op.Rm); - Context.EmitStvecsf(Op.Rd); - - Context.Emit(OpCodes.Br_S, LblEnd); - - Context.MarkLabel(LblTrue); - - Context.EmitLdvecsf(Op.Rn); - Context.EmitStvecsf(Op.Rd); - - Context.MarkLabel(LblEnd); - } - - public static void Fcvt_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - - EmitFloatCast(Context, Op.Opc); - - Context.EmitStvecsf(Op.Rd); - } - - public static void Fcvtms_S(AILEmitterCtx Context) => EmitMathOpCvtToInt(Context, nameof(Math.Floor)); - public static void Fcvtps_S(AILEmitterCtx Context) => EmitMathOpCvtToInt(Context, nameof(Math.Ceiling)); - - public static void Fcvtzs_S(AILEmitterCtx Context) => EmitFcvtz_(Context, true); - public static void Fcvtzu_S(AILEmitterCtx Context) => EmitFcvtz_(Context, false); - - private static void EmitFcvtz_(AILEmitterCtx Context, bool Signed) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - - if (Signed) - { - EmitCvtToInt(Context, Op.Size); - } - else - { - EmitCvtToUInt(Context, Op.Size); - } - - Context.EmitStintzr(Op.Rd); - } - - public static void Fcvtzs_Fix(AILEmitterCtx Context) => EmitFcvtz__Fix(Context, true); - public static void Fcvtzu_Fix(AILEmitterCtx Context) => EmitFcvtz__Fix(Context, false); - - private static void EmitFcvtz__Fix(AILEmitterCtx Context, bool Signed) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - - EmitLdcImmF(Context, 1L << Op.FBits, Op.Size); - - Context.Emit(OpCodes.Mul); - - if (Signed) - { - EmitCvtToInt(Context, Op.Size); - } - else - { - EmitCvtToUInt(Context, Op.Size); - } - - Context.EmitStintzr(Op.Rd); - } - - public static void Fdiv_S(AILEmitterCtx Context) => EmitScalarOp(Context, OpCodes.Div); - - public static void Fmadd_S(AILEmitterCtx Context) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - Context.EmitLdvecsf(Op.Ra); - Context.EmitLdvecsf(Op.Rn); - Context.EmitLdvecsf(Op.Rm); - - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Add); - - Context.EmitStvecsf(Op.Rd); - } - - public static void Fmax_S(AILEmitterCtx Context) => EmitMathOp3(Context, nameof(Math.Max)); - public static void Fmin_S(AILEmitterCtx Context) => EmitMathOp3(Context, nameof(Math.Min)); - - public static void Fmaxnm_S(AILEmitterCtx Context) => EmitMathOp3(Context, nameof(Math.Max)); - public static void Fminnm_S(AILEmitterCtx Context) => EmitMathOp3(Context, nameof(Math.Min)); - - public static void Fmov_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - Context.EmitStvecsf(Op.Rd); - } - - public static void Fmov_Si(AILEmitterCtx Context) - { - AOpCodeSimdFmov Op = (AOpCodeSimdFmov)Context.CurrOp; - - Context.EmitLdc_I8(Op.Imm); - Context.EmitLdc_I4(0); - Context.EmitLdc_I4(Op.Size + 2); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Fmov_S)); - - Context.EmitStvec(Op.Rd); - } - - public static void Fmov_Ftoi(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdvecsi(Op.Rn); - Context.EmitStintzr(Op.Rd); - } - - public static void Fmov_Itof(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - Context.EmitStvecsi(Op.Rd); - } - - public static void Fmov_Ftoi1(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdvec(Op.Rn); - Context.EmitLdc_I4(1); - Context.EmitLdc_I4(3); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec)); - - Context.EmitStintzr(Op.Rd); - } - - public static void Fmov_Itof1(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - Context.EmitLdc_I4(1); - Context.EmitLdc_I4(3); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Fmov_S)); - - Context.EmitStvec(Op.Rd); - } - - public static void Fmsub_S(AILEmitterCtx Context) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - Context.EmitLdvecsf(Op.Ra); - Context.EmitLdvecsf(Op.Rn); - - Context.Emit(OpCodes.Neg); - - Context.EmitLdvecsf(Op.Rm); - - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Sub); - - Context.EmitStvecsf(Op.Rd); - } - - public static void Fmul_S(AILEmitterCtx Context) => EmitScalarOp(Context, OpCodes.Mul); - - public static void Fneg_S(AILEmitterCtx Context) => EmitScalarOp(Context, OpCodes.Neg); - - public static void Fnmul_S(AILEmitterCtx Context) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - Context.EmitLdvecsf(Op.Rm); - - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Neg); - - Context.EmitStvecsf(Op.Rd); - } - - public static void Frinta_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - Context.EmitLdc_I4((int)MidpointRounding.AwayFromZero); - - MethodInfo MthdInfo; - - if (Op.Size == 0) - { - Type[] Types = new Type[] { typeof(float), typeof(MidpointRounding) }; - - MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types); - } - else if (Op.Size == 1) - { - Type[] Types = new Type[] { typeof(double), typeof(MidpointRounding) }; - - MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types); - } - else - { - throw new InvalidOperationException(); - } - - Context.EmitCall(MthdInfo); - - Context.EmitStvecsf(Op.Rd); - } - - public static void Frintm_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - - MethodInfo MthdInfo; - - if (Op.Size == 0) - { - MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Floor), new Type[] { typeof(float) }); - } - else if (Op.Size == 1) - { - MthdInfo = typeof(Math).GetMethod(nameof(Math.Floor), new Type[] { typeof(double) }); - } - else - { - throw new InvalidOperationException(); - } - - Context.EmitCall(MthdInfo); - - Context.EmitStvecsf(Op.Rd); - } - - public static void Fsqrt_S(AILEmitterCtx Context) => EmitMathOp2(Context, nameof(Math.Sqrt)); - - public static void Fsub_S(AILEmitterCtx Context) => EmitScalarOp(Context, OpCodes.Sub); - - public static void Scvtf_Gp(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - EmitFloatCast(Context, Op.Size); - - Context.EmitStvecsf(Op.Rd); - } - - public static void Scvtf_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - Context.EmitLdvecsi(Op.Rn); - - EmitFloatCast(Context, Op.Size); - - Context.EmitStvecsf(Op.Rd); - } - - public static void Shl_S(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - Context.EmitLdvecsi(Op.Rn); - Context.EmitLdc_I4(Op.Imm - (8 << Op.Size)); - - Context.Emit(OpCodes.Shl); - - Context.EmitStvecsi(Op.Rd); - } - - public static void Sshr_S(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - Context.EmitLdvecsi(Op.Rn); - Context.EmitLdc_I4((8 << (Op.Size + 1)) - Op.Imm); - - Context.Emit(OpCodes.Shr); - - Context.EmitStvecsi(Op.Rd); - } - - public static void Sub_S(AILEmitterCtx Context) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - Context.EmitLdvecsi(Op.Rn); - Context.EmitLdvecsi(Op.Rm); - - Context.Emit(OpCodes.Sub); - - Context.EmitStvecsi(Op.Rd); - } - - public static void Ucvtf_Gp(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - Context.Emit(OpCodes.Conv_R_Un); - - EmitFloatCast(Context, Op.Size); - - Context.EmitStvecsf(Op.Rd); - } - - public static void Ucvtf_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - Context.EmitLdvecsi(Op.Rn); - - Context.Emit(OpCodes.Conv_R_Un); - - EmitFloatCast(Context, Op.Size); - - Context.EmitStvecsf(Op.Rd); - } - - public static void Umov_S(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - Context.EmitLdvec(Op.Rn); - Context.EmitLdc_I4(Op.DstIndex); - Context.EmitLdc_I4(Op.Size); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec)); - - Context.EmitStintzr(Op.Rd); - } - - private static void EmitScalarOp(AILEmitterCtx Context, OpCode ILOp) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - - //Negate and Not are the only unary operations supported on IL. - //"Not" doesn't work with floats, so we don't need to compare it. - if (ILOp != OpCodes.Neg) - { - Context.EmitLdvecsf(Op.Rm); - } - - Context.Emit(ILOp); - - Context.EmitStvecsf(Op.Rd); - } - - private static void EmitMathOp2(AILEmitterCtx Context, string Name) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - - EmitMathOpCall(Context, Name); - - Context.EmitStvecsf(Op.Rd); - } - - private static void EmitMathOp3(AILEmitterCtx Context, string Name) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - Context.EmitLdvecsf(Op.Rm); - - MethodInfo MthdInfo; - - if (Op.Size == 0) - { - MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float), typeof(float) }); - } - else if (Op.Size == 1) - { - MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double), typeof(double) }); - } - else - { - throw new InvalidOperationException(); - } - - Context.EmitCall(MthdInfo); - - Context.EmitStvecsf(Op.Rd); - } - - public static void EmitMathOpCvtToInt(AILEmitterCtx Context, string Name) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdvecsf(Op.Rn); - - EmitMathOpCall(Context, Name); - - EmitCvtToInt(Context, Op.Size); - - Context.EmitStintzr(Op.Rd); - } - - private static void EmitMathOpCall(AILEmitterCtx Context, string Name) - { - IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; - - MethodInfo MthdInfo; - - if (Op.Size == 0) - { - MthdInfo = typeof(MathF).GetMethod(Name); - } - else if (Op.Size == 1) - { - MthdInfo = typeof(Math).GetMethod(Name); - } - else - { - throw new InvalidOperationException(); - } - - Context.EmitCall(MthdInfo); - } - - private static void EmitCvtToInt(AILEmitterCtx Context, int Size) - { - if (Size < 0 || Size > 1) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.EmitLdc_I4(0); - - if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) - { - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatSingleToInt32)); - } - else /* if (Size == 1) */ - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatDoubleToInt32)); - } - } - else - { - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatSingleToInt64)); - } - else /* if (Size == 1) */ - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatDoubleToInt64)); - } - } - } - - private static void EmitCvtToUInt(AILEmitterCtx Context, int Size) - { - if (Size < 0 || Size > 1) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.EmitLdc_I4(0); - - if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) - { - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatSingleToUInt32)); - } - else /* if (Size == 1) */ - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatDoubleToUInt32)); - } - } - else - { - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatSingleToUInt64)); - } - else /* if (Size == 1) */ - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatDoubleToUInt64)); - } - } - } - - private static void EmitFloatCast(AILEmitterCtx Context, int Size) - { - if (Size == 0) - { - Context.Emit(OpCodes.Conv_R4); - } - else if (Size == 1) - { - Context.Emit(OpCodes.Conv_R8); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - } - - private static void EmitLdcImmF(AILEmitterCtx Context, double ImmF, int Size) - { - if (Size == 0) - { - Context.EmitLdc_R4((float)ImmF); - } - else if (Size == 1) - { - Context.EmitLdc_R8(ImmF); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - } - - private static void EmitNaNCheck(AILEmitterCtx Context, int Index) - { - IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; - - Context.EmitLdvecsf(Index); - - if (Op.Size == 0) - { - Context.EmitCall(typeof(float), nameof(float.IsNaN)); - } - else if (Op.Size == 1) - { - Context.EmitCall(typeof(double), nameof(double.IsNaN)); - } - else - { - throw new InvalidOperationException(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs deleted file mode 100644 index f4f9aa1a9..000000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs +++ /dev/null @@ -1,1370 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection; -using System.Reflection.Emit; - -using static ChocolArm64.Instruction.AInstEmitMemoryHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Add_V(AILEmitterCtx Context) - { - EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.Add)); - } - - public static void Addp_V(AILEmitterCtx Context) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - int Elems = Bytes >> Op.Size; - int Half = Elems >> 1; - - for (int Index = 0; Index < Elems; Index++) - { - int Elem = (Index & (Half - 1)) << 1; - - EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 0, Op.Size); - EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 1, Op.Size); - - Context.Emit(OpCodes.Add); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void Addv_V(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - int Results = 0; - - for (int Size = Op.Size; Size < 4; Size++) - { - for (int Index = 0; Index < (Bytes >> Size); Index += 2) - { - EmitVectorExtractZx(Context, Op.Rn, Index + 0, Size); - EmitVectorExtractZx(Context, Op.Rn, Index + 1, Size); - - Context.Emit(OpCodes.Add); - - Results++; - } - } - - while (--Results > 0) - { - Context.Emit(OpCodes.Add); - } - - EmitVectorZeroLower(Context, Op.Rd); - EmitVectorZeroUpper(Context, Op.Rd); - - EmitVectorInsert(Context, Op.Rd, 0, Op.Size); - } - - public static void And_V(AILEmitterCtx Context) - { - EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.And)); - } - - public static void Bic_V(AILEmitterCtx Context) - { - EmitVectorBinaryZx(Context, () => - { - Context.Emit(OpCodes.Not); - Context.Emit(OpCodes.And); - }); - } - - public static void Bic_Vi(AILEmitterCtx Context) - { - EmitVectorImmBinary(Context, () => - { - Context.Emit(OpCodes.Not); - Context.Emit(OpCodes.And); - }); - } - - public static void Bsl_V(AILEmitterCtx Context) - { - EmitVectorTernaryZx(Context, () => - { - Context.EmitSttmp(); - Context.EmitLdtmp(); - - Context.Emit(OpCodes.Xor); - Context.Emit(OpCodes.And); - - Context.EmitLdtmp(); - - Context.Emit(OpCodes.Xor); - }); - } - - public static void Cmeq_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Beq_S); - } - - public static void Cmge_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Bge_S); - } - - public static void Cmgt_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Bgt_S); - } - - public static void Cmhi_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Bgt_Un_S); - } - - public static void Cmhs_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Bge_Un_S); - } - - public static void Cmle_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Ble_S); - } - - public static void Cmlt_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Blt_S); - } - - public static void Cnt_V(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 16 : 8; - - for (int Index = 0; Index < Elems; Index++) - { - EmitVectorExtractZx(Context, Op.Rn, Index, 0); - - Context.Emit(OpCodes.Conv_U1); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountSetBits8)); - - Context.Emit(OpCodes.Conv_U8); - - EmitVectorInsert(Context, Op.Rd, Index, 0); - } - } - - public static void Dup_Gp(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - Context.EmitLdintzr(Op.Rn); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void Dup_V(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void Eor_V(AILEmitterCtx Context) - { - EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.Xor)); - } - - public static void Fadd_V(AILEmitterCtx Context) - { - EmitVectorBinaryF(Context, () => Context.Emit(OpCodes.Add)); - } - - public static void Fcvtzs_V(AILEmitterCtx Context) - { - EmitVectorFcvt(Context, Signed: true); - } - - public static void Fcvtzu_V(AILEmitterCtx Context) - { - EmitVectorFcvt(Context, Signed: false); - } - - public static void Fmla_V(AILEmitterCtx Context) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - EmitVectorTernaryF(Context, () => - { - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Add); - }); - } - - public static void Fmla_Ve(AILEmitterCtx Context) - { - EmitVectorTernaryByElemF(Context, () => - { - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Add); - }); - } - - public static void Fmov_V(AILEmitterCtx Context) - { - AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; - - Context.EmitLdc_I8(Op.Imm); - Context.EmitLdc_I4(Op.Size + 2); - - ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Dup_Gp64), - nameof(ASoftFallback.Dup_Gp128)); - - Context.EmitStvec(Op.Rd); - } - - public static void Fmul_V(AILEmitterCtx Context) - { - EmitVectorBinaryF(Context, () => Context.Emit(OpCodes.Mul)); - } - - public static void Fmul_Ve(AILEmitterCtx Context) - { - EmitVectorBinaryByElemF(Context, () => Context.Emit(OpCodes.Mul)); - } - - public static void Fsub_V(AILEmitterCtx Context) - { - EmitVectorBinaryF(Context, () => Context.Emit(OpCodes.Sub)); - } - - public static void Ins_Gp(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size); - } - - public static void Ins_V(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - EmitVectorExtractZx(Context, Op.Rn, Op.SrcIndex, Op.Size); - - EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size); - } - - 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) - { - EmitVectorTernaryZx(Context, () => - { - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Add); - }); - } - - public static void Movi_V(AILEmitterCtx Context) - { - EmitVectorImmUnary(Context, () => { }); - } - - public static void Mul_V(AILEmitterCtx Context) - { - EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.Mul)); - } - - public static void Mvni_V(AILEmitterCtx Context) - { - EmitVectorImmUnary(Context, () => Context.Emit(OpCodes.Not)); - } - - public static void Neg_V(AILEmitterCtx Context) - { - EmitVectorUnarySx(Context, () => Context.Emit(OpCodes.Neg)); - } - - public static void Not_V(AILEmitterCtx Context) - { - EmitVectorUnaryZx(Context, () => Context.Emit(OpCodes.Not)); - } - - public static void Orr_V(AILEmitterCtx Context) - { - EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.Or)); - } - - public static void Orr_Vi(AILEmitterCtx Context) - { - EmitVectorImmBinary(Context, () => Context.Emit(OpCodes.Or)); - } - - public static void Saddw_V(AILEmitterCtx Context) - { - EmitVectorWidenBinarySx(Context, () => Context.Emit(OpCodes.Add)); - } - - public static void Scvtf_V(AILEmitterCtx Context) - { - EmitVectorCvtf(Context, Signed: true); - } - - public static void Shl_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = Op.Imm - (8 << Op.Size); - - EmitVectorShImmBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift); - } - - public static void Shrn_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = (8 << (Op.Size + 1)) - Op.Imm; - - EmitVectorShImmNarrowBinaryZx(Context, () => Context.Emit(OpCodes.Shr_Un), Shift); - } - - public static void Smax_V(AILEmitterCtx Context) - { - Type[] Types = new Type[] { typeof(long), typeof(long) }; - - MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types); - - EmitVectorBinarySx(Context, () => Context.EmitCall(MthdInfo)); - } - - public static void Smin_V(AILEmitterCtx Context) - { - Type[] Types = new Type[] { typeof(long), typeof(long) }; - - MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types); - - EmitVectorBinarySx(Context, () => Context.EmitCall(MthdInfo)); - } - - public static void Sshl_V(AILEmitterCtx Context) - { - EmitVectorShl(Context, Signed: true); - } - - public static void Sshll_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = Op.Imm - (8 << Op.Size); - - EmitVectorShImmWidenBinarySx(Context, () => Context.Emit(OpCodes.Shl), Shift); - } - - public static void Sshr_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = (8 << (Op.Size + 1)) - Op.Imm; - - EmitVectorShImmBinarySx(Context, () => Context.Emit(OpCodes.Shr), Shift); - } - - public static void St__Vms(AILEmitterCtx Context) - { - EmitSimdMemMs(Context, IsLoad: false); - } - - public static void St__Vss(AILEmitterCtx Context) - { - EmitSimdMemSs(Context, IsLoad: false); - } - - public static void Sub_V(AILEmitterCtx Context) - { - EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.Sub)); - } - - public static void Tbl_V(AILEmitterCtx Context) - { - AOpCodeSimdTbl Op = (AOpCodeSimdTbl)Context.CurrOp; - - Context.EmitLdvec(Op.Rm); - - for (int Index = 0; Index < Op.Size; Index++) - { - Context.EmitLdvec((Op.Rn + Index) & 0x1f); - } - - switch (Op.Size) - { - case 1: ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Tbl1_V64), - nameof(ASoftFallback.Tbl1_V128)); break; - - case 2: ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Tbl2_V64), - nameof(ASoftFallback.Tbl2_V128)); break; - - case 3: ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Tbl3_V64), - nameof(ASoftFallback.Tbl3_V128)); break; - - case 4: ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Tbl4_V64), - nameof(ASoftFallback.Tbl4_V128)); break; - - default: throw new InvalidOperationException(); - } - - Context.EmitStvec(Op.Rd); - } - - public static void Uaddlv_V(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); - - for (int Index = 1; Index < (Bytes >> Op.Size); Index++) - { - EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); - - Context.Emit(OpCodes.Add); - } - - EmitVectorZeroLower(Context, Op.Rd); - EmitVectorZeroUpper(Context, Op.Rd); - - EmitVectorInsert(Context, Op.Rd, 0, Op.Size); - } - - public static void Uaddw_V(AILEmitterCtx Context) - { - EmitVectorWidenBinaryZx(Context, () => Context.Emit(OpCodes.Add)); - } - - public static void Ucvtf_V(AILEmitterCtx Context) - { - EmitVectorCvtf(Context, Signed: false); - } - - public static void Ushl_V(AILEmitterCtx Context) - { - EmitVectorShl(Context, Signed: false); - } - - public static void Ushll_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = Op.Imm - (8 << Op.Size); - - EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift); - } - - public static void Ushr_V(AILEmitterCtx Context) - { - EmitVectorShr(Context, ShrFlags.None); - } - - public static void Usra_V(AILEmitterCtx Context) - { - EmitVectorShr(Context, ShrFlags.Accumulate); - } - - [Flags] - private enum ShrFlags - { - None = 0, - Signed = 1 << 0, - Rounding = 1 << 1, - Accumulate = 1 << 2 - } - - private static void EmitVectorShr(AILEmitterCtx Context, ShrFlags Flags) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = (8 << (Op.Size + 1)) - Op.Imm; - - if (Flags.HasFlag(ShrFlags.Accumulate)) - { - Action Emit = () => - { - Context.EmitLdc_I4(Shift); - - Context.Emit(OpCodes.Shr_Un); - Context.Emit(OpCodes.Add); - }; - - EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false); - } - else - { - EmitVectorUnaryZx(Context, () => - { - Context.EmitLdc_I4(Shift); - - Context.Emit(OpCodes.Shr_Un); - }); - } - } - - public static void Uzp1_V(AILEmitterCtx Context) - { - EmitVectorUnzip(Context, Part: 0); - } - - public static void Uzp2_V(AILEmitterCtx Context) - { - EmitVectorUnzip(Context, Part: 1); - } - - private static void EmitVectorUnzip(AILEmitterCtx Context, int Part) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - int Elems = Bytes >> Op.Size; - int Half = Elems >> 1; - - for (int Index = 0; Index < Elems; Index++) - { - int Elem = Part + ((Index & (Half - 1)) << 1); - - EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem, Op.Size); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void Xtn_V(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Elems = 8 >> Op.Size; - - int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; - - for (int Index = 0; Index < Elems; Index++) - { - EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1); - - EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size); - } - - if (Part == 0) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad) - { - AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)Context.CurrOp; - - int Offset = 0; - - for (int Rep = 0; Rep < Op.Reps; Rep++) - for (int Elem = 0; Elem < Op.Elems; Elem++) - for (int SElem = 0; SElem < Op.SElems; SElem++) - { - int Rtt = (Op.Rt + Rep + SElem) & 0x1f; - - if (IsLoad) - { - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdint(Op.Rn); - Context.EmitLdc_I8(Offset); - - Context.Emit(OpCodes.Add); - - EmitReadZxCall(Context, Op.Size); - - EmitVectorInsert(Context, Rtt, Elem, Op.Size); - - if (Op.RegisterSize == ARegisterSize.SIMD64 && Elem == Op.Elems - 1) - { - EmitVectorZeroUpper(Context, Rtt); - } - } - else - { - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdint(Op.Rn); - Context.EmitLdc_I8(Offset); - - Context.Emit(OpCodes.Add); - - EmitVectorExtractZx(Context, Rtt, Elem, Op.Size); - - EmitWriteCall(Context, Op.Size); - } - - Offset += 1 << Op.Size; - } - - if (Op.WBack) - { - EmitSimdMemWBack(Context, Offset); - } - } - - 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.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdint(Op.Rn); - Context.EmitLdc_I8(Offset); - - Context.Emit(OpCodes.Add); - - EmitReadZxCall(Context, Op.Size); - - EmitVectorInsert(Context, Rt, Op.Index, Op.Size); - - 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); - - EmitVectorExtractZx(Context, Rt, Op.Index, Op.Size); - - EmitWriteCall(Context, Op.Size); - } - - Offset += 1 << Op.Size; - } - - if (Op.WBack) - { - EmitSimdMemWBack(Context, Offset); - } - } - - private static void EmitSimdMemWBack(AILEmitterCtx Context, int Offset) - { - AOpCodeMemReg Op = (AOpCodeMemReg)Context.CurrOp; - - 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 EmitVectorCmp(AILEmitterCtx Context, OpCode ILOp) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size)); - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size); - - if (Op is AOpCodeSimdReg BinOp) - { - EmitVectorExtractSx(Context, BinOp.Rm, Index, Op.Size); - } - else - { - Context.EmitLdc_I8(0); - } - - AILLabel LblTrue = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - Context.Emit(ILOp, LblTrue); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0); - - Context.Emit(OpCodes.Br_S, LblEnd); - - Context.MarkLabel(LblTrue); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask); - - Context.MarkLabel(LblEnd); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitVectorShl(AILEmitterCtx Context, bool Signed) - { - //This instruction shifts the value on vector A by the number of bits - //specified on the signed, lower 8 bits of vector B. If the shift value - //is greater or equal to the data size of each lane, then the result is zero. - //Additionally, negative shifts produces right shifts by the negated shift value. - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int MaxShift = 8 << Op.Size; - - Action Emit = () => - { - AILLabel LblShl = new AILLabel(); - AILLabel LblZero = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - void EmitShift(OpCode ILOp) - { - Context.Emit(OpCodes.Dup); - - Context.EmitLdc_I4(MaxShift); - - Context.Emit(OpCodes.Bge_S, LblZero); - Context.Emit(ILOp); - Context.Emit(OpCodes.Br_S, LblEnd); - } - - Context.Emit(OpCodes.Conv_I1); - Context.Emit(OpCodes.Dup); - - Context.EmitLdc_I4(0); - - Context.Emit(OpCodes.Bge_S, LblShl); - Context.Emit(OpCodes.Neg); - - EmitShift(Signed - ? OpCodes.Shr - : OpCodes.Shr_Un); - - Context.MarkLabel(LblShl); - - EmitShift(OpCodes.Shl); - - Context.MarkLabel(LblZero); - - Context.Emit(OpCodes.Pop); - Context.Emit(OpCodes.Pop); - - Context.EmitLdc_I8(0); - - Context.MarkLabel(LblEnd); - }; - - if (Signed) - { - EmitVectorBinarySx(Context, Emit); - } - else - { - EmitVectorBinaryZx(Context, Emit); - } - } - - private static void EmitVectorFcvt(AILEmitterCtx Context, bool Signed) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int SizeF = Op.Size & 1; - int SizeI = SizeF + 2; - - int FBits = GetFBits(Context); - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> SizeI); Index++) - { - EmitVectorExtractF(Context, Op.Rn, Index, SizeF); - - Context.EmitLdc_I4(FBits); - - if (SizeF == 0) - { - ASoftFallback.EmitCall(Context, Signed - ? nameof(ASoftFallback.SatSingleToInt32) - : nameof(ASoftFallback.SatSingleToUInt32)); - } - else if (SizeF == 1) - { - ASoftFallback.EmitCall(Context, Signed - ? nameof(ASoftFallback.SatDoubleToInt64) - : nameof(ASoftFallback.SatDoubleToUInt64)); - } - - EmitVectorInsert(Context, Op.Rd, Index, SizeI); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitVectorCvtf(AILEmitterCtx Context, bool Signed) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int SizeF = Op.Size & 1; - int SizeI = SizeF + 2; - - int FBits = GetFBits(Context); - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> SizeI); Index++) - { - EmitVectorExtract(Context, Op.Rn, Index, SizeI, Signed); - - Context.EmitLdc_I4(FBits); - - if (SizeF == 0) - { - Context.Emit(OpCodes.Conv_I4); - - ASoftFallback.EmitCall(Context, Signed - ? nameof(ASoftFallback.Int32ToSingle) - : nameof(ASoftFallback.UInt32ToSingle)); - } - else if (SizeF == 1) - { - ASoftFallback.EmitCall(Context, Signed - ? nameof(ASoftFallback.Int64ToDouble) - : nameof(ASoftFallback.UInt64ToDouble)); - } - - EmitVectorInsertF(Context, Op.Rd, Index, SizeF); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static int GetFBits(AILEmitterCtx Context) - { - if (Context.CurrOp is AOpCodeSimdShImm Op) - { - return (8 << (Op.Size + 1)) - Op.Imm; - } - - return 0; - } - - [Flags] - private enum OperFlags - { - Rd = 1 << 0, - Rn = 1 << 1, - Rm = 1 << 2, - - RnRm = Rn | Rm, - RdRn = Rd | Rn, - RdRnRm = Rd | Rn | Rm - } - - private static void EmitVectorBinaryF(AILEmitterCtx Context, Action Emit) - { - EmitVectorFOp(Context, Emit, OperFlags.RnRm); - } - - private static void EmitVectorTernaryF(AILEmitterCtx Context, Action Emit) - { - EmitVectorFOp(Context, Emit, OperFlags.RdRnRm); - } - - private static void EmitVectorBinaryByElemF(AILEmitterCtx Context, Action Emit) - { - AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; - - EmitVectorFOp(Context, Emit, OperFlags.RnRm, Op.Index); - } - - private static void EmitVectorTernaryByElemF(AILEmitterCtx Context, Action Emit) - { - AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; - - EmitVectorFOp(Context, Emit, OperFlags.RdRnRm, Op.Index); - } - - private static void EmitVectorFOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, int Elem = -1) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int SizeF = Op.Size & 1; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> SizeF + 2); Index++) - { - if (Opers.HasFlag(OperFlags.Rd)) - { - EmitVectorExtractF(Context, Op.Rd, Index, SizeF); - } - - if (Opers.HasFlag(OperFlags.Rn)) - { - EmitVectorExtractF(Context, Op.Rn, Index, SizeF); - } - - if (Opers.HasFlag(OperFlags.Rm)) - { - if (Elem != -1) - { - EmitVectorExtractF(Context, Op.Rm, Elem, SizeF); - } - else - { - EmitVectorExtractF(Context, Op.Rm, Index, SizeF); - } - } - - Emit(); - - EmitVectorInsertF(Context, Op.Rd, Index, SizeF); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitVectorUnarySx(AILEmitterCtx Context, Action Emit) - { - EmitVectorOp(Context, Emit, OperFlags.Rn, true); - } - - private static void EmitVectorBinarySx(AILEmitterCtx Context, Action Emit) - { - EmitVectorOp(Context, Emit, OperFlags.RnRm, true); - } - - private static void EmitVectorUnaryZx(AILEmitterCtx Context, Action Emit) - { - EmitVectorOp(Context, Emit, OperFlags.Rn, false); - } - - private static void EmitVectorBinaryZx(AILEmitterCtx Context, Action Emit) - { - EmitVectorOp(Context, Emit, OperFlags.RnRm, false); - } - - private static void EmitVectorTernaryZx(AILEmitterCtx Context, Action Emit) - { - EmitVectorOp(Context, Emit, OperFlags.RdRnRm, false); - } - - private static void EmitVectorOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - if (Opers.HasFlag(OperFlags.Rd)) - { - EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed); - } - - if (Opers.HasFlag(OperFlags.Rn)) - { - EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); - } - - if (Opers.HasFlag(OperFlags.Rm)) - { - EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed); - } - - Emit(); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitVectorImmUnary(AILEmitterCtx Context, Action Emit) - { - EmitVectorImmOp(Context, Emit, false); - } - - private static void EmitVectorImmBinary(AILEmitterCtx Context, Action Emit) - { - EmitVectorImmOp(Context, Emit, true); - } - - private static void EmitVectorImmOp(AILEmitterCtx Context, Action Emit, bool Binary) - { - AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - if (Binary) - { - EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size); - } - - Context.EmitLdc_I8(Op.Imm); - - Emit(); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitVectorShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmBinaryOp(Context, Emit, Imm, true); - } - - private static void EmitVectorShImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmBinaryOp(Context, Emit, Imm, false); - } - - private static void EmitVectorShImmBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); - - Context.EmitLdc_I4(Imm); - - Emit(); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitVectorShImmNarrowBinarySx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, true); - } - - private static void EmitVectorShImmNarrowBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, false); - } - - private static void EmitVectorShImmNarrowBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Elems = 8 >> Op.Size; - - int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; - - for (int Index = 0; Index < Elems; Index++) - { - EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed); - - Context.EmitLdc_I4(Imm); - - Emit(); - - EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size); - } - - if (Part == 0) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitVectorShImmWidenBinarySx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, true); - } - - private static void EmitVectorShImmWidenBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, false); - } - - private static void EmitVectorShImmWidenBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Elems = 8 >> Op.Size; - - int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; - - for (int Index = 0; Index < Elems; Index++) - { - EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed); - - Context.EmitLdc_I4(Imm); - - Emit(); - - EmitVectorInsertTmp(Context, Index, Op.Size + 1); - } - - Context.EmitLdvectmp(); - Context.EmitStvec(Op.Rd); - } - - private static void EmitVectorWidenBinarySx(AILEmitterCtx Context, Action Emit) - { - EmitVectorWidenBinary(Context, Emit, true); - } - - private static void EmitVectorWidenBinaryZx(AILEmitterCtx Context, Action Emit) - { - EmitVectorWidenBinary(Context, Emit, false); - } - - private static void EmitVectorWidenBinary(AILEmitterCtx Context, Action Emit, bool Signed) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int Elems = 8 >> Op.Size; - - int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; - - for (int Index = 0; Index < Elems; Index++) - { - EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed); - EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed); - - Emit(); - - EmitVectorInsertTmp(Context, Index, Op.Size + 1); - } - - Context.EmitLdvectmp(); - Context.EmitStvec(Op.Rd); - } - - private static void EmitVectorExtractF(AILEmitterCtx Context, int Reg, int Index, int Size) - { - Context.EmitLdvec(Reg); - Context.EmitLdc_I4(Index); - - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractSingle)); - } - else if (Size == 1) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractDouble)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - } - - private static void EmitVectorExtractSx(AILEmitterCtx Context, int Reg, int Index, int Size) - { - EmitVectorExtract(Context, Reg, Index, Size, true); - } - - private static void EmitVectorExtractZx(AILEmitterCtx Context, int Reg, int Index, int Size) - { - EmitVectorExtract(Context, Reg, Index, Size, false); - } - - private static void EmitVectorExtract(AILEmitterCtx Context, int Reg, int Index, int Size, bool Signed) - { - if (Size < 0 || Size > 3) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; - - Context.EmitLdvec(Reg); - Context.EmitLdc_I4(Index); - Context.EmitLdc_I4(Size); - - ASoftFallback.EmitCall(Context, Signed - ? nameof(ASoftFallback.ExtractSVec) - : nameof(ASoftFallback.ExtractVec)); - } - - private static void EmitVectorZeroLower(AILEmitterCtx Context, int Rd) - { - EmitVectorInsert(Context, Rd, 0, 3, 0); - } - - private static void EmitVectorZeroUpper(AILEmitterCtx Context, int Rd) - { - EmitVectorInsert(Context, Rd, 1, 3, 0); - } - - private static void EmitVectorInsertF(AILEmitterCtx Context, int Reg, int Index, int Size) - { - Context.EmitLdvec(Reg); - Context.EmitLdc_I4(Index); - - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertSingle)); - } - else if (Size == 1) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertDouble)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.EmitStvec(Reg); - } - - private static void EmitVectorInsertTmp(AILEmitterCtx Context, int Index, int Size) - { - if (Size < 0 || Size > 3) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.EmitLdvectmp(); - Context.EmitLdc_I4(Index); - Context.EmitLdc_I4(Size); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); - - Context.EmitStvectmp(); - } - - private static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size) - { - if (Size < 0 || Size > 3) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.EmitLdvec(Reg); - Context.EmitLdc_I4(Index); - Context.EmitLdc_I4(Size); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); - - Context.EmitStvec(Reg); - } - - private static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value) - { - if (Size < 0 || Size > 3) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.EmitLdvec(Reg); - Context.EmitLdc_I4(Index); - Context.EmitLdc_I4(Size); - Context.EmitLdc_I8(Value); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec)); - - Context.EmitStvec(Reg); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs new file mode 100644 index 000000000..854ba85d4 --- /dev/null +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs @@ -0,0 +1,354 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Add_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Add)); + } + + public static void Addp_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); + EmitVectorExtractZx(Context, Op.Rn, 1, Op.Size); + + Context.Emit(OpCodes.Add); + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void Addp_V(AILEmitterCtx Context) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + int Elems = Bytes >> Op.Size; + int Half = Elems >> 1; + + for (int Index = 0; Index < Elems; Index++) + { + int Elem = (Index & (Half - 1)) << 1; + + EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 0, Op.Size); + EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 1, Op.Size); + + Context.Emit(OpCodes.Add); + + EmitVectorInsertTmp(Context, Index, Op.Size); + } + + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void Addv_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); + + for (int Index = 1; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); + + Context.Emit(OpCodes.Add); + } + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void Cnt_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 16 : 8; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Index, 0); + + Context.Emit(OpCodes.Conv_U1); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountSetBits8)); + + Context.Emit(OpCodes.Conv_U8); + + EmitVectorInsert(Context, Op.Rd, Index, 0); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void Fabs_S(AILEmitterCtx Context) + { + EmitScalarUnaryOpF(Context, () => + { + EmitUnaryMathCall(Context, nameof(Math.Abs)); + }); + } + + public static void Fadd_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Add)); + } + + public static void Fadd_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Add)); + } + + public static void Fdiv_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Div)); + } + + public static void Fmadd_S(AILEmitterCtx Context) + { + EmitScalarTernaryRaOpF(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Add); + }); + } + + public static void Fmax_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => + { + EmitBinaryMathCall(Context, nameof(Math.Max)); + }); + } + + public static void Fmin_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => + { + EmitBinaryMathCall(Context, nameof(Math.Min)); + }); + } + + public static void Fmaxnm_S(AILEmitterCtx Context) + { + Fmax_S(Context); + } + + public static void Fminnm_S(AILEmitterCtx Context) + { + Fmin_S(Context); + } + + public static void Fmla_V(AILEmitterCtx Context) + { + EmitVectorTernaryOpF(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Add); + }); + } + + public static void Fmla_Ve(AILEmitterCtx Context) + { + EmitVectorTernaryOpByElemF(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Add); + }); + } + + public static void Fmsub_S(AILEmitterCtx Context) + { + EmitScalarTernaryRaOpF(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Neg); + Context.Emit(OpCodes.Add); + }); + } + + public static void Fmul_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Mul)); + } + + public static void Fmul_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Mul)); + } + + public static void Fmul_Ve(AILEmitterCtx Context) + { + EmitVectorBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul)); + } + + public static void Fneg_S(AILEmitterCtx Context) + { + EmitScalarUnaryOpF(Context, () => Context.Emit(OpCodes.Neg)); + } + + public static void Fnmul_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Neg); + }); + } + + public static void Frinta_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + Context.EmitLdc_I4((int)MidpointRounding.AwayFromZero); + + MethodInfo MthdInfo; + + Type[] Types = new Type[] { null, typeof(MidpointRounding) }; + + Types[0] = Op.Size == 0 + ? typeof(float) + : typeof(double); + + if (Op.Size == 0) + { + MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types); + } + else if (Op.Size == 1) + { + MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types); + } + else + { + throw new InvalidOperationException(); + } + + Context.EmitCall(MthdInfo); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Frintm_S(AILEmitterCtx Context) + { + EmitScalarUnaryOpF(Context, () => + { + EmitUnaryMathCall(Context, nameof(Math.Floor)); + }); + } + + public static void Fsqrt_S(AILEmitterCtx Context) + { + EmitScalarUnaryOpF(Context, () => + { + EmitUnaryMathCall(Context, nameof(Math.Sqrt)); + }); + } + + public static void Fsub_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Sub)); + } + + public static void Fsub_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Sub)); + } + + public static void Mla_V(AILEmitterCtx Context) + { + EmitVectorTernaryOpZx(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Add); + }); + } + + public static void Mul_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul)); + } + + public static void Neg_V(AILEmitterCtx Context) + { + EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg)); + } + + public static void Saddw_V(AILEmitterCtx Context) + { + EmitVectorWidenBinaryOpSx(Context, () => Context.Emit(OpCodes.Add)); + } + + public static void Smax_V(AILEmitterCtx Context) + { + Type[] Types = new Type[] { typeof(long), typeof(long) }; + + MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types); + + EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo)); + } + + public static void Smin_V(AILEmitterCtx Context) + { + Type[] Types = new Type[] { typeof(long), typeof(long) }; + + MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types); + + EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo)); + } + + public static void Sub_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub)); + } + + public static void Sub_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub)); + } + + public static void Uaddlv_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); + + for (int Index = 1; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); + + Context.Emit(OpCodes.Add); + } + + EmitScalarSet(Context, Op.Rd, Op.Size + 1); + } + + public static void Uaddw_V(AILEmitterCtx Context) + { + EmitVectorWidenBinaryOpZx(Context, () => Context.Emit(OpCodes.Add)); + } + } +} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs new file mode 100644 index 000000000..92361fbd3 --- /dev/null +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs @@ -0,0 +1,236 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Cmeq_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Beq_S); + } + + public static void Cmge_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Bge_S); + } + + public static void Cmgt_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Bgt_S); + } + + public static void Cmhi_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Bgt_Un_S); + } + + public static void Cmhs_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Bge_Un_S); + } + + public static void Cmle_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Ble_S); + } + + public static void Cmlt_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Blt_S); + } + + public static void Fccmp_S(AILEmitterCtx Context) + { + AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; + + AILLabel LblTrue = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.EmitCondBranch(LblTrue, Op.Cond); + + //TODO: Share this logic with Ccmp. + Context.EmitLdc_I4((Op.NZCV >> 0) & 1); + + Context.EmitStflg((int)APState.VBit); + + Context.EmitLdc_I4((Op.NZCV >> 1) & 1); + + Context.EmitStflg((int)APState.CBit); + + Context.EmitLdc_I4((Op.NZCV >> 2) & 1); + + Context.EmitStflg((int)APState.ZBit); + + Context.EmitLdc_I4((Op.NZCV >> 3) & 1); + + Context.EmitStflg((int)APState.NBit); + + Context.Emit(OpCodes.Br_S, LblEnd); + + Context.MarkLabel(LblTrue); + + Fcmp_S(Context); + + Context.MarkLabel(LblEnd); + } + + public static void Fcmp_S(AILEmitterCtx Context) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false; + + void EmitLoadOpers() + { + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + if (CmpWithZero) + { + EmitLdcImmF(Context, 0, Op.Size); + } + else + { + EmitVectorExtractF(Context, Op.Rm, 0, Op.Size); + } + } + + //Z = Rn == Rm + EmitLoadOpers(); + + Context.Emit(OpCodes.Ceq); + Context.Emit(OpCodes.Dup); + + Context.EmitStflg((int)APState.ZBit); + + //C = Rn >= Rm + EmitLoadOpers(); + + Context.Emit(OpCodes.Cgt); + Context.Emit(OpCodes.Or); + + Context.EmitStflg((int)APState.CBit); + + //N = Rn < Rm + EmitLoadOpers(); + + Context.Emit(OpCodes.Clt); + + Context.EmitStflg((int)APState.NBit); + + //Handle NaN case. If any number is NaN, then NZCV = 0011. + AILLabel LblNotNaN = new AILLabel(); + + if (CmpWithZero) + { + EmitNaNCheck(Context, Op.Rn); + } + else + { + EmitNaNCheck(Context, Op.Rn); + EmitNaNCheck(Context, Op.Rm); + + Context.Emit(OpCodes.Or); + } + + Context.Emit(OpCodes.Brfalse_S, LblNotNaN); + + Context.EmitLdc_I4(1); + Context.EmitLdc_I4(1); + + Context.EmitStflg((int)APState.CBit); + Context.EmitStflg((int)APState.VBit); + + Context.MarkLabel(LblNotNaN); + } + + public static void Fcmpe_S(AILEmitterCtx Context) + { + Fcmp_S(Context); + } + + private static void EmitLdcImmF(AILEmitterCtx Context, double ImmF, int Size) + { + if (Size == 0) + { + Context.EmitLdc_R4((float)ImmF); + } + else if (Size == 1) + { + Context.EmitLdc_R8(ImmF); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + } + + private static void EmitNaNCheck(AILEmitterCtx Context, int Reg) + { + IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + + EmitVectorExtractF(Context, Reg, 0, Op.Size); + + if (Op.Size == 0) + { + Context.EmitCall(typeof(float), nameof(float.IsNaN)); + } + else if (Op.Size == 1) + { + Context.EmitCall(typeof(double), nameof(double.IsNaN)); + } + else + { + throw new InvalidOperationException(); + } + } + + private static void EmitVectorCmp(AILEmitterCtx Context, OpCode ILOp) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size)); + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size); + + if (Op is AOpCodeSimdReg BinOp) + { + EmitVectorExtractSx(Context, BinOp.Rm, Index, Op.Size); + } + else + { + Context.EmitLdc_I8(0); + } + + AILLabel LblTrue = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.Emit(ILOp, LblTrue); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0); + + Context.Emit(OpCodes.Br_S, LblEnd); + + Context.MarkLabel(LblTrue); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask); + + Context.MarkLabel(LblEnd); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs new file mode 100644 index 000000000..b7a474116 --- /dev/null +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs @@ -0,0 +1,399 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Fcvt_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + EmitFloatCast(Context, Op.Opc); + + EmitScalarSetF(Context, Op.Rd, Op.Opc); + } + + public static void Fcvtms_Gp(AILEmitterCtx Context) + { + EmitFcvt_s_Gp(Context, nameof(Math.Floor)); + } + + public static void Fcvtps_Gp(AILEmitterCtx Context) + { + EmitFcvt_s_Gp(Context, nameof(Math.Ceiling)); + } + + public static void Fcvtzs_Gp(AILEmitterCtx Context) + { + EmitFcvtz__Gp(Context, Signed: true); + } + + public static void Fcvtzs_Gp_Fix(AILEmitterCtx Context) + { + EmitFcvtz__Gp_Fix(Context, Signed: true); + } + + public static void Fcvtzs_V(AILEmitterCtx Context) + { + EmitVectorFcvt(Context, Signed: true); + } + + public static void Fcvtzu_Gp(AILEmitterCtx Context) + { + EmitFcvtz__Gp(Context, Signed: false); + } + + public static void Fcvtzu_Gp_Fix(AILEmitterCtx Context) + { + EmitFcvtz__Gp_Fix(Context, Signed: false); + } + + public static void Fcvtzu_V(AILEmitterCtx Context) + { + EmitVectorFcvt(Context, Signed: false); + } + + public static void Scvtf_Gp(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U4); + } + + EmitFloatCast(Context, Op.Size); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Scvtf_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractSx(Context, Op.Rd, 0, Op.Size + 2); + + EmitFloatCast(Context, Op.Size); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Scvtf_V(AILEmitterCtx Context) + { + EmitVectorCvtf(Context, Signed: true); + } + + public static void Ucvtf_Gp(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U4); + } + + Context.Emit(OpCodes.Conv_R_Un); + + EmitFloatCast(Context, Op.Size); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Ucvtf_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size + 2); + + Context.Emit(OpCodes.Conv_R_Un); + + EmitFloatCast(Context, Op.Size); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Ucvtf_V(AILEmitterCtx Context) + { + EmitVectorCvtf(Context, Signed: false); + } + + private static int GetFBits(AILEmitterCtx Context) + { + if (Context.CurrOp is AOpCodeSimdShImm Op) + { + return GetImmShr(Op); + } + + return 0; + } + + private static void EmitFloatCast(AILEmitterCtx Context, int Size) + { + if (Size == 0) + { + Context.Emit(OpCodes.Conv_R4); + } + else if (Size == 1) + { + Context.Emit(OpCodes.Conv_R8); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + } + + private static void EmitFcvt_s_Gp(AILEmitterCtx Context, string Name) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + EmitUnaryMathCall(Context, Name); + + EmitScalarFcvts(Context, Op.Size, 0); + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U8); + } + + Context.EmitStintzr(Op.Rd); + } + + private static void EmitFcvtz__Gp(AILEmitterCtx Context, bool Signed) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + if (Signed) + { + EmitScalarFcvts(Context, Op.Size, 0); + } + else + { + EmitScalarFcvtu(Context, Op.Size, 0); + } + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U8); + } + + Context.EmitStintzr(Op.Rd); + } + + private static void EmitFcvtz__Gp_Fix(AILEmitterCtx Context, bool Signed) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + if (Signed) + { + EmitScalarFcvts(Context, Op.Size, Op.FBits); + } + else + { + EmitScalarFcvtu(Context, Op.Size, Op.FBits); + } + + Context.EmitStintzr(Op.Rd); + } + + private static void EmitVectorCvtf(AILEmitterCtx Context, bool Signed) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int SizeF = Op.Size & 1; + int SizeI = SizeF + 2; + + int FBits = GetFBits(Context); + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> SizeI); Index++) + { + EmitVectorExtract(Context, Op.Rn, Index, SizeI, Signed); + + if (!Signed) + { + Context.Emit(OpCodes.Conv_R_Un); + } + + Context.Emit(SizeF == 0 + ? OpCodes.Conv_R4 + : OpCodes.Conv_R8); + + EmitI2fFBitsMul(Context, SizeF, FBits); + + EmitVectorInsertF(Context, Op.Rd, Index, SizeF); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + private static void EmitVectorFcvt(AILEmitterCtx Context, bool Signed) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int SizeF = Op.Size & 1; + int SizeI = SizeF + 2; + + int FBits = GetFBits(Context); + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> SizeI); Index++) + { + EmitVectorExtractF(Context, Op.Rn, Index, SizeF); + + EmitF2iFBitsMul(Context, SizeF, FBits); + + if (SizeF == 0) + { + ASoftFallback.EmitCall(Context, Signed + ? nameof(ASoftFallback.SatF32ToS32) + : nameof(ASoftFallback.SatF32ToU32)); + } + else /* if (SizeF == 1) */ + { + ASoftFallback.EmitCall(Context, Signed + ? nameof(ASoftFallback.SatF64ToS64) + : nameof(ASoftFallback.SatF64ToU64)); + } + + EmitVectorInsert(Context, Op.Rd, Index, SizeI); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + private static void EmitScalarFcvts(AILEmitterCtx Context, int Size, int FBits) + { + if (Size < 0 || Size > 1) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + EmitF2iFBitsMul(Context, Size, FBits); + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToS32)); + } + else /* if (Size == 1) */ + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToS32)); + } + } + else + { + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToS64)); + } + else /* if (Size == 1) */ + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToS64)); + } + } + } + + private static void EmitScalarFcvtu(AILEmitterCtx Context, int Size, int FBits) + { + if (Size < 0 || Size > 1) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + EmitF2iFBitsMul(Context, Size, FBits); + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToU32)); + } + else /* if (Size == 1) */ + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToU32)); + } + } + else + { + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToU64)); + } + else /* if (Size == 1) */ + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToU64)); + } + } + } + + private static void EmitF2iFBitsMul(AILEmitterCtx Context, int Size, int FBits) + { + if (FBits != 0) + { + if (Size == 0) + { + Context.EmitLdc_R4(MathF.Pow(2, FBits)); + } + else if (Size == 1) + { + Context.EmitLdc_R8(Math.Pow(2, FBits)); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.Emit(OpCodes.Mul); + } + } + + private static void EmitI2fFBitsMul(AILEmitterCtx Context, int Size, int FBits) + { + if (FBits != 0) + { + if (Size == 0) + { + Context.EmitLdc_R4(1f / MathF.Pow(2, FBits)); + } + else if (Size == 1) + { + Context.EmitLdc_R8(1 / Math.Pow(2, FBits)); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.Emit(OpCodes.Mul); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs new file mode 100644 index 000000000..0149fd2e3 --- /dev/null +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs @@ -0,0 +1,508 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection; + +namespace ChocolArm64.Instruction +{ + static class AInstEmitSimdHelper + { + [Flags] + public enum OperFlags + { + Rd = 1 << 0, + Rn = 1 << 1, + Rm = 1 << 2, + Ra = 1 << 3, + + RnRm = Rn | Rm, + RdRn = Rd | Rn, + RaRnRm = Ra | Rn | Rm, + RdRnRm = Rd | Rn | Rm + } + + public static int GetImmShl(AOpCodeSimdShImm Op) + { + return Op.Imm - (8 << Op.Size); + } + + public static int GetImmShr(AOpCodeSimdShImm Op) + { + return (8 << (Op.Size + 1)) - Op.Imm; + } + + public static void EmitUnaryMathCall(AILEmitterCtx Context, string Name) + { + IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + + MethodInfo MthdInfo; + + if (Op.Size == 0) + { + MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float) }); + } + else if (Op.Size == 1) + { + MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double) }); + } + else + { + throw new InvalidOperationException(); + } + + Context.EmitCall(MthdInfo); + } + + public static void EmitBinaryMathCall(AILEmitterCtx Context, string Name) + { + IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + + MethodInfo MthdInfo; + + if (Op.Size == 0) + { + MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float), typeof(float) }); + } + else if (Op.Size == 1) + { + MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double), typeof(double) }); + } + else + { + throw new InvalidOperationException(); + } + + Context.EmitCall(MthdInfo); + } + + public static void EmitScalarUnaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitScalarOp(Context, Emit, OperFlags.Rn, true); + } + + public static void EmitScalarBinaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitScalarOp(Context, Emit, OperFlags.RnRm, true); + } + + public static void EmitScalarUnaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitScalarOp(Context, Emit, OperFlags.Rn, false); + } + + public static void EmitScalarBinaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitScalarOp(Context, Emit, OperFlags.RnRm, false); + } + + public static void EmitScalarTernaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitScalarOp(Context, Emit, OperFlags.RdRnRm, false); + } + + public static void EmitScalarOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + if (Opers.HasFlag(OperFlags.Rd)) + { + EmitVectorExtract(Context, Op.Rd, 0, Op.Size, Signed); + } + + if (Opers.HasFlag(OperFlags.Rn)) + { + EmitVectorExtract(Context, Op.Rn, 0, Op.Size, Signed); + } + + if (Opers.HasFlag(OperFlags.Rm)) + { + EmitVectorExtract(Context, Op.Rm, 0, Op.Size, Signed); + } + + Emit(); + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void EmitScalarUnaryOpF(AILEmitterCtx Context, Action Emit) + { + EmitScalarOpF(Context, Emit, OperFlags.Rn); + } + + public static void EmitScalarBinaryOpF(AILEmitterCtx Context, Action Emit) + { + EmitScalarOpF(Context, Emit, OperFlags.RnRm); + } + + public static void EmitScalarTernaryRaOpF(AILEmitterCtx Context, Action Emit) + { + EmitScalarOpF(Context, Emit, OperFlags.RaRnRm); + } + + public static void EmitScalarOpF(AILEmitterCtx Context, Action Emit, OperFlags Opers) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int SizeF = Op.Size & 1; + + if (Opers.HasFlag(OperFlags.Ra)) + { + EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Ra, 0, SizeF); + } + + if (Opers.HasFlag(OperFlags.Rn)) + { + EmitVectorExtractF(Context, Op.Rn, 0, SizeF); + } + + if (Opers.HasFlag(OperFlags.Rm)) + { + EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Rm, 0, SizeF); + } + + Emit(); + + EmitScalarSetF(Context, Op.Rd, SizeF); + } + + public static void EmitVectorBinaryOpF(AILEmitterCtx Context, Action Emit) + { + EmitVectorOpF(Context, Emit, OperFlags.RnRm); + } + + public static void EmitVectorTernaryOpF(AILEmitterCtx Context, Action Emit) + { + EmitVectorOpF(Context, Emit, OperFlags.RdRnRm); + } + + public static void EmitVectorBinaryOpByElemF(AILEmitterCtx Context, Action Emit) + { + AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; + + EmitVectorOpF(Context, Emit, OperFlags.RnRm, Op.Index); + } + + public static void EmitVectorTernaryOpByElemF(AILEmitterCtx Context, Action Emit) + { + AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; + + EmitVectorOpF(Context, Emit, OperFlags.RdRnRm, Op.Index); + } + + public static void EmitVectorOpF(AILEmitterCtx Context, Action Emit, OperFlags Opers, int Elem = -1) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int SizeF = Op.Size & 1; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> SizeF + 2); Index++) + { + if (Opers.HasFlag(OperFlags.Rd)) + { + EmitVectorExtractF(Context, Op.Rd, Index, SizeF); + } + + if (Opers.HasFlag(OperFlags.Rn)) + { + EmitVectorExtractF(Context, Op.Rn, Index, SizeF); + } + + if (Opers.HasFlag(OperFlags.Rm)) + { + if (Elem != -1) + { + EmitVectorExtractF(Context, Op.Rm, Elem, SizeF); + } + else + { + EmitVectorExtractF(Context, Op.Rm, Index, SizeF); + } + } + + Emit(); + + EmitVectorInsertF(Context, Op.Rd, Index, SizeF); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void EmitVectorUnaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitVectorOp(Context, Emit, OperFlags.Rn, true); + } + + public static void EmitVectorBinaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitVectorOp(Context, Emit, OperFlags.RnRm, true); + } + + public static void EmitVectorUnaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitVectorOp(Context, Emit, OperFlags.Rn, false); + } + + public static void EmitVectorBinaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitVectorOp(Context, Emit, OperFlags.RnRm, false); + } + + public static void EmitVectorTernaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitVectorOp(Context, Emit, OperFlags.RdRnRm, false); + } + + public static void EmitVectorOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + if (Opers.HasFlag(OperFlags.Rd)) + { + EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed); + } + + if (Opers.HasFlag(OperFlags.Rn)) + { + EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); + } + + if (Opers.HasFlag(OperFlags.Rm)) + { + EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed); + } + + Emit(); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void EmitVectorImmUnaryOp(AILEmitterCtx Context, Action Emit) + { + EmitVectorImmOp(Context, Emit, false); + } + + public static void EmitVectorImmBinaryOp(AILEmitterCtx Context, Action Emit) + { + EmitVectorImmOp(Context, Emit, true); + } + + public static void EmitVectorImmOp(AILEmitterCtx Context, Action Emit, bool Binary) + { + AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + if (Binary) + { + EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size); + } + + Context.EmitLdc_I8(Op.Imm); + + Emit(); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void EmitVectorWidenBinaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitVectorWidenBinaryOp(Context, Emit, true); + } + + public static void EmitVectorWidenBinaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitVectorWidenBinaryOp(Context, Emit, false); + } + + public static void EmitVectorWidenBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Elems = 8 >> Op.Size; + + int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed); + EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed); + + Emit(); + + EmitVectorInsertTmp(Context, Index, Op.Size + 1); + } + + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + } + + public static void EmitScalarSet(AILEmitterCtx Context, int Reg, int Size) + { + EmitVectorZeroAll(Context, Reg); + EmitVectorInsert(Context, Reg, 0, Size); + } + + public static void EmitScalarSetF(AILEmitterCtx Context, int Reg, int Size) + { + EmitVectorZeroAll(Context, Reg); + EmitVectorInsertF(Context, Reg, 0, Size); + } + + public static void EmitVectorExtractSx(AILEmitterCtx Context, int Reg, int Index, int Size) + { + EmitVectorExtract(Context, Reg, Index, Size, true); + } + + public static void EmitVectorExtractZx(AILEmitterCtx Context, int Reg, int Index, int Size) + { + EmitVectorExtract(Context, Reg, Index, Size, false); + } + + public static void EmitVectorExtract(AILEmitterCtx Context, int Reg, int Index, int Size, bool Signed) + { + if (Size < 0 || Size > 3) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + + Context.EmitLdvec(Reg); + Context.EmitLdc_I4(Index); + Context.EmitLdc_I4(Size); + + ASoftFallback.EmitCall(Context, Signed + ? nameof(ASoftFallback.VectorExtractIntSx) + : nameof(ASoftFallback.VectorExtractIntZx)); + } + + public static void EmitVectorExtractF(AILEmitterCtx Context, int Reg, int Index, int Size) + { + Context.EmitLdvec(Reg); + Context.EmitLdc_I4(Index); + + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractSingle)); + } + else if (Size == 1) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractDouble)); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + } + + public static void EmitVectorZeroAll(AILEmitterCtx Context, int Rd) + { + EmitVectorZeroLower(Context, Rd); + EmitVectorZeroUpper(Context, Rd); + } + + public static void EmitVectorZeroLower(AILEmitterCtx Context, int Rd) + { + EmitVectorInsert(Context, Rd, 0, 3, 0); + } + + public static void EmitVectorZeroUpper(AILEmitterCtx Context, int Rd) + { + EmitVectorInsert(Context, Rd, 1, 3, 0); + } + + public static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size) + { + if (Size < 0 || Size > 3) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.EmitLdvec(Reg); + Context.EmitLdc_I4(Index); + Context.EmitLdc_I4(Size); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); + + Context.EmitStvec(Reg); + } + + public static void EmitVectorInsertTmp(AILEmitterCtx Context, int Index, int Size) + { + if (Size < 0 || Size > 3) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.EmitLdvectmp(); + Context.EmitLdc_I4(Index); + Context.EmitLdc_I4(Size); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); + + Context.EmitStvectmp(); + } + + public static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value) + { + if (Size < 0 || Size > 3) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.EmitLdc_I8(Value); + Context.EmitLdvec(Reg); + Context.EmitLdc_I4(Index); + Context.EmitLdc_I4(Size); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); + + Context.EmitStvec(Reg); + } + + public static void EmitVectorInsertF(AILEmitterCtx Context, int Reg, int Index, int Size) + { + Context.EmitLdvec(Reg); + Context.EmitLdc_I4(Index); + + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertSingle)); + } + else if (Size == 1) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertDouble)); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.EmitStvec(Reg); + } + } +} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs new file mode 100644 index 000000000..ea4b17b3d --- /dev/null +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs @@ -0,0 +1,69 @@ +using ChocolArm64.Translation; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void And_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.And)); + } + + public static void Bic_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => + { + Context.Emit(OpCodes.Not); + Context.Emit(OpCodes.And); + }); + } + + public static void Bic_Vi(AILEmitterCtx Context) + { + EmitVectorImmBinaryOp(Context, () => + { + Context.Emit(OpCodes.Not); + Context.Emit(OpCodes.And); + }); + } + + public static void Bsl_V(AILEmitterCtx Context) + { + EmitVectorTernaryOpZx(Context, () => + { + Context.EmitSttmp(); + Context.EmitLdtmp(); + + Context.Emit(OpCodes.Xor); + Context.Emit(OpCodes.And); + + Context.EmitLdtmp(); + + Context.Emit(OpCodes.Xor); + }); + } + + public static void Eor_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Xor)); + } + + public static void Not_V(AILEmitterCtx Context) + { + EmitVectorUnaryOpZx(Context, () => Context.Emit(OpCodes.Not)); + } + + public static void Orr_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Or)); + } + + public static void Orr_Vi(AILEmitterCtx Context) + { + EmitVectorImmBinaryOp(Context, () => Context.Emit(OpCodes.Or)); + } + } +} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs new file mode 100644 index 000000000..d75db619e --- /dev/null +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs @@ -0,0 +1,155 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitMemoryHelper; +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + 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 St__Vms(AILEmitterCtx Context) + { + EmitSimdMemMs(Context, IsLoad: false); + } + + public static void St__Vss(AILEmitterCtx Context) + { + EmitSimdMemSs(Context, IsLoad: false); + } + + private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad) + { + AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)Context.CurrOp; + + int Offset = 0; + + for (int Rep = 0; Rep < Op.Reps; Rep++) + for (int Elem = 0; Elem < Op.Elems; Elem++) + for (int SElem = 0; SElem < Op.SElems; SElem++) + { + int Rtt = (Op.Rt + Rep + SElem) & 0x1f; + + if (IsLoad) + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdc_I8(Offset); + + Context.Emit(OpCodes.Add); + + EmitReadZxCall(Context, Op.Size); + + EmitVectorInsert(Context, Rtt, Elem, Op.Size); + + if (Op.RegisterSize == ARegisterSize.SIMD64 && Elem == Op.Elems - 1) + { + EmitVectorZeroUpper(Context, Rtt); + } + } + else + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdc_I8(Offset); + + Context.Emit(OpCodes.Add); + + EmitVectorExtractZx(Context, Rtt, Elem, Op.Size); + + EmitWriteCall(Context, Op.Size); + } + + Offset += 1 << Op.Size; + } + + if (Op.WBack) + { + EmitSimdMemWBack(Context, Offset); + } + } + + 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.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdc_I8(Offset); + + Context.Emit(OpCodes.Add); + + EmitReadZxCall(Context, Op.Size); + + EmitVectorInsert(Context, Rt, Op.Index, Op.Size); + + 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); + + EmitVectorExtractZx(Context, Rt, Op.Index, Op.Size); + + EmitWriteCall(Context, Op.Size); + } + + Offset += 1 << Op.Size; + } + + if (Op.WBack) + { + EmitSimdMemWBack(Context, Offset); + } + } + + private static void EmitSimdMemWBack(AILEmitterCtx Context, int Offset) + { + AOpCodeMemReg Op = (AOpCodeMemReg)Context.CurrOp; + + 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); + } + } +} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs new file mode 100644 index 000000000..87d57e962 --- /dev/null +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs @@ -0,0 +1,275 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Dup_Gp(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + Context.EmitLdintzr(Op.Rn); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void Dup_S(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size); + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void Dup_V(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void Fcsel_S(AILEmitterCtx Context) + { + AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; + + AILLabel LblTrue = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.EmitCondBranch(LblTrue, Op.Cond); + + EmitVectorExtractF(Context, Op.Rm, 0, Op.Size); + + Context.Emit(OpCodes.Br_S, LblEnd); + + Context.MarkLabel(LblTrue); + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + Context.MarkLabel(LblEnd); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Fmov_Ftoi(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, 0, 3); + + Context.EmitStintzr(Op.Rd); + } + + public static void Fmov_Ftoi1(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, 1, 3); + + Context.EmitStintzr(Op.Rd); + } + + public static void Fmov_Itof(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + EmitScalarSet(Context, Op.Rd, 3); + } + + public static void Fmov_Itof1(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + EmitVectorInsert(Context, Op.Rd, 1, 3); + } + + public static void Fmov_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Fmov_Si(AILEmitterCtx Context) + { + AOpCodeSimdFmov Op = (AOpCodeSimdFmov)Context.CurrOp; + + Context.EmitLdc_I8(Op.Imm); + + EmitScalarSet(Context, Op.Rd, Op.Size + 2); + } + + public static void Fmov_V(AILEmitterCtx Context) + { + AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; + + for (int Index = 0; Index < (4 >> Op.Size); Index++) + { + Context.EmitLdc_I8(Op.Imm); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size + 2); + } + } + + public static void Ins_Gp(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size); + } + + public static void Ins_V(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, Op.SrcIndex, Op.Size); + + EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size); + } + + public static void Movi_V(AILEmitterCtx Context) + { + EmitVectorImmUnaryOp(Context, () => { }); + } + + public static void Mvni_V(AILEmitterCtx Context) + { + EmitVectorImmUnaryOp(Context, () => Context.Emit(OpCodes.Not)); + } + + public static void Tbl_V(AILEmitterCtx Context) + { + AOpCodeSimdTbl Op = (AOpCodeSimdTbl)Context.CurrOp; + + Context.EmitLdvec(Op.Rm); + + for (int Index = 0; Index < Op.Size; Index++) + { + Context.EmitLdvec((Op.Rn + Index) & 0x1f); + } + + switch (Op.Size) + { + case 1: ASoftFallback.EmitCall(Context, + nameof(ASoftFallback.Tbl1_V64), + nameof(ASoftFallback.Tbl1_V128)); break; + + case 2: ASoftFallback.EmitCall(Context, + nameof(ASoftFallback.Tbl2_V64), + nameof(ASoftFallback.Tbl2_V128)); break; + + case 3: ASoftFallback.EmitCall(Context, + nameof(ASoftFallback.Tbl3_V64), + nameof(ASoftFallback.Tbl3_V128)); break; + + case 4: ASoftFallback.EmitCall(Context, + nameof(ASoftFallback.Tbl4_V64), + nameof(ASoftFallback.Tbl4_V128)); break; + + default: throw new InvalidOperationException(); + } + + Context.EmitStvec(Op.Rd); + } + + public static void Umov_S(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size); + + Context.EmitStintzr(Op.Rd); + } + + public static void Uzp1_V(AILEmitterCtx Context) + { + EmitVectorUnzip(Context, Part: 0); + } + + public static void Uzp2_V(AILEmitterCtx Context) + { + EmitVectorUnzip(Context, Part: 1); + } + + public static void Xtn_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Elems = 8 >> Op.Size; + + int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1); + + EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size); + } + + if (Part == 0) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + private static void EmitVectorUnzip(AILEmitterCtx Context, int Part) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + int Elems = Bytes >> Op.Size; + int Half = Elems >> 1; + + for (int Index = 0; Index < Elems; Index++) + { + int Elem = Part + ((Index & (Half - 1)) << 1); + + EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem, Op.Size); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs new file mode 100644 index 000000000..165642342 --- /dev/null +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs @@ -0,0 +1,306 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + [Flags] + private enum ShrFlags + { + None = 0, + Signed = 1 << 0, + Rounding = 1 << 1, + Accumulate = 1 << 2 + } + + public static void Shl_S(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); + + Context.EmitLdc_I4(GetImmShl(Op)); + + Context.Emit(OpCodes.Shl); + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void Shl_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Shift = Op.Imm - (8 << Op.Size); + + EmitVectorShImmBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift); + } + + public static void Shrn_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Shift = (8 << (Op.Size + 1)) - Op.Imm; + + EmitVectorShImmNarrowBinaryZx(Context, () => Context.Emit(OpCodes.Shr_Un), Shift); + } + + public static void Sshl_V(AILEmitterCtx Context) + { + EmitVectorShl(Context, Signed: true); + } + + public static void Sshll_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Shift = Op.Imm - (8 << Op.Size); + + EmitVectorShImmWidenBinarySx(Context, () => Context.Emit(OpCodes.Shl), Shift); + } + + public static void Sshr_S(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + EmitVectorExtractSx(Context, Op.Rn, 0, Op.Size); + + Context.EmitLdc_I4(GetImmShr(Op)); + + Context.Emit(OpCodes.Shr); + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void Sshr_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Shift = (8 << (Op.Size + 1)) - Op.Imm; + + EmitVectorShImmBinarySx(Context, () => Context.Emit(OpCodes.Shr), Shift); + } + + public static void Ushl_V(AILEmitterCtx Context) + { + EmitVectorShl(Context, Signed: false); + } + + public static void Ushll_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Shift = Op.Imm - (8 << Op.Size); + + EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift); + } + + public static void Ushr_V(AILEmitterCtx Context) + { + EmitVectorShr(Context, ShrFlags.None); + } + + public static void Usra_V(AILEmitterCtx Context) + { + EmitVectorShr(Context, ShrFlags.Accumulate); + } + + private static void EmitVectorShl(AILEmitterCtx Context, bool Signed) + { + //This instruction shifts the value on vector A by the number of bits + //specified on the signed, lower 8 bits of vector B. If the shift value + //is greater or equal to the data size of each lane, then the result is zero. + //Additionally, negative shifts produces right shifts by the negated shift value. + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int MaxShift = 8 << Op.Size; + + Action Emit = () => + { + AILLabel LblShl = new AILLabel(); + AILLabel LblZero = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + void EmitShift(OpCode ILOp) + { + Context.Emit(OpCodes.Dup); + + Context.EmitLdc_I4(MaxShift); + + Context.Emit(OpCodes.Bge_S, LblZero); + Context.Emit(ILOp); + Context.Emit(OpCodes.Br_S, LblEnd); + } + + Context.Emit(OpCodes.Conv_I1); + Context.Emit(OpCodes.Dup); + + Context.EmitLdc_I4(0); + + Context.Emit(OpCodes.Bge_S, LblShl); + Context.Emit(OpCodes.Neg); + + EmitShift(Signed + ? OpCodes.Shr + : OpCodes.Shr_Un); + + Context.MarkLabel(LblShl); + + EmitShift(OpCodes.Shl); + + Context.MarkLabel(LblZero); + + Context.Emit(OpCodes.Pop); + Context.Emit(OpCodes.Pop); + + Context.EmitLdc_I8(0); + + Context.MarkLabel(LblEnd); + }; + + if (Signed) + { + EmitVectorBinaryOpSx(Context, Emit); + } + else + { + EmitVectorBinaryOpZx(Context, Emit); + } + } + + private static void EmitVectorShr(AILEmitterCtx Context, ShrFlags Flags) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Shift = (8 << (Op.Size + 1)) - Op.Imm; + + if (Flags.HasFlag(ShrFlags.Accumulate)) + { + Action Emit = () => + { + Context.EmitLdc_I4(Shift); + + Context.Emit(OpCodes.Shr_Un); + Context.Emit(OpCodes.Add); + }; + + EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false); + } + else + { + EmitVectorUnaryOpZx(Context, () => + { + Context.EmitLdc_I4(Shift); + + Context.Emit(OpCodes.Shr_Un); + }); + } + } + + private static void EmitVectorShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmBinaryOp(Context, Emit, Imm, true); + } + + private static void EmitVectorShImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmBinaryOp(Context, Emit, Imm, false); + } + + private static void EmitVectorShImmBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); + + Context.EmitLdc_I4(Imm); + + Emit(); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + private static void EmitVectorShImmNarrowBinarySx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, true); + } + + private static void EmitVectorShImmNarrowBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, false); + } + + private static void EmitVectorShImmNarrowBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Elems = 8 >> Op.Size; + + int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed); + + Context.EmitLdc_I4(Imm); + + Emit(); + + EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size); + } + + if (Part == 0) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + private static void EmitVectorShImmWidenBinarySx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, true); + } + + private static void EmitVectorShImmWidenBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, false); + } + + private static void EmitVectorShImmWidenBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Elems = 8 >> Op.Size; + + int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed); + + Context.EmitLdc_I4(Imm); + + Emit(); + + EmitVectorInsertTmp(Context, Index, Op.Size + 1); + } + + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + } + } +} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/ASoftFallback.cs b/Ryujinx/Cpu/Instruction/ASoftFallback.cs index a8df01070..b70d0b4f4 100644 --- a/Ryujinx/Cpu/Instruction/ASoftFallback.cs +++ b/Ryujinx/Cpu/Instruction/ASoftFallback.cs @@ -1,6 +1,7 @@ using ChocolArm64.State; using ChocolArm64.Translation; using System; +using System.Runtime.CompilerServices; namespace ChocolArm64.Instruction { @@ -97,142 +98,62 @@ namespace ChocolArm64.Instruction throw new ArgumentException(nameof(Size)); } - public static int SatSingleToInt32(float Value, int FBits) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SatF32ToS32(float Value) { - if (FBits != 0) Value *= MathF.Pow(2, FBits); - return Value > int.MaxValue ? int.MaxValue : Value < int.MinValue ? int.MinValue : (int)Value; } - public static long SatSingleToInt64(float Value, int FBits) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long SatF32ToS64(float Value) { - if (FBits != 0) Value *= MathF.Pow(2, FBits); - return Value > long.MaxValue ? long.MaxValue : Value < long.MinValue ? long.MinValue : (long)Value; } - public static uint SatSingleToUInt32(float Value, int FBits) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint SatF32ToU32(float Value) { - if (FBits != 0) Value *= MathF.Pow(2, FBits); - return Value > uint.MaxValue ? uint.MaxValue : Value < uint.MinValue ? uint.MinValue : (uint)Value; } - public static ulong SatSingleToUInt64(float Value, int FBits) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong SatF32ToU64(float Value) { - if (FBits != 0) Value *= MathF.Pow(2, FBits); - return Value > ulong.MaxValue ? ulong.MaxValue : Value < ulong.MinValue ? ulong.MinValue : (ulong)Value; } - public static int SatDoubleToInt32(double Value, int FBits) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SatF64ToS32(double Value) { - if (FBits != 0) Value *= Math.Pow(2, FBits); - return Value > int.MaxValue ? int.MaxValue : Value < int.MinValue ? int.MinValue : (int)Value; } - public static long SatDoubleToInt64(double Value, int FBits) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long SatF64ToS64(double Value) { - if (FBits != 0) Value *= Math.Pow(2, FBits); - return Value > long.MaxValue ? long.MaxValue : Value < long.MinValue ? long.MinValue : (long)Value; } - public static uint SatDoubleToUInt32(double Value, int FBits) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint SatF64ToU32(double Value) { - if (FBits != 0) Value *= Math.Pow(2, FBits); - return Value > uint.MaxValue ? uint.MaxValue : Value < uint.MinValue ? uint.MinValue : (uint)Value; } - public static ulong SatDoubleToUInt64(double Value, int FBits) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong SatF64ToU64(double Value) { - if (FBits != 0) Value *= Math.Pow(2, FBits); - return Value > ulong.MaxValue ? ulong.MaxValue : Value < ulong.MinValue ? ulong.MinValue : (ulong)Value; } - public static float Int32ToSingle(int Value, int FBits) - { - float ValueF = Value; - - if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits); - - return ValueF; - } - - public static float Int64ToSingle(long Value, int FBits) - { - float ValueF = Value; - - if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits); - - return ValueF; - } - - public static float UInt32ToSingle(uint Value, int FBits) - { - float ValueF = Value; - - if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits); - - return ValueF; - } - - public static float UInt64ToSingle(ulong Value, int FBits) - { - float ValueF = Value; - - if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits); - - return ValueF; - } - - public static double Int32ToDouble(int Value, int FBits) - { - double ValueF = Value; - - if (FBits != 0) ValueF *= 1 / Math.Pow(2, FBits); - - return ValueF; - } - - public static double Int64ToDouble(long Value, int FBits) - { - double ValueF = Value; - - if (FBits != 0) ValueF *= 1 / Math.Pow(2, FBits); - - return ValueF; - } - - public static double UInt32ToDouble(uint Value, int FBits) - { - double ValueF = Value; - - if (FBits != 0) ValueF *= 1 / Math.Pow(2, FBits); - - return ValueF; - } - - public static double UInt64ToDouble(ulong Value, int FBits) - { - double ValueF = Value; - - if (FBits != 0) ValueF *= 1 / Math.Pow(2, FBits); - - return ValueF; - } - public static ulong SMulHi128(ulong LHS, ulong RHS) { long LLo = (uint)(LHS >> 0); @@ -269,14 +190,6 @@ namespace ChocolArm64.Instruction ulong ResHi = LHiRHi + (LHiRLo >> 32) + (LLoRHi >> 32) + Carry; return ResHi; - } - - public static AVec Addp_S(AVec Vector, int Size) - { - ulong Low = ExtractVec(Vector, 0, Size); - ulong High = ExtractVec(Vector, 1, Size); - - return InsertVec(new AVec(), 0, Size, Low + High); } public static int CountSetBits8(byte Value) @@ -287,38 +200,6 @@ namespace ChocolArm64.Instruction (Value >> 6) & 1 + (Value >> 7); } - public static AVec Dup_Gp64(ulong Value, int Size) - { - return Dup_Gp(Value, Size, 8); - } - - public static AVec Dup_Gp128(ulong Value, int Size) - { - return Dup_Gp(Value, Size, 16); - } - - private static AVec Dup_Gp(ulong Value, int Size, int Bytes) - { - AVec Res = new AVec(); - - for (int Index = 0; Index < (Bytes >> Size); Index++) - { - Res = InsertVec(Res, Index, Size, Value); - } - - return Res; - } - - public static AVec Dup_S(AVec Vector, int Elem, int Size) - { - return InsertVec(new AVec(), 0, Size, ExtractVec(Vector, Elem, Size)); - } - - public static AVec Fmov_S(ulong Value, int Elem, int Size) - { - return InsertVec(new AVec(), Elem, Size, Value); - } - public static AVec Tbl1_V64(AVec Vector, AVec Tb0) { return Tbl(Vector, 8, Tb0); @@ -368,27 +249,27 @@ namespace ChocolArm64.Instruction for (int Index = 0; Index < Tb.Length; Index++) for (int Index2 = 0; Index2 < 16; Index2++) { - Table[Index * 16 + Index2] = (byte)ExtractVec(Tb[Index], Index2, 0); + Table[Index * 16 + Index2] = (byte)VectorExtractIntZx(Tb[Index], Index2, 0); } for (int Index = 0; Index < Bytes; Index++) { - byte TblIdx = (byte)ExtractVec(Vector, Index, 0); + byte TblIdx = (byte)VectorExtractIntZx(Vector, Index, 0); if (TblIdx < Table.Length) { - Res = InsertVec(Res, Index, 0, Table[TblIdx]); + Res = VectorInsertInt(Table[TblIdx], Res, Index, 0); } } return Res; } - public static ulong ExtractVec(AVec Vector, int Index, int Size) + public static ulong VectorExtractIntZx(AVec Vector, int Index, int Size) { switch (Size) { - case 0: return Vector.ExtractByte(Index); + case 0: return Vector.ExtractByte (Index); case 1: return Vector.ExtractUInt16(Index); case 2: return Vector.ExtractUInt32(Index); case 3: return Vector.ExtractUInt64(Index); @@ -397,14 +278,14 @@ namespace ChocolArm64.Instruction throw new ArgumentOutOfRangeException(nameof(Size)); } - public static long ExtractSVec(AVec Vector, int Index, int Size) + public static long VectorExtractIntSx(AVec Vector, int Index, int Size) { switch (Size) { - case 0: return (sbyte)Vector.ExtractByte(Index); + case 0: return (sbyte)Vector.ExtractByte (Index); case 1: return (short)Vector.ExtractUInt16(Index); - case 2: return (int)Vector.ExtractUInt32(Index); - case 3: return (long)Vector.ExtractUInt64(Index); + case 2: return (int)Vector.ExtractUInt32(Index); + case 3: return (long)Vector.ExtractUInt64(Index); } throw new ArgumentOutOfRangeException(nameof(Size)); @@ -442,31 +323,5 @@ namespace ChocolArm64.Instruction throw new ArgumentOutOfRangeException(nameof(Size)); } - - public static AVec InsertVec(AVec Vector, int Index, int Size, ulong Value) - { - switch (Size) - { - case 0: return AVec.InsertByte(Vector, Index, (byte)Value); - case 1: return AVec.InsertUInt16(Vector, Index, (ushort)Value); - case 2: return AVec.InsertUInt32(Vector, Index, (uint)Value); - case 3: return AVec.InsertUInt64(Vector, Index, (ulong)Value); - } - - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - public static AVec InsertSVec(AVec Vector, int Index, int Size, long Value) - { - switch (Size) - { - case 0: return AVec.InsertByte(Vector, Index, (byte)Value); - case 1: return AVec.InsertUInt16(Vector, Index, (ushort)Value); - case 2: return AVec.InsertUInt32(Vector, Index, (uint)Value); - case 3: return AVec.InsertUInt64(Vector, Index, (ulong)Value); - } - - throw new ArgumentOutOfRangeException(nameof(Size)); - } } } \ No newline at end of file diff --git a/Ryujinx/Cpu/Memory/AMemory.cs b/Ryujinx/Cpu/Memory/AMemory.cs index ead99f3f6..52f76e2ec 100644 --- a/Ryujinx/Cpu/Memory/AMemory.cs +++ b/Ryujinx/Cpu/Memory/AMemory.cs @@ -174,6 +174,42 @@ namespace ChocolArm64.Memory return *((ulong*)(RamPtr + (uint)Position)); } + public AVec ReadVector8(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { B0 = ReadByte(Position) }; + } + + public AVec ReadVector16(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { H0 = ReadUInt16(Position) }; + } + + public AVec ReadVector32(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { W0 = ReadUInt32(Position) }; + } + + public AVec ReadVector64(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { X0 = ReadUInt64(Position) }; + } + public AVec ReadVector128(long Position) { #if DEBUG @@ -228,6 +264,42 @@ namespace ChocolArm64.Memory *((ulong*)(RamPtr + (uint)Position)) = Value; } + public void WriteVector8(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteByte(Position, Value.B0); + } + + public void WriteVector16(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteUInt16(Position, Value.H0); + } + + public void WriteVector32(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteUInt32(Position, Value.W0); + } + + public void WriteVector64(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteUInt64(Position, Value.X0); + } + public void WriteVector128(long Position, AVec Value) { #if DEBUG diff --git a/Ryujinx/Cpu/Translation/AILConv.cs b/Ryujinx/Cpu/Translation/AILConv.cs deleted file mode 100644 index 8969dc4e9..000000000 --- a/Ryujinx/Cpu/Translation/AILConv.cs +++ /dev/null @@ -1,113 +0,0 @@ -using ChocolArm64.State; -using System; -using System.Reflection; -using System.Reflection.Emit; - -namespace ChocolArm64.Translation -{ - static class AILConv - { - public static void EmitConv(AILEmitter Context, Type SrcType, Type TgtType) - { - if (SrcType == TgtType) - { - //If both types are equal we don't need to cast anything. - return; - } - - if (SrcType.IsPrimitive) - { - if (TgtType == typeof(byte)) - { - Context.Generator.Emit(OpCodes.Conv_U1); - } - else if (TgtType == typeof(ushort)) - { - Context.Generator.Emit(OpCodes.Conv_U2); - } - else if (TgtType == typeof(uint)) - { - Context.Generator.Emit(OpCodes.Conv_U4); - } - else if (TgtType == typeof(ulong)) - { - Context.Generator.Emit(OpCodes.Conv_U8); - } - else if (TgtType == typeof(float)) - { - Context.Generator.Emit(OpCodes.Conv_R4); - } - else if (TgtType == typeof(double)) - { - Context.Generator.Emit(OpCodes.Conv_R8); - } - else if (TgtType == typeof(AVec)) - { - EmitMakeVec(Context, SrcType); - } - else - { - throw new ArgumentException(nameof(TgtType)); - } - } - else if (SrcType == typeof(AVec)) - { - if (TgtType == typeof(float)) - { - EmitScalarLdfld(Context, nameof(AVec.S0)); - } - else if (TgtType == typeof(double)) - { - EmitScalarLdfld(Context, nameof(AVec.D0)); - } - else if (TgtType == typeof(byte)) - { - EmitScalarLdfld(Context, nameof(AVec.B0)); - } - else if (TgtType == typeof(ushort)) - { - EmitScalarLdfld(Context, nameof(AVec.H0)); - } - else if (TgtType == typeof(uint)) - { - EmitScalarLdfld(Context, nameof(AVec.W0)); - } - else if (TgtType == typeof(ulong)) - { - EmitScalarLdfld(Context, nameof(AVec.X0)); - } - else - { - throw new ArgumentException(nameof(TgtType)); - } - } - else - { - throw new ArgumentException(nameof(SrcType)); - } - } - - private static void EmitScalarLdfld(AILEmitter Context,string FldName) - { - Context.Generator.Emit(OpCodes.Ldfld, typeof(AVec).GetField(FldName)); - } - - private static void EmitMakeVec(AILEmitter Context, Type SrcType) - { - string MthdName = nameof(MakeScalar); - - Type[] MthdTypes = new Type[] { SrcType }; - - MethodInfo MthdInfo = typeof(AILConv).GetMethod(MthdName, MthdTypes); - - Context.Generator.Emit(OpCodes.Call, MthdInfo); - } - - public static AVec MakeScalar(byte Value) => new AVec { B0 = Value }; - public static AVec MakeScalar(ushort Value) => new AVec { H0 = Value }; - public static AVec MakeScalar(uint Value) => new AVec { W0 = Value }; - public static AVec MakeScalar(float Value) => new AVec { S0 = Value }; - public static AVec MakeScalar(ulong Value) => new AVec { X0 = Value }; - public static AVec MakeScalar(double Value) => new AVec { D0 = Value }; - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILEmitter.cs b/Ryujinx/Cpu/Translation/AILEmitter.cs index 0619149c3..8f6e1210f 100644 --- a/Ryujinx/Cpu/Translation/AILEmitter.cs +++ b/Ryujinx/Cpu/Translation/AILEmitter.cs @@ -86,9 +86,6 @@ namespace ChocolArm64.Translation ARegister Reg = Subroutine.Params[Index]; Generator.EmitLdarg(Index + ParamsStart); - - AILConv.EmitConv(this, GetFieldType(Reg.Type), GetLocalType(Reg)); - Generator.EmitStloc(GetLocalIndex(Reg)); } } diff --git a/Ryujinx/Cpu/Translation/AILEmitterCtx.cs b/Ryujinx/Cpu/Translation/AILEmitterCtx.cs index 4c4841c5c..619ad3ae6 100644 --- a/Ryujinx/Cpu/Translation/AILEmitterCtx.cs +++ b/Ryujinx/Cpu/Translation/AILEmitterCtx.cs @@ -150,8 +150,8 @@ namespace ChocolArm64.Translation if (LastCmpOp != null && LastFlagOp == LastCmpOp && BranchOps.ContainsKey(Cond)) { - Ldloc(Tmp3Index, AIoType.Int, GetIntType(LastCmpOp)); - Ldloc(Tmp4Index, AIoType.Int, GetIntType(LastCmpOp)); + Ldloc(Tmp3Index, AIoType.Int, LastCmpOp.RegisterSize); + Ldloc(Tmp4Index, AIoType.Int, LastCmpOp.RegisterSize); if (LastCmpOp.Emitter == AInstEmit.Adds) { @@ -353,12 +353,6 @@ namespace ChocolArm64.Translation public void EmitLdvec(int Index) => Ldloc(Index, AIoType.Vector); public void EmitStvec(int Index) => Stloc(Index, AIoType.Vector); - public void EmitLdvecsi(int Index) => Ldloc(Index, AIoType.VectorI); - public void EmitStvecsi(int Index) => Stloc(Index, AIoType.VectorI); - - public void EmitLdvecsf(int Index) => Ldloc(Index, AIoType.VectorF); - public void EmitStvecsf(int Index) => Stloc(Index, AIoType.VectorF); - public void EmitLdflg(int Index) => Ldloc(Index, AIoType.Flag); public void EmitStflg(int Index) { @@ -369,107 +363,17 @@ namespace ChocolArm64.Translation private void Ldloc(int Index, AIoType IoType) { - ILBlock.Add(new AILOpCodeLoad(Index, IoType, GetOperType(IoType))); + ILBlock.Add(new AILOpCodeLoad(Index, IoType, CurrOp.RegisterSize)); } - private void Ldloc(int Index, AIoType IoType, Type Type) + private void Ldloc(int Index, AIoType IoType, ARegisterSize RegisterSize) { - ILBlock.Add(new AILOpCodeLoad(Index, IoType, Type)); + ILBlock.Add(new AILOpCodeLoad(Index, IoType, RegisterSize)); } private void Stloc(int Index, AIoType IoType) { - ILBlock.Add(new AILOpCodeStore(Index, IoType, GetOutOperType(IoType))); - } - - private Type GetOutOperType(AIoType IoType) - { - //This instruction is used to convert between floating point - //types, so the input and output types are different. - if (CurrOp.Emitter == AInstEmit.Fcvt_S) - { - return GetFloatType(((AOpCodeSimd)CurrOp).Opc); - } - else - { - return GetOperType(IoType); - } - } - - private Type GetOperType(AIoType IoType) - { - switch (IoType & AIoType.Mask) - { - case AIoType.Flag: return typeof(bool); - case AIoType.Int: return GetIntType(CurrOp); - case AIoType.Vector: return GetVecType(CurrOp, IoType); - } - - throw new ArgumentException(nameof(IoType)); - } - - private Type GetIntType(AOpCode OpCode) - { - //Always default to 64-bits. - return OpCode.RegisterSize == ARegisterSize.Int32 - ? typeof(uint) - : typeof(ulong); - } - - private Type GetVecType(AOpCode OpCode, AIoType IoType) - { - if (!(OpCode is IAOpCodeSimd Op)) - { - return typeof(AVec); - } - - int Size = Op.Size; - - if (Op.Emitter == AInstEmit.Fmov_Ftoi || - Op.Emitter == AInstEmit.Fmov_Itof) - { - Size |= 2; - } - - if ((Op is AOpCodeMem || Op is IAOpCodeLit) && - !(Op is AOpCodeSimdMemMs || Op is AOpCodeSimdMemSs)) - { - return Size < 4 ? typeof(ulong) : typeof(AVec); - } - else if (IoType == AIoType.VectorI) - { - return GetIntType(Size); - } - else if (IoType == AIoType.VectorF) - { - return GetFloatType(Size); - } - - return typeof(AVec); - } - - private static Type GetIntType(int Size) - { - switch (Size) - { - case 0: return typeof(byte); - case 1: return typeof(ushort); - case 2: return typeof(uint); - case 3: return typeof(ulong); - } - - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - private static Type GetFloatType(int Size) - { - switch (Size) - { - case 0: return typeof(float); - case 1: return typeof(double); - } - - throw new ArgumentOutOfRangeException(nameof(Size)); + ILBlock.Add(new AILOpCodeStore(Index, IoType, CurrOp.RegisterSize)); } public void EmitCallPropGet(Type ObjType, string PropName) diff --git a/Ryujinx/Cpu/Translation/AILOpCodeLoad.cs b/Ryujinx/Cpu/Translation/AILOpCodeLoad.cs index 2169cc777..23ea0d07b 100644 --- a/Ryujinx/Cpu/Translation/AILOpCodeLoad.cs +++ b/Ryujinx/Cpu/Translation/AILOpCodeLoad.cs @@ -1,5 +1,4 @@ using ChocolArm64.State; -using System; using System.Reflection.Emit; namespace ChocolArm64.Translation @@ -10,43 +9,40 @@ namespace ChocolArm64.Translation public AIoType IoType { get; private set; } - public Type OperType { get; private set; } + public ARegisterSize RegisterSize { get; private set; } - public AILOpCodeLoad(int Index, AIoType IoType) : this(Index, IoType, null) { } + public AILOpCodeLoad(int Index, AIoType IoType) : this(Index, IoType, ARegisterSize.Int64) { } - public AILOpCodeLoad(int Index, AIoType IoType, Type OperType) + public AILOpCodeLoad(int Index, AIoType IoType, ARegisterSize RegisterSize) { - this.IoType = IoType; - this.Index = Index; - this.OperType = OperType; + this.IoType = IoType; + this.Index = Index; + this.RegisterSize = RegisterSize; } public void Emit(AILEmitter Context) { switch (IoType & AIoType.Mask) { - case AIoType.Arg: EmitLdarg(Context, Index); break; - case AIoType.Fields: EmitLdfld(Context, Index); break; + case AIoType.Arg: Context.Generator.EmitLdarg(Index); break; + + case AIoType.Fields: + { + long IntInputs = Context.LocalAlloc.GetIntInputs(Context.GetILBlock(Index)); + long VecInputs = Context.LocalAlloc.GetVecInputs(Context.GetILBlock(Index)); + + LoadLocals(Context, IntInputs, ARegisterType.Int); + LoadLocals(Context, VecInputs, ARegisterType.Vector); + + break; + } + case AIoType.Flag: EmitLdloc(Context, Index, ARegisterType.Flag); break; case AIoType.Int: EmitLdloc(Context, Index, ARegisterType.Int); break; case AIoType.Vector: EmitLdloc(Context, Index, ARegisterType.Vector); break; } } - private void EmitLdarg(AILEmitter Context, int Index) - { - Context.Generator.EmitLdarg(Index); - } - - private void EmitLdfld(AILEmitter Context, int Index) - { - long IntInputs = Context.LocalAlloc.GetIntInputs(Context.GetILBlock(Index)); - long VecInputs = Context.LocalAlloc.GetVecInputs(Context.GetILBlock(Index)); - - LoadLocals(Context, IntInputs, ARegisterType.Int); - LoadLocals(Context, VecInputs, ARegisterType.Vector); - } - private void LoadLocals(AILEmitter Context, long Inputs, ARegisterType BaseType) { for (int Bit = 0; Bit < 64; Bit++) @@ -60,23 +56,22 @@ namespace ChocolArm64.Translation Context.Generator.EmitLdarg(ATranslatedSub.RegistersArgIdx); Context.Generator.Emit(OpCodes.Ldfld, Reg.GetField()); - AILConv.EmitConv( - Context, - Context.GetFieldType(Reg.Type), - Context.GetLocalType(Reg)); - Context.Generator.EmitStloc(Context.GetLocalIndex(Reg)); } } } - private void EmitLdloc(AILEmitter Context, int Index, ARegisterType Type) + private void EmitLdloc(AILEmitter Context, int Index, ARegisterType RegisterType) { - ARegister Reg = new ARegister(Index, Type); + ARegister Reg = new ARegister(Index, RegisterType); Context.Generator.EmitLdloc(Context.GetLocalIndex(Reg)); - AILConv.EmitConv(Context, Context.GetLocalType(Reg), OperType); + if (RegisterType == ARegisterType.Int && + RegisterSize == ARegisterSize.Int32) + { + Context.Generator.Emit(OpCodes.Conv_U4); + } } } } \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILOpCodeStore.cs b/Ryujinx/Cpu/Translation/AILOpCodeStore.cs index 012e24aec..87d3f85a9 100644 --- a/Ryujinx/Cpu/Translation/AILOpCodeStore.cs +++ b/Ryujinx/Cpu/Translation/AILOpCodeStore.cs @@ -1,52 +1,48 @@ using ChocolArm64.State; -using System; using System.Reflection.Emit; namespace ChocolArm64.Translation { struct AILOpCodeStore : IAILEmit { - public AIoType IoType { get; private set; } - - public Type OperType { get; private set; } - public int Index { get; private set; } - public AILOpCodeStore(int Index, AIoType IoType) : this(Index, IoType, null) { } + public AIoType IoType { get; private set; } - public AILOpCodeStore(int Index, AIoType IoType, Type OperType) + public ARegisterSize RegisterSize { get; private set; } + + public AILOpCodeStore(int Index, AIoType IoType) : this(Index, IoType, ARegisterSize.Int64) { } + + public AILOpCodeStore(int Index, AIoType IoType, ARegisterSize RegisterSize) { - this.IoType = IoType; - this.Index = Index; - this.OperType = OperType; + this.IoType = IoType; + this.Index = Index; + this.RegisterSize = RegisterSize; } public void Emit(AILEmitter Context) { switch (IoType & AIoType.Mask) { - case AIoType.Arg: EmitStarg(Context, Index); break; - case AIoType.Fields: EmitStfld(Context, Index); break; + case AIoType.Arg: Context.Generator.EmitStarg(Index); break; + + case AIoType.Fields: + { + long IntOutputs = Context.LocalAlloc.GetIntOutputs(Context.GetILBlock(Index)); + long VecOutputs = Context.LocalAlloc.GetVecOutputs(Context.GetILBlock(Index)); + + StoreLocals(Context, IntOutputs, ARegisterType.Int); + StoreLocals(Context, VecOutputs, ARegisterType.Vector); + + break; + } + case AIoType.Flag: EmitStloc(Context, Index, ARegisterType.Flag); break; case AIoType.Int: EmitStloc(Context, Index, ARegisterType.Int); break; case AIoType.Vector: EmitStloc(Context, Index, ARegisterType.Vector); break; } } - private void EmitStarg(AILEmitter Context, int Index) - { - Context.Generator.EmitStarg(Index); - } - - private void EmitStfld(AILEmitter Context, int Index) - { - long IntOutputs = Context.LocalAlloc.GetIntOutputs(Context.GetILBlock(Index)); - long VecOutputs = Context.LocalAlloc.GetVecOutputs(Context.GetILBlock(Index)); - - StoreLocals(Context, IntOutputs, ARegisterType.Int); - StoreLocals(Context, VecOutputs, ARegisterType.Vector); - } - private void StoreLocals(AILEmitter Context, long Outputs, ARegisterType BaseType) { for (int Bit = 0; Bit < 64; Bit++) @@ -60,21 +56,20 @@ namespace ChocolArm64.Translation Context.Generator.EmitLdarg(ATranslatedSub.RegistersArgIdx); Context.Generator.EmitLdloc(Context.GetLocalIndex(Reg)); - AILConv.EmitConv( - Context, - Context.GetLocalType(Reg), - Context.GetFieldType(Reg.Type)); - Context.Generator.Emit(OpCodes.Stfld, Reg.GetField()); } } } - private void EmitStloc(AILEmitter Context, int Index, ARegisterType Type) + private void EmitStloc(AILEmitter Context, int Index, ARegisterType RegisterType) { - ARegister Reg = new ARegister(Index, Type); + ARegister Reg = new ARegister(Index, RegisterType); - AILConv.EmitConv(Context, OperType, Context.GetLocalType(Reg)); + if (RegisterType == ARegisterType.Int && + RegisterSize == ARegisterSize.Int32) + { + Context.Generator.Emit(OpCodes.Conv_U8); + } Context.Generator.EmitStloc(Context.GetLocalIndex(Reg)); } diff --git a/Ryujinx/OsHle/Horizon.cs b/Ryujinx/OsHle/Horizon.cs index f31088738..01380105c 100644 --- a/Ryujinx/OsHle/Horizon.cs +++ b/Ryujinx/OsHle/Horizon.cs @@ -80,6 +80,8 @@ namespace Ryujinx.OsHle continue; } + Logging.Info($"Loding {Path.GetFileNameWithoutExtension(File)}..."); + using (FileStream Input = new FileStream(File, FileMode.Open)) { Nso Program = new Nso(Input); diff --git a/Ryujinx/OsHle/Process.cs b/Ryujinx/OsHle/Process.cs index 05f12c1a4..d1f020b5d 100644 --- a/Ryujinx/OsHle/Process.cs +++ b/Ryujinx/OsHle/Process.cs @@ -70,6 +70,8 @@ namespace Ryujinx.OsHle public void LoadProgram(IExecutable Program) { + Logging.Info($"Image base at 0x{ImageBase:x16}."); + Executable Executable = new Executable(Program, Memory, ImageBase); Executables.Add(Executable);