diff --git a/ChocolArm64/AOpCodeTable.cs b/ChocolArm64/AOpCodeTable.cs index 5db495af94..6b250b4b00 100644 --- a/ChocolArm64/AOpCodeTable.cs +++ b/ChocolArm64/AOpCodeTable.cs @@ -183,7 +183,7 @@ namespace ChocolArm64 Set("000111100x1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg)); Set("000111100x1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg)); Set("0>0011100<1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg)); - Set("0x0011111<1011100<1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg)); - Set("0x0011111<> 11) & 1; - } - else - { - Index = (OpCode >> 21) & 1 | - (OpCode >> 10) & 2; + case 1: + Index = (OpCode >> 21) & 1 | + (OpCode >> 10) & 2 | + (OpCode >> 18) & 4; + + Rm &= 0xf; + + break; + + case 2: + Index = (OpCode >> 21) & 1 | + (OpCode >> 10) & 2; + + break; + + default: Emitter = AInstEmit.Und; return; } + + } } } \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdRegElemF.cs b/ChocolArm64/Decoder/AOpCodeSimdRegElemF.cs new file mode 100644 index 0000000000..e61d7093a7 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdRegElemF.cs @@ -0,0 +1,22 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdRegElemF : AOpCodeSimdReg + { + public int Index { get; private set; } + + public AOpCodeSimdRegElemF(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + if ((Size & 1) != 0) + { + Index = (OpCode >> 11) & 1; + } + else + { + Index = (OpCode >> 21) & 1 | + (OpCode >> 10) & 2; + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs index 9c1bc28626..9f5cc64f4c 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs @@ -341,6 +341,11 @@ namespace ChocolArm64.Instruction EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul)); } + public static void Mul_Ve(AILEmitterCtx Context) + { + EmitVectorBinaryOpByElemZx(Context, () => Context.Emit(OpCodes.Mul)); + } + public static void Neg_V(AILEmitterCtx Context) { EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg)); diff --git a/ChocolArm64/Instruction/AInstEmitSimdCvt.cs b/ChocolArm64/Instruction/AInstEmitSimdCvt.cs index e97027777e..b9944e565f 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdCvt.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdCvt.cs @@ -99,6 +99,11 @@ namespace ChocolArm64.Instruction EmitVectorInsertF(Context, Op.Rd, Part + Index, 0); } } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } } public static void Fcvtps_Gp(AILEmitterCtx Context) diff --git a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs index 68ee3d3e4e..33e4d54874 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs @@ -200,20 +200,6 @@ namespace ChocolArm64.Instruction EmitVectorOpF(Context, Emit, OperFlags.RdRnRm); } - public static void EmitVectorBinaryOpByElemF(AILEmitterCtx Context, Action Emit) - { - AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; - - EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: false); - } - - public static void EmitVectorTernaryOpByElemF(AILEmitterCtx Context, Action Emit) - { - AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; - - EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: true); - } - public static void EmitVectorOpF(AILEmitterCtx Context, Action Emit, OperFlags Opers) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; @@ -250,6 +236,20 @@ namespace ChocolArm64.Instruction } } + public static void EmitVectorBinaryOpByElemF(AILEmitterCtx Context, Action Emit) + { + AOpCodeSimdRegElemF Op = (AOpCodeSimdRegElemF)Context.CurrOp; + + EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: false); + } + + public static void EmitVectorTernaryOpByElemF(AILEmitterCtx Context, Action Emit) + { + AOpCodeSimdRegElemF Op = (AOpCodeSimdRegElemF)Context.CurrOp; + + EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: true); + } + public static void EmitVectorOpByElemF(AILEmitterCtx Context, Action Emit, int Elem, bool Ternary) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; @@ -341,6 +341,54 @@ namespace ChocolArm64.Instruction } } + public static void EmitVectorBinaryOpByElemSx(AILEmitterCtx Context, Action Emit) + { + AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; + + EmitVectorOpByElem(Context, Emit, Op.Index, false, true); + } + + public static void EmitVectorBinaryOpByElemZx(AILEmitterCtx Context, Action Emit) + { + AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; + + EmitVectorOpByElem(Context, Emit, Op.Index, false, false); + } + + public static void EmitVectorTernaryOpByElemZx(AILEmitterCtx Context, Action Emit) + { + AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; + + EmitVectorOpByElem(Context, Emit, Op.Index, true, false); + } + + public static void EmitVectorOpByElem(AILEmitterCtx Context, Action Emit, int Elem, bool Ternary, bool Signed) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + if (Ternary) + { + EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed); + } + + EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); + EmitVectorExtract(Context, 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); diff --git a/Ryujinx.Core/OsHle/ErrorCode.cs b/Ryujinx.Core/OsHle/ErrorCode.cs new file mode 100644 index 0000000000..4210b23000 --- /dev/null +++ b/Ryujinx.Core/OsHle/ErrorCode.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Core.OsHle +{ + static class ErrorCode + { + public static uint MakeError(ErrorModule Module, int Code) + { + return (uint)Module | ((uint)Code << 9); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ErrorModule.cs b/Ryujinx.Core/OsHle/ErrorModule.cs similarity index 98% rename from Ryujinx.Core/OsHle/Services/ErrorModule.cs rename to Ryujinx.Core/OsHle/ErrorModule.cs index 78af6195db..f23e8d2703 100644 --- a/Ryujinx.Core/OsHle/Services/ErrorModule.cs +++ b/Ryujinx.Core/OsHle/ErrorModule.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Core.OsHle.IpcServices +namespace Ryujinx.Core.OsHle { enum ErrorModule { diff --git a/Ryujinx.Core/OsHle/KernelErr.cs b/Ryujinx.Core/OsHle/KernelErr.cs new file mode 100644 index 0000000000..19983af19d --- /dev/null +++ b/Ryujinx.Core/OsHle/KernelErr.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.Core.OsHle +{ + static class KernelErr + { + public const int InvalidMemRange = 110; + public const int InvalidHandle = 114; + public const int Timeout = 117; + public const int InvalidInfo = 120; + public const int InvalidIpcReq = 123; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ErrorCode.cs b/Ryujinx.Core/OsHle/Services/ErrorCode.cs deleted file mode 100644 index a4e197b225..0000000000 --- a/Ryujinx.Core/OsHle/Services/ErrorCode.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.Core.OsHle.IpcServices -{ - static class ErrorCode - { - public static long MakeError(ErrorModule Module, int Code) - { - return (int)Module | (Code << 9); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs index 569a7dd6b4..62bcb8e8b2 100644 --- a/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Text; -using static Ryujinx.Core.OsHle.IpcServices.ErrorCode; +using static Ryujinx.Core.OsHle.ErrorCode; using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; namespace Ryujinx.Core.OsHle.IpcServices.FspSrv diff --git a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs index 6969d37936..1bb3011b83 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs @@ -2,6 +2,8 @@ using ChocolArm64.Memory; using ChocolArm64.State; using Ryujinx.Core.OsHle.Handles; +using static Ryujinx.Core.OsHle.ErrorCode; + namespace Ryujinx.Core.OsHle.Svc { partial class SvcHandler @@ -23,7 +25,7 @@ namespace Ryujinx.Core.OsHle.Svc CurrentHeapSize = Size; - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; ThreadState.X1 = (ulong)Position; } @@ -44,7 +46,7 @@ namespace Ryujinx.Core.OsHle.Svc Memory.Manager.SetAttrBit(Position, Size, 3); } - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcMapMemory(AThreadState ThreadState) @@ -61,7 +63,7 @@ namespace Ryujinx.Core.OsHle.Svc Memory.Manager.SetAttrBit(Src, Size, 0); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcUnmapMemory(AThreadState ThreadState) @@ -78,7 +80,7 @@ namespace Ryujinx.Core.OsHle.Svc Memory.Manager.ClearAttrBit(Src, Size, 0); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcQueryMemory(AThreadState ThreadState) @@ -86,12 +88,13 @@ namespace Ryujinx.Core.OsHle.Svc long InfoPtr = (long)ThreadState.X0; long Position = (long)ThreadState.X2; + Position &= uint.MaxValue; + AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position); if (MapInfo == null) { - //TODO: Correct error code. - ThreadState.X0 = ulong.MaxValue; + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); return; } @@ -106,7 +109,7 @@ namespace Ryujinx.Core.OsHle.Svc Memory.WriteInt32(InfoPtr + 0x24, 0); //TODO: X1. - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; ThreadState.X1 = 0; } @@ -127,7 +130,7 @@ namespace Ryujinx.Core.OsHle.Svc Memory.Manager.Map(Src, Size, (int)MemoryType.SharedMemory, (AMemoryPerm)Perm); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } //TODO: Error codes. @@ -143,7 +146,7 @@ namespace Ryujinx.Core.OsHle.Svc if (HndData != null) { - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } //TODO: Error codes. @@ -164,7 +167,7 @@ namespace Ryujinx.Core.OsHle.Svc int Handle = Ns.Os.Handles.GenerateId(HndData); ThreadState.X1 = (ulong)Handle; - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Svc/SvcResult.cs b/Ryujinx.Core/OsHle/Svc/SvcResult.cs deleted file mode 100644 index a5be9a9457..0000000000 --- a/Ryujinx.Core/OsHle/Svc/SvcResult.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.Core.OsHle.Svc -{ - enum SvcResult - { - Success = 0, - ErrBadHandle = 0xe401, - ErrTimeout = 0xea01, - ErrBadInfo = 0xf001, - ErrBadIpcReq = 0xf601 - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs index d0459f2f24..8a0a391750 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs @@ -7,6 +7,8 @@ using Ryujinx.Core.OsHle.IpcServices; using System; using System.Threading; +using static Ryujinx.Core.OsHle.ErrorCode; + namespace Ryujinx.Core.OsHle.Svc { partial class SvcHandler @@ -26,7 +28,7 @@ namespace Ryujinx.Core.OsHle.Svc //TODO: Implement events. - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcCloseHandle(AThreadState ThreadState) @@ -35,7 +37,7 @@ namespace Ryujinx.Core.OsHle.Svc Ns.Os.CloseHandle(Handle); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcResetSignal(AThreadState ThreadState) @@ -44,7 +46,7 @@ namespace Ryujinx.Core.OsHle.Svc //TODO: Implement events. - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcWaitSynchronization(AThreadState ThreadState) @@ -60,7 +62,7 @@ namespace Ryujinx.Core.OsHle.Svc Process.Scheduler.Suspend(CurrThread.ProcessorId); Process.Scheduler.Resume(CurrThread); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcGetSystemTick(AThreadState ThreadState) @@ -81,7 +83,7 @@ namespace Ryujinx.Core.OsHle.Svc HSession Session = new HSession(ServiceFactory.MakeService(Name)); ThreadState.X1 = (ulong)Ns.Os.Handles.GenerateId(Session); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcSendSyncRequest(AThreadState ThreadState) @@ -127,11 +129,11 @@ namespace Ryujinx.Core.OsHle.Svc byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } else { - ThreadState.X0 = (int)SvcResult.ErrBadIpcReq; + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidIpcReq); } Thread.Yield(); @@ -157,7 +159,7 @@ namespace Ryujinx.Core.OsHle.Svc Logging.Info($"SvcOutputDebugString: {Str}"); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcGetInfo(AThreadState ThreadState) @@ -171,7 +173,7 @@ namespace Ryujinx.Core.OsHle.Svc if (InfoType == 18 || InfoType == 19) { - ThreadState.X0 = (int)SvcResult.ErrBadInfo; + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidInfo); return; } @@ -233,7 +235,7 @@ namespace Ryujinx.Core.OsHle.Svc default: throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle} {InfoId}"); } - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } } } diff --git a/Ryujinx.Core/OsHle/Svc/SvcThread.cs b/Ryujinx.Core/OsHle/Svc/SvcThread.cs index cc0f980be3..6afd2e6106 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcThread.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcThread.cs @@ -28,7 +28,7 @@ namespace Ryujinx.Core.OsHle.Svc Priority, ProcessorId); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; ThreadState.X1 = (ulong)Handle; } @@ -45,7 +45,7 @@ namespace Ryujinx.Core.OsHle.Svc { Process.Scheduler.StartThread(Thread); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } //TODO: Error codes. @@ -75,8 +75,8 @@ namespace Ryujinx.Core.OsHle.Svc if (Thread != null) { + ThreadState.X0 = 0; ThreadState.X1 = (ulong)Thread.Priority; - ThreadState.X0 = (int)SvcResult.Success; } //TODO: Error codes. @@ -93,7 +93,7 @@ namespace Ryujinx.Core.OsHle.Svc { Thread.Priority = Prio; - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } //TODO: Error codes. @@ -101,7 +101,7 @@ namespace Ryujinx.Core.OsHle.Svc private void SvcSetThreadCoreMask(AThreadState ThreadState) { - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; //TODO: Error codes. } @@ -114,8 +114,8 @@ namespace Ryujinx.Core.OsHle.Svc if (Thread != null) { + ThreadState.X0 = 0; ThreadState.X1 = (ulong)Thread.ThreadId; - ThreadState.X0 = (int)SvcResult.Success; } //TODO: Error codes. diff --git a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs index 2705272a39..6e488da589 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs @@ -1,6 +1,8 @@ using ChocolArm64.State; using Ryujinx.Core.OsHle.Handles; +using static Ryujinx.Core.OsHle.ErrorCode; + namespace Ryujinx.Core.OsHle.Svc { partial class SvcHandler @@ -19,7 +21,7 @@ namespace Ryujinx.Core.OsHle.Svc M.WaitForLock(RequestingThread, RequestingThreadHandle); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcArbitrateUnlock(AThreadState ThreadState) @@ -31,7 +33,7 @@ namespace Ryujinx.Core.OsHle.Svc M.Unlock(); } - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcWaitProcessWideKeyAtomic(AThreadState ThreadState) @@ -55,14 +57,14 @@ namespace Ryujinx.Core.OsHle.Svc if (!Cv.WaitForSignal(Thread)) { - ThreadState.X0 = (int)SvcResult.ErrTimeout; + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.Timeout); return; } M.WaitForLock(Thread, ThreadHandle); - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } private void SvcSignalProcessWideKey(AThreadState ThreadState) @@ -77,7 +79,7 @@ namespace Ryujinx.Core.OsHle.Svc Cv.SetSignal(CurrThread, Count); } - ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X0 = 0; } } } \ No newline at end of file