diff --git a/Ryujinx/Cpu/AOpCodeTable.cs b/Ryujinx/Cpu/AOpCodeTable.cs index b61326a47e..dcc0f6aaa2 100644 --- a/Ryujinx/Cpu/AOpCodeTable.cs +++ b/Ryujinx/Cpu/AOpCodeTable.cs @@ -11,11 +11,11 @@ namespace ChocolArm64 #region "OpCode Table" //Integer Set("x0011010000xxxxx000000xxxxxxxxxx", AInstEmit.Adc, typeof(AOpCodeAluRs)); - Set("x0010001xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluImm)); - Set("x0001011xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRs)); + Set("x00100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluImm)); + Set("x0001011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRs)); Set("x0001011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRx)); - Set("x0110001xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adds, typeof(AOpCodeAluImm)); - Set("x0101011xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adds, typeof(AOpCodeAluRs)); + Set("x01100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adds, typeof(AOpCodeAluImm)); + Set("x0101011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adds, typeof(AOpCodeAluRs)); Set("x0101011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adds, typeof(AOpCodeAluRx)); Set("0xx10000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adr, typeof(AOpCodeAdr)); Set("1xx10000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adrp, typeof(AOpCodeAdr)); @@ -102,11 +102,11 @@ namespace ChocolArm64 Set("xx111000001xxxxxxxxx10xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeMemReg)); Set("1x001000001xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Stxp, typeof(AOpCodeMemEx)); Set("xx001000000xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Stxr, typeof(AOpCodeMemEx)); - Set("x1010001xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sub, typeof(AOpCodeAluImm)); - Set("x1001011xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sub, typeof(AOpCodeAluRs)); + Set("x10100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sub, typeof(AOpCodeAluImm)); + Set("x1001011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sub, typeof(AOpCodeAluRs)); Set("x1001011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sub, typeof(AOpCodeAluRx)); - Set("x1110001xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Subs, typeof(AOpCodeAluImm)); - Set("x1101011xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Subs, typeof(AOpCodeAluRs)); + Set("x11100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Subs, typeof(AOpCodeAluImm)); + Set("x1101011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Subs, typeof(AOpCodeAluRs)); Set("x1101011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Subs, typeof(AOpCodeAluRx)); Set("11010100000xxxxxxxxxxxxxxxx00001", AInstEmit.Svc, typeof(AOpCodeException)); Set("1101010100001xxxxxxxxxxxxxxxxxxx", AInstEmit.Sys, typeof(AOpCodeSystem)); @@ -119,24 +119,25 @@ namespace ChocolArm64 Set("10011011110xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Umulh, typeof(AOpCodeMul)); //Vector - Set("0x001110xx1xxxxx100001xxxxxxxxxx", AInstEmit.Add_V, typeof(AOpCodeSimdReg)); + Set("0>001110<<1xxxxx100001xxxxxxxxxx", AInstEmit.Add_V, typeof(AOpCodeSimdReg)); Set("01011110xx110001101110xxxxxxxxxx", AInstEmit.Addp_S, typeof(AOpCodeSimd)); - Set("0x001110xx1xxxxx101111xxxxxxxxxx", AInstEmit.Addp_V, typeof(AOpCodeSimdReg)); - Set("0x001110<<110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd)); + Set("0>001110<<1xxxxx101111xxxxxxxxxx", AInstEmit.Addp_V, typeof(AOpCodeSimdReg)); + Set("000011100x110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd)); + Set("01001110<<110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd)); Set("0x001110001xxxxx000111xxxxxxxxxx", AInstEmit.And_V, typeof(AOpCodeSimdReg)); Set("0x001110011xxxxx000111xxxxxxxxxx", AInstEmit.Bic_V, typeof(AOpCodeSimdReg)); Set("0x10111100000xxx<101110<<1xxxxx100011xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimdReg)); + Set("0>001110<<100000100110xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimd)); + Set("0>001110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmge_V, typeof(AOpCodeSimdReg)); + Set("0>101110<<100000100010xxxxxxxxxx", AInstEmit.Cmge_V, typeof(AOpCodeSimd)); + Set("0>001110<<1xxxxx001101xxxxxxxxxx", AInstEmit.Cmgt_V, typeof(AOpCodeSimdReg)); + Set("0>001110<<100000100010xxxxxxxxxx", AInstEmit.Cmgt_V, typeof(AOpCodeSimd)); + Set("0>101110<<1xxxxx001101xxxxxxxxxx", AInstEmit.Cmhi_V, typeof(AOpCodeSimdReg)); + Set("0>101110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmhs_V, typeof(AOpCodeSimdReg)); + Set("0>101110<<100000100110xxxxxxxxxx", AInstEmit.Cmle_V, typeof(AOpCodeSimd)); + Set("0>001110<<100000101010xxxxxxxxxx", AInstEmit.Cmlt_V, typeof(AOpCodeSimd)); Set("0x00111000100000010110xxxxxxxxxx", AInstEmit.Cnt_V, typeof(AOpCodeSimd)); Set("01011110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_S, typeof(AOpCodeSimdIns)); Set("0x001110000xxxxx000011xxxxxxxxxx", AInstEmit.Dup_Gp, typeof(AOpCodeSimdIns)); @@ -199,26 +200,28 @@ namespace ChocolArm64 Set("xx111101x1xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemImm)); Set("xx111100x11xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemReg)); Set("xx011100xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.LdrLit, typeof(AOpCodeSimdMemLit)); - Set("0x001110xx1xxxxx100101xxxxxxxxxx", AInstEmit.Mla_V, typeof(AOpCodeSimdReg)); + Set("0x001110<<1xxxxx100101xxxxxxxxxx", AInstEmit.Mla_V, typeof(AOpCodeSimdReg)); Set("0x00111100000xxx0xx001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); Set("0x00111100000xxx10x001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); Set("0x00111100000xxx110x01xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); Set("0xx0111100000xxx111001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); - Set("0x001110xx1xxxxx100111xxxxxxxxxx", AInstEmit.Mul_V, typeof(AOpCodeSimdReg)); + Set("0x001110<<1xxxxx100111xxxxxxxxxx", AInstEmit.Mul_V, typeof(AOpCodeSimdReg)); Set("0x10111100000xxx0xx001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm)); Set("0x10111100000xxx10x001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm)); Set("0x10111100000xxx110x01xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm)); - Set("0x101110xx100000101110xxxxxxxxxx", AInstEmit.Neg_V, typeof(AOpCodeSimdReg)); + Set("0>101110<<100000101110xxxxxxxxxx", AInstEmit.Neg_V, typeof(AOpCodeSimdReg)); Set("0x10111000100000010110xxxxxxxxxx", AInstEmit.Not_V, typeof(AOpCodeSimd)); Set("0x001110101xxxxx000111xxxxxxxxxx", AInstEmit.Orr_V, typeof(AOpCodeSimdReg)); Set("0x00111100000xxx<>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_S, typeof(AOpCodeSimdShImm)); Set("0x0011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_V, typeof(AOpCodeSimdShImm)); Set("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg)); Set("0x001110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Smin_V, typeof(AOpCodeSimdReg)); - Set("0x001110xx1xxxxx010001xxxxxxxxxx", AInstEmit.Sshl_V, typeof(AOpCodeSimdReg)); + Set("0>001110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Sshl_V, typeof(AOpCodeSimdReg)); Set("0x00111100>>>xxx101001xxxxxxxxxx", AInstEmit.Sshll_V, typeof(AOpCodeSimdShImm)); Set("010111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_S, typeof(AOpCodeSimdShImm)); Set("0x0011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_V, typeof(AOpCodeSimdShImm)); @@ -231,9 +234,7 @@ namespace ChocolArm64 Set("xx111101x0xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm)); Set("xx111100x01xxxxxxxxx10xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemReg)); Set("01111110xx1xxxxx100001xxxxxxxxxx", AInstEmit.Sub_S, typeof(AOpCodeSimdReg)); - Set("0x101110xx1xxxxx100001xxxxxxxxxx", AInstEmit.Sub_V, typeof(AOpCodeSimdReg)); - Set("x0011110xx100010000000xxxxxxxxxx", AInstEmit.Scvtf_Gp, typeof(AOpCodeSimdCvt)); - Set("010111100x100001110110xxxxxxxxxx", AInstEmit.Scvtf_S, typeof(AOpCodeSimd)); + Set("0>101110<<1xxxxx100001xxxxxxxxxx", AInstEmit.Sub_V, typeof(AOpCodeSimdReg)); Set("0x001110000xxxxx0xx000xxxxxxxxxx", AInstEmit.Tbl_V, typeof(AOpCodeSimdTbl)); Set("001011100x110000001110xxxxxxxxxx", AInstEmit.Uaddlv_V, typeof(AOpCodeSimd)); Set("01101110<<110000001110xxxxxxxxxx", AInstEmit.Uaddlv_V, typeof(AOpCodeSimd)); @@ -241,7 +242,7 @@ namespace ChocolArm64 Set("x0011110xx100011000000xxxxxxxxxx", AInstEmit.Ucvtf_Gp, typeof(AOpCodeSimdCvt)); Set("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimdReg)); Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns)); - Set("0x101110xx1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg)); + Set("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg)); Set("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm)); Set("0x1011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_V, typeof(AOpCodeSimdShImm)); Set("0x1011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm)); @@ -311,9 +312,13 @@ namespace ChocolArm64 { InsertTop(XMask, Value, Inst); } - else if ((ZCount & OCount) != 0) + else if (ZCount != 0 && OCount != 0) { - for (int OCtr = 0; (uint)OCtr < (1 << OCount) - 1; OCtr++) + //When both the > and the <, then a value is blacklisted, + //with > indicating 0, and < indicating 1. So, for example, ><< + //blacklists the pattern 011, but 000, 001, 010, 100, 101, + //110 and 111 are valid. + for (int OCtr = 0; (uint)OCtr < (1 << OCount); OCtr++) { int OVal = Value; @@ -322,7 +327,9 @@ namespace ChocolArm64 OVal |= ((OCtr >> O) & 1) << OPos[O]; } - InsertWithCtr(1, 1 << ZCount, ZCount, ZPos, XMask, OVal, Inst); + int ZStart = OCtr == (1 << OCount) ? 1 : 0; + + InsertWithCtr(ZStart, 1 << ZCount, ZCount, ZPos, XMask, OVal, Inst); } } else if (ZCount != 0) diff --git a/Ryujinx/Cpu/Decoder/AOpCodeAluImm.cs b/Ryujinx/Cpu/Decoder/AOpCodeAluImm.cs index 6b0adbc25e..e913475ad2 100644 --- a/Ryujinx/Cpu/Decoder/AOpCodeAluImm.cs +++ b/Ryujinx/Cpu/Decoder/AOpCodeAluImm.cs @@ -15,8 +15,6 @@ namespace ChocolArm64.Decoder int Shift = (OpCode >> 22) & 3; - //Assert Shift < 2 - Imm <<= Shift * 12; } else if (DataOp == ADataOp.Logical) diff --git a/Ryujinx/Cpu/Decoder/AOpCodeAluRs.cs b/Ryujinx/Cpu/Decoder/AOpCodeAluRs.cs index 8439df6f28..9c215be383 100644 --- a/Ryujinx/Cpu/Decoder/AOpCodeAluRs.cs +++ b/Ryujinx/Cpu/Decoder/AOpCodeAluRs.cs @@ -11,11 +11,19 @@ namespace ChocolArm64.Decoder public AOpCodeAluRs(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { - Shift = (OpCode >> 10) & 0x3f; + int Shift = (OpCode >> 10) & 0x3f; + + if (Shift >= GetBitsCount()) + { + Emitter = AInstEmit.Und; + + return; + } + + this.Shift = Shift; + Rm = (OpCode >> 16) & 0x1f; ShiftType = (AShiftType)((OpCode >> 22) & 0x3); - - //Assert ShiftType != 3 } } } \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitException.cs b/Ryujinx/Cpu/Instruction/AInstEmitException.cs index f05d962f29..085bb9aae4 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitException.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitException.cs @@ -1,12 +1,14 @@ using ChocolArm64.Decoder; using ChocolArm64.State; using ChocolArm64.Translation; -using System; +using System.Reflection; namespace ChocolArm64.Instruction { static partial class AInstEmit { + private const BindingFlags Binding = BindingFlags.NonPublic | BindingFlags.Instance; + public static void Brk(AILEmitterCtx Context) { EmitExceptionCall(Context, nameof(ARegisters.OnBreak)); @@ -27,7 +29,9 @@ namespace ChocolArm64.Instruction Context.EmitLdc_I4(Op.Id); - Context.EmitCall(typeof(ARegisters), MthdName); + MethodInfo MthdInfo = typeof(ARegisters).GetMethod(MthdName, Binding); + + Context.EmitCall(MthdInfo); if (Context.CurrBlock.Next != null) { @@ -46,7 +50,11 @@ namespace ChocolArm64.Instruction Context.EmitLdc_I8(Op.Position); Context.EmitLdc_I4(Op.RawOpCode); - Context.EmitCall(typeof(ARegisters), nameof(ARegisters.OnUndefined)); + string MthdName = nameof(ARegisters.OnUndefined); + + MethodInfo MthdInfo = typeof(ARegisters).GetMethod(MthdName, Binding); + + Context.EmitCall(MthdInfo); if (Context.CurrBlock.Next != null) { diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs index 75c308c355..3ff65ea48b 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs @@ -104,8 +104,8 @@ namespace ChocolArm64.Instruction public static void Fadd_V(AILEmitterCtx Context) => EmitVectorBinaryFOp(Context, OpCodes.Add); - public static void Fcvtzs_V(AILEmitterCtx Context) => EmitVectorFcvtS(Context); - public static void Fcvtzu_V(AILEmitterCtx Context) => EmitVectorFcvtU(Context); + public static void Fcvtzs_V(AILEmitterCtx Context) => EmitVectorFcvts(Context); + public static void Fcvtzu_V(AILEmitterCtx Context) => EmitVectorFcvtu(Context); public static void Fmla_V(AILEmitterCtx Context) { @@ -264,19 +264,7 @@ namespace ChocolArm64.Instruction Context.EmitStvec(Op.Rd); } - public static void Scvtf_V(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - Context.EmitLdvec(Op.Rn); - Context.EmitLdc_I4(Op.SizeF); - - ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Scvtf_V64), - nameof(ASoftFallback.Scvtf_V128)); - - Context.EmitStvec(Op.Rd); - } + public static void Scvtf_V(AILEmitterCtx Context) => EmitVectorScvtf(Context); public static void Shl_V(AILEmitterCtx Context) { @@ -346,7 +334,7 @@ namespace ChocolArm64.Instruction nameof(ASoftFallback.Tbl4_V128)); break; default: throw new InvalidOperationException(); - } + } Context.EmitStvec(Op.Rd); } @@ -434,33 +422,12 @@ namespace ChocolArm64.Instruction public static void Ushr_V(AILEmitterCtx Context) { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - Context.EmitLdvec(Op.Rn); - Context.EmitLdc_I4((8 << (Op.Size + 1)) - Op.Imm); - Context.EmitLdc_I4(Op.Size); - - ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Ushr64), - nameof(ASoftFallback.Ushr128)); - - Context.EmitStvec(Op.Rd); + EmitVectorShr(Context, ShrFlags.None); } public static void Usra_V(AILEmitterCtx Context) { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - Context.EmitLdvec(Op.Rd); - Context.EmitLdvec(Op.Rn); - Context.EmitLdc_I4((8 << (Op.Size + 1)) - Op.Imm); - Context.EmitLdc_I4(Op.Size); - - ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Usra64), - nameof(ASoftFallback.Usra128)); - - Context.EmitStvec(Op.Rd); + EmitVectorShr(Context, ShrFlags.Accumulate); } public static void Uzp1_V(AILEmitterCtx Context) @@ -651,11 +618,11 @@ namespace ChocolArm64.Instruction Context.EmitLdc_I4(0); Context.EmitLdc_I4(Op.Size); - EmitVectorExtractZx(Context, Op.Rn, 0); + EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); for (int Index = 1; Index < (Bytes >> Op.Size); Index++) { - EmitVectorExtractZx(Context, Op.Rn, Index); + EmitVectorExtractZx(Context, Op.Rn, Op.Size, Index); Context.Emit(OpCodes.Add); } @@ -730,7 +697,7 @@ namespace ChocolArm64.Instruction int MaxShift = 8 << Op.Size; - EmitVectorBinaryZx(Context, () => + Action Emit = () => { AILLabel LblShl = new AILLabel(); AILLabel LblZero = new AILLabel(); @@ -771,48 +738,83 @@ namespace ChocolArm64.Instruction Context.EmitLdc_I8(0); Context.MarkLabel(LblEnd); - }); + }; + + if (Signed) + { + EmitVectorBinarySx(Context, Emit); + } + else + { + EmitVectorBinaryZx(Context, Emit); + } } - private static void EmitVectorFcvtS(AILEmitterCtx Context) + private enum ShrFlags { - EmitVectorCvtOp(Context, CvtDir.Fcvt, true); + None = 0, + Signed = 1 << 0, + Rounding = 1 << 1, + Accumulate = 1 << 2 } - private static void EmitVectorFcvtU(AILEmitterCtx Context) + private static void EmitVectorShr(AILEmitterCtx Context, ShrFlags Flags) { - EmitVectorCvtOp(Context, CvtDir.Fcvt, false); + 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); + }); + } } - private static void EmitVectorCvtfS(AILEmitterCtx Context) + private static void EmitVectorFcvts(AILEmitterCtx Context) { - EmitVectorCvtOp(Context, CvtDir.Cvtf, true); + EmitVectorFcvtOp(Context, Signed: true); } - private static void EmitVectorCvtfU(AILEmitterCtx Context) + private static void EmitVectorFcvtu(AILEmitterCtx Context) { - EmitVectorCvtOp(Context, CvtDir.Cvtf, false); + EmitVectorFcvtOp(Context, Signed: false); } - private enum CvtDir + private static void EmitVectorScvtf(AILEmitterCtx Context) { - Fcvt, - Cvtf + EmitVectorCvtfOp(Context, Signed: true); } - private static void EmitVectorCvtOp(AILEmitterCtx Context, CvtDir Dir, bool Signed) + private static void EmitVectorUcvtf(AILEmitterCtx Context) + { + EmitVectorCvtfOp(Context, Signed: false); + } + + private static void EmitVectorFcvtOp(AILEmitterCtx Context, bool Signed) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int SizeF = Op.Size & 1; int SizeI = SizeF + 2; - int FBits = 0; - - if (Op is AOpCodeSimdShImm OpImm) - { - FBits = (8 << (Op.Size + 1)) - OpImm.Imm; - } + int FBits = GetFBits(Context); int Bytes = Context.CurrOp.GetBitsCount() >> 3; @@ -822,26 +824,17 @@ namespace ChocolArm64.Instruction Context.EmitLdc_I4(FBits); - if (Dir == CvtDir.Fcvt) + if (SizeF == 0) { - //Float to Integer. - 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)); - } + ASoftFallback.EmitCall(Context, Signed + ? nameof(ASoftFallback.SatSingleToInt32) + : nameof(ASoftFallback.SatSingleToUInt32)); } - else if (Dir == CvtDir.Cvtf) + else if (SizeF == 1) { - //Integer to Float. - //TODO. + ASoftFallback.EmitCall(Context, Signed + ? nameof(ASoftFallback.SatDoubleToInt64) + : nameof(ASoftFallback.SatDoubleToUInt64)); } EmitVectorInsert(Context, Op.Rd, Index, SizeI); @@ -853,6 +846,57 @@ namespace ChocolArm64.Instruction } } + private static void EmitVectorCvtfOp(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; + } + private static void EmitVectorBinaryFOp(AILEmitterCtx Context, OpCode ILOp) { EmitVectorBinaryFOp(Context, () => Context.Emit(ILOp)); @@ -899,36 +943,43 @@ namespace ChocolArm64.Instruction private static void EmitVectorUnarySx(AILEmitterCtx Context, Action Emit) { - EmitVectorOp(Context, Emit, 1, true); + EmitVectorOp(Context, Emit, OperFlags.Rn, true); } private static void EmitVectorBinarySx(AILEmitterCtx Context, Action Emit) { - EmitVectorOp(Context, Emit, 2, true); + EmitVectorOp(Context, Emit, OperFlags.RnRm, true); } private static void EmitVectorUnaryZx(AILEmitterCtx Context, Action Emit) { - EmitVectorOp(Context, Emit, 1, false); + EmitVectorOp(Context, Emit, OperFlags.Rn, false); } private static void EmitVectorBinaryZx(AILEmitterCtx Context, Action Emit) { - EmitVectorOp(Context, Emit, 2, false); + EmitVectorOp(Context, Emit, OperFlags.RnRm, false); } private static void EmitVectorTernaryZx(AILEmitterCtx Context, Action Emit) { - EmitVectorOp(Context, Emit, 3, false); + EmitVectorOp(Context, Emit, OperFlags.RdRnRm, false); } - private static void EmitVectorOp(AILEmitterCtx Context, Action Emit, int Opers, bool Signed) + [Flags] + private enum OperFlags { - if (Opers < 1 || Opers > 3) - { - throw new ArgumentOutOfRangeException(nameof(Opers)); - } + Rd = 1 << 0, + Rn = 1 << 1, + Rm = 1 << 2, + RnRm = Rn | Rm, + RdRn = Rd | Rn, + RdRnRm = Rd | Rn | Rm + } + + private static void EmitVectorOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed) + { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int Bytes = Context.CurrOp.GetBitsCount() >> 3; @@ -939,19 +990,19 @@ namespace ChocolArm64.Instruction Context.EmitLdc_I4(Index); Context.EmitLdc_I4(Op.Size); - if (Opers == 3) + if (Opers.HasFlag(OperFlags.Rd)) { - EmitVectorExtract(Context, Op.Rd, Index, Signed); + EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed); } - if (Opers >= 1) + if (Opers.HasFlag(OperFlags.Rn)) { - EmitVectorExtract(Context, Op.Rn, Index, Signed); + EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); } - if (Opers >= 2) + if (Opers.HasFlag(OperFlags.Rm)) { - EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Signed); + EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed); } Emit(); @@ -999,7 +1050,7 @@ namespace ChocolArm64.Instruction Context.EmitLdc_I4(Index); Context.EmitLdc_I4(Op.Size); - EmitVectorExtract(Context, Op.Rn, Index, Signed); + EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); Context.EmitLdc_I8(Imm); @@ -1026,11 +1077,11 @@ namespace ChocolArm64.Instruction for (int Index = 0; Index < (Bytes >> Op.Size); Index++) { - EmitVectorExtractSx(Context, Op.Rn, Index); + EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size); if (Op is AOpCodeSimdReg BinOp) { - EmitVectorExtractSx(Context, BinOp.Rm, Index); + EmitVectorExtractSx(Context, BinOp.Rm, Index, Op.Size); } else { @@ -1078,29 +1129,39 @@ namespace ChocolArm64.Instruction } } - private static void EmitVectorExtractSx(AILEmitterCtx Context, int Reg, int Index) + private static void EmitVectorExtractSx(AILEmitterCtx Context, int Reg, int Index, int Size) { - EmitVectorExtract(Context, Reg, Index, true); + EmitVectorExtract(Context, Reg, Index, Size, true); } - private static void EmitVectorExtractZx(AILEmitterCtx Context, int Reg, int Index) + private static void EmitVectorExtractZx(AILEmitterCtx Context, int Reg, int Index, int Size) { - EmitVectorExtract(Context, Reg, Index, false); + EmitVectorExtract(Context, Reg, Index, Size, false); } - private static void EmitVectorExtract(AILEmitterCtx Context, int Reg, int Index, bool Signed) + private static void EmitVectorExtract(AILEmitterCtx Context, int Reg, int Index, int Size, bool Signed) { IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; Context.EmitLdvec(Reg); Context.EmitLdc_I4(Index); - Context.EmitLdc_I4(Op.Size); + 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); @@ -1122,16 +1183,6 @@ namespace ChocolArm64.Instruction Context.EmitStvec(Reg); } - 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 EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size) { Context.EmitLdvec(Reg); diff --git a/Ryujinx/Cpu/Instruction/ASoftFallback.cs b/Ryujinx/Cpu/Instruction/ASoftFallback.cs index a7508d7f35..8fe31a2293 100644 --- a/Ryujinx/Cpu/Instruction/ASoftFallback.cs +++ b/Ryujinx/Cpu/Instruction/ASoftFallback.cs @@ -97,39 +97,7 @@ namespace ChocolArm64.Instruction throw new ArgumentException(nameof(Size)); } - public static int SatDoubleToInt32(double Value, int FBits = 0) - { - 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 = 0) - { - 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 = 0) - { - 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 = 0) - { - if (FBits != 0) Value *= Math.Pow(2, FBits); - - return Value > ulong.MaxValue ? ulong.MaxValue : - Value < ulong.MinValue ? ulong.MinValue : (ulong)Value; - } - - public static int SatSingleToInt32(float Value, int FBits = 0) + public static int SatSingleToInt32(float Value, int FBits) { if (FBits != 0) Value *= MathF.Pow(2, FBits); @@ -137,7 +105,7 @@ namespace ChocolArm64.Instruction Value < int.MinValue ? int.MinValue : (int)Value; } - public static long SatSingleToInt64(float Value, int FBits = 0) + public static long SatSingleToInt64(float Value, int FBits) { if (FBits != 0) Value *= MathF.Pow(2, FBits); @@ -145,7 +113,7 @@ namespace ChocolArm64.Instruction Value < long.MinValue ? long.MinValue : (long)Value; } - public static uint SatSingleToUInt32(float Value, int FBits = 0) + public static uint SatSingleToUInt32(float Value, int FBits) { if (FBits != 0) Value *= MathF.Pow(2, FBits); @@ -153,7 +121,7 @@ namespace ChocolArm64.Instruction Value < uint.MinValue ? uint.MinValue : (uint)Value; } - public static ulong SatSingleToUInt64(float Value, int FBits = 0) + public static ulong SatSingleToUInt64(float Value, int FBits) { if (FBits != 0) Value *= MathF.Pow(2, FBits); @@ -161,6 +129,110 @@ namespace ChocolArm64.Instruction Value < ulong.MinValue ? ulong.MinValue : (ulong)Value; } + public static int SatDoubleToInt32(double Value, int FBits) + { + 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) + { + 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) + { + 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) + { + 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 float Int32ToDouble(int Value, int FBits) + { + float ValueF = Value; + + if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits); + + return ValueF; + } + + public static float Int64ToDouble(long Value, int FBits) + { + float ValueF = Value; + + if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits); + + return ValueF; + } + + public static float UInt32ToDouble(uint Value, int FBits) + { + float ValueF = Value; + + if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits); + + return ValueF; + } + + public static float UInt64ToDouble(ulong Value, int FBits) + { + float ValueF = Value; + + if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits); + + return ValueF; + } + public static ulong SMulHi128(ulong LHS, ulong RHS) { long LLo = (uint)(LHS >> 0); @@ -556,44 +628,6 @@ namespace ChocolArm64.Instruction return Res; } - public static AVec Scvtf_V64(AVec Vector, int Size) - { - return Scvtf_V(Vector, Size, 2); - } - - public static AVec Scvtf_V128(AVec Vector, int Size) - { - return Scvtf_V(Vector, Size, 4); - } - - private static AVec Scvtf_V(AVec Vector, int Size, int Bytes) - { - AVec Res = new AVec(); - - int Elems = Bytes >> Size; - - if (Size == 0) - { - for (int Index = 0; Index < Elems; Index++) - { - int Value = (int)ExtractSVec(Vector, Index, Size + 2); - - Res = AVec.InsertSingle(Res, Index, Value); - } - } - else - { - for (int Index = 0; Index < Elems; Index++) - { - long Value = ExtractSVec(Vector, Index, Size + 2); - - Res = AVec.InsertDouble(Res, Index, Value); - } - } - - return Res; - } - public static AVec Sshll(AVec Vector, int Shift, int Size) { return Sshll_(Vector, Shift, Size, false); @@ -785,57 +819,6 @@ namespace ChocolArm64.Instruction return Res; } - public static AVec Ushr64(AVec Vector, int Shift, int Size) - { - return Ushr(Vector, Shift, Size, 8); - } - - public static AVec Ushr128(AVec Vector, int Shift, int Size) - { - return Ushr(Vector, Shift, Size, 16); - } - - private static AVec Ushr(AVec Vector, int Shift, int Size, int Bytes) - { - AVec Res = new AVec(); - - int Elems = Bytes >> Size; - - for (int Index = 0; Index < Elems; Index++) - { - ulong Value = ExtractVec(Vector, Index, Size); - - Res = InsertVec(Res, Index, Size, Value >> Shift); - } - - return Res; - } - - public static AVec Usra64(AVec Res, AVec Vector, int Shift, int Size) - { - return Usra(Res, Vector, Shift, Size, 8); - } - - public static AVec Usra128(AVec Res, AVec Vector, int Shift, int Size) - { - return Usra(Res, Vector, Shift, Size, 16); - } - - private static AVec Usra(AVec Res, AVec Vector, int Shift, int Size, int Bytes) - { - int Elems = Bytes >> Size; - - for (int Index = 0; Index < Elems; Index++) - { - ulong Value = ExtractVec(Vector, Index, Size); - ulong Addend = ExtractVec(Res, Index, Size); - - Res = InsertVec(Res, Index, Size, Addend + (Value >> Shift)); - } - - return Res; - } - public static AVec Uzp1_V64(AVec LHS, AVec RHS, int Size) { return Uzp(LHS, RHS, Size, 0, 8); diff --git a/Ryujinx/Cpu/State/ARegisters.cs b/Ryujinx/Cpu/State/ARegisters.cs index 0765672465..bb93699d54 100644 --- a/Ryujinx/Cpu/State/ARegisters.cs +++ b/Ryujinx/Cpu/State/ARegisters.cs @@ -10,9 +10,6 @@ namespace ChocolArm64.State internal const int ErgSizeLog2 = 4; internal const int DczSizeLog2 = 4; - private const long TicksPerS = 19_200_000; - private const long TicksPerMS = TicksPerS / 1_000; - public ulong X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, @@ -40,23 +37,26 @@ namespace ChocolArm64.State public uint CtrEl0 => 0x8444c004; public uint DczidEl0 => 0x00000004; + private const long TicksPerS = 19_200_000; + private const long TicksPerMS = TicksPerS / 1_000; + public long CntpctEl0 => Environment.TickCount * TicksPerMS; public event EventHandler Break; public event EventHandler SvcCall; - public event EventHandler Undefined; + public event EventHandler Undefined; - public void OnBreak(int Imm) + internal void OnBreak(int Imm) { Break?.Invoke(this, new AInstExceptEventArgs(Imm)); } - public void OnSvcCall(int Imm) + internal void OnSvcCall(int Imm) { SvcCall?.Invoke(this, new AInstExceptEventArgs(Imm)); } - public void OnUndefined(long Position, int RawOpCode) + internal void OnUndefined(long Position, int RawOpCode) { Undefined?.Invoke(this, new AInstUndEventArgs(Position, RawOpCode)); }