diff --git a/Ryujinx/Cpu/AOpCodeTable.cs b/Ryujinx/Cpu/AOpCodeTable.cs index dcc0f6aaa2..267b0d80b1 100644 --- a/Ryujinx/Cpu/AOpCodeTable.cs +++ b/Ryujinx/Cpu/AOpCodeTable.cs @@ -219,14 +219,17 @@ namespace ChocolArm64 Set("0x0011100x100001110110xxxxxxxxxx", AInstEmit.Scvtf_V, typeof(AOpCodeSimd)); Set("010111110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_S, typeof(AOpCodeSimdShImm)); Set("0x0011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_V, typeof(AOpCodeSimdShImm)); + Set("0x00111100>>>xxx100001xxxxxxxxxx", AInstEmit.Shrn_V, typeof(AOpCodeSimdShImm)); Set("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg)); Set("0x001110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Smin_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)); - Set("0x00110000000000xxxxxxxxxxxxxxxx", AInstEmit.St__V, typeof(AOpCodeSimdMemMs)); - Set("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__V, typeof(AOpCodeSimdMemMs)); + Set("0x00110000000000xxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs)); + Set("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs)); + Set("0x00110100000000xx0xxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs)); + Set("0x001101100xxxxxxx0xxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs)); Set("xx10110xx0xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Stp, typeof(AOpCodeSimdMemPair)); Set("xx111100x00xxxxxxxxx00xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm)); Set("xx111100x00xxxxxxxxx01xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm)); @@ -293,7 +296,7 @@ namespace ChocolArm64 //The < means that we should never have ALL bits with the '<' set. //So, when the encoding has <<, it means that 00, 01, and 10 are valid, //but not 11. <<< is 000, 001, ..., 110 but NOT 111, and so on... - //For >, the invalid value is zero. So, for << 01, 10 and 11 are valid, + //For >, the invalid value is zero. So, for >> 01, 10 and 11 are valid, //but 00 isn't. switch (Encoding[Index]) { diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs index 3ff65ea48b..08fd5807ea 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs @@ -273,6 +273,13 @@ namespace ChocolArm64.Instruction EmitVectorImmBinaryZx(Context, OpCodes.Shl, Op.Imm - (8 << Op.Size)); } + public static void Shrn_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + EmitVectorImmNarrowBinaryZx(Context, OpCodes.Shr_Un, (8 << (Op.Size + 1)) - Op.Imm); + } + public static void Smax_V(AILEmitterCtx Context) => EmitVectorSmax(Context); public static void Smin_V(AILEmitterCtx Context) => EmitVectorSmin(Context); @@ -300,7 +307,8 @@ namespace ChocolArm64.Instruction EmitVectorImmBinarySx(Context, OpCodes.Shr, (8 << (Op.Size + 1)) - Op.Imm); } - public static void St__V(AILEmitterCtx Context) => EmitSimdMemMs(Context, IsLoad: false); + 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, OpCodes.Sub); @@ -622,7 +630,7 @@ namespace ChocolArm64.Instruction for (int Index = 1; Index < (Bytes >> Op.Size); Index++) { - EmitVectorExtractZx(Context, Op.Rn, Op.Size, Index); + EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); Context.Emit(OpCodes.Add); } @@ -986,10 +994,6 @@ namespace ChocolArm64.Instruction for (int Index = 0; Index < (Bytes >> Op.Size); Index++) { - Context.EmitLdvec(Op.Rd); - Context.EmitLdc_I4(Index); - Context.EmitLdc_I4(Op.Size); - if (Opers.HasFlag(OperFlags.Rd)) { EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed); @@ -1007,9 +1011,7 @@ namespace ChocolArm64.Instruction Emit(); - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec)); - - Context.EmitStvec(Op.Rd); + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); } if (Op.RegisterSize == ARegisterSize.SIMD64) @@ -1018,27 +1020,27 @@ namespace ChocolArm64.Instruction } } - private static void EmitVectorImmBinarySx(AILEmitterCtx Context, OpCode ILOp, long Imm) + private static void EmitVectorImmBinarySx(AILEmitterCtx Context, OpCode ILOp, int Imm) { EmitVectorImmBinarySx(Context, () => Context.Emit(ILOp), Imm); } - private static void EmitVectorImmBinaryZx(AILEmitterCtx Context, OpCode ILOp, long Imm) + private static void EmitVectorImmBinaryZx(AILEmitterCtx Context, OpCode ILOp, int Imm) { EmitVectorImmBinaryZx(Context, () => Context.Emit(ILOp), Imm); } - private static void EmitVectorImmBinarySx(AILEmitterCtx Context, Action Emit, long Imm) + private static void EmitVectorImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm) { EmitVectorImmBinaryOp(Context, Emit, Imm, true); } - private static void EmitVectorImmBinaryZx(AILEmitterCtx Context, Action Emit, long Imm) + private static void EmitVectorImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) { EmitVectorImmBinaryOp(Context, Emit, Imm, false); } - private static void EmitVectorImmBinaryOp(AILEmitterCtx Context, Action Emit, long Imm, bool Signed) + private static void EmitVectorImmBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) { AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; @@ -1046,19 +1048,13 @@ namespace ChocolArm64.Instruction for (int Index = 0; Index < (Bytes >> Op.Size); Index++) { - Context.EmitLdvec(Op.Rd); - Context.EmitLdc_I4(Index); - Context.EmitLdc_I4(Op.Size); + EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); - EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); - - Context.EmitLdc_I8(Imm); + Context.EmitLdc_I4(Imm); Emit(); - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec)); - - Context.EmitStvec(Op.Rd); + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); } if (Op.RegisterSize == ARegisterSize.SIMD64) @@ -1067,6 +1063,56 @@ namespace ChocolArm64.Instruction } } + private static void EmitVectorImmNarrowBinarySx(AILEmitterCtx Context, OpCode ILOp, int Imm) + { + EmitVectorImmNarrowBinarySx(Context, () => Context.Emit(ILOp), Imm); + } + + private static void EmitVectorImmNarrowBinaryZx(AILEmitterCtx Context, OpCode ILOp, int Imm) + { + EmitVectorImmNarrowBinaryZx(Context, () => Context.Emit(ILOp), Imm); + } + + private static void EmitVectorImmNarrowBinarySx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorImmNarrowBinaryOp(Context, Emit, Imm, true); + } + + private static void EmitVectorImmNarrowBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorImmNarrowBinaryOp(Context, Emit, Imm, false); + } + + private static void EmitVectorImmNarrowBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + if (Op.Size < 0 || Op.Size > 2) + { + throw new InvalidOperationException(Op.Size.ToString()); + } + + 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 EmitVectorCmp(AILEmitterCtx Context, OpCode ILOp) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; @@ -1141,6 +1187,11 @@ namespace ChocolArm64.Instruction 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); @@ -1185,6 +1236,11 @@ namespace ChocolArm64.Instruction 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); @@ -1196,6 +1252,11 @@ namespace ChocolArm64.Instruction 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); diff --git a/Ryujinx/OsHle/Ipc/IpcHandler.cs b/Ryujinx/OsHle/Ipc/IpcHandler.cs index c373d2cef6..f127891458 100644 --- a/Ryujinx/OsHle/Ipc/IpcHandler.cs +++ b/Ryujinx/OsHle/Ipc/IpcHandler.cs @@ -62,10 +62,12 @@ namespace Ryujinx.OsHle.Ipc { ( "time:u", 1), Service.TimeGetStandardNetworkSystemClock }, { ( "time:u", 2), Service.TimeGetStandardSteadyClock }, { ( "time:u", 3), Service.TimeGetTimeZoneService }, + { ( "time:u", 4), Service.TimeGetStandardLocalSystemClock }, { ( "time:s", 0), Service.TimeGetStandardUserSystemClock }, { ( "time:s", 1), Service.TimeGetStandardNetworkSystemClock }, { ( "time:s", 2), Service.TimeGetStandardSteadyClock }, { ( "time:s", 3), Service.TimeGetTimeZoneService }, + { ( "time:s", 4), Service.TimeGetStandardLocalSystemClock }, { ( "vi:m", 2), Service.ViGetDisplayService }, }; diff --git a/Ryujinx/OsHle/Objects/Time/ISystemClock.cs b/Ryujinx/OsHle/Objects/Time/ISystemClock.cs index 2c5b898b7d..6705a5a192 100644 --- a/Ryujinx/OsHle/Objects/Time/ISystemClock.cs +++ b/Ryujinx/OsHle/Objects/Time/ISystemClock.cs @@ -12,16 +12,28 @@ namespace Ryujinx.OsHle.Objects.Time private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - public ISystemClock() + private SystemClockType ClockType; + + public ISystemClock(SystemClockType ClockType) { m_Commands = new Dictionary() { { 0, GetCurrentTime } }; + + this.ClockType = ClockType; } public long GetCurrentTime(ServiceCtx Context) { + DateTime CurrentTime = DateTime.Now; + + if (ClockType == SystemClockType.Standard || + ClockType == SystemClockType.Network) + { + CurrentTime = CurrentTime.ToUniversalTime(); + } + Context.ResponseData.Write((long)(DateTime.Now - Epoch).TotalSeconds); return 0; diff --git a/Ryujinx/OsHle/Objects/Time/SystemClockType.cs b/Ryujinx/OsHle/Objects/Time/SystemClockType.cs new file mode 100644 index 0000000000..052152b70a --- /dev/null +++ b/Ryujinx/OsHle/Objects/Time/SystemClockType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.OsHle.Objects.Time +{ + enum SystemClockType + { + Standard, + Network, + Local + } +} \ No newline at end of file diff --git a/Ryujinx/OsHle/Process.cs b/Ryujinx/OsHle/Process.cs index 624ab65466..653d9dfda7 100644 --- a/Ryujinx/OsHle/Process.cs +++ b/Ryujinx/OsHle/Process.cs @@ -30,7 +30,7 @@ namespace Ryujinx.OsHle public KProcessScheduler Scheduler { get; private set; } - private SvcHandler SvcHandler; + private SvcHandler SvcHandler; private ConcurrentDictionary TlsSlots; diff --git a/Ryujinx/OsHle/Services/ServiceTime.cs b/Ryujinx/OsHle/Services/ServiceTime.cs index 4f8e34e97b..bcc046ef6a 100644 --- a/Ryujinx/OsHle/Services/ServiceTime.cs +++ b/Ryujinx/OsHle/Services/ServiceTime.cs @@ -8,14 +8,14 @@ namespace Ryujinx.OsHle.Services { public static long TimeGetStandardUserSystemClock(ServiceCtx Context) { - MakeObject(Context, new ISystemClock()); + MakeObject(Context, new ISystemClock(SystemClockType.Standard)); return 0; } public static long TimeGetStandardNetworkSystemClock(ServiceCtx Context) { - MakeObject(Context, new ISystemClock()); + MakeObject(Context, new ISystemClock(SystemClockType.Network)); return 0; } @@ -33,5 +33,13 @@ namespace Ryujinx.OsHle.Services return 0; } + + public static long TimeGetStandardLocalSystemClock(ServiceCtx Context) + { + MakeObject(Context, new ISystemClock(SystemClockType.Local)); + + return 0; + } + } } \ No newline at end of file