diff --git a/ChocolArm64/Instruction/ASoftFallback.cs b/ChocolArm64/Instruction/ASoftFallback.cs index 8ed55e204..3f8ab5e3e 100644 --- a/ChocolArm64/Instruction/ASoftFallback.cs +++ b/ChocolArm64/Instruction/ASoftFallback.cs @@ -153,12 +153,30 @@ namespace ChocolArm64.Instruction public static long SMulHi128(long LHS, long RHS) { - return (long)(BigInteger.Multiply(LHS, RHS) >> 64); + bool LSign = (LHS < 0); + bool RSign = (RHS < 0); + + long Result = (long)UMulHi128((ulong)(LSign ? -LHS : LHS), (ulong)(RSign ? -RHS : RHS)); + + if (LSign != RSign && LHS != 0 && RHS != 0) + return ~Result; //for negative results, hi 64-bits start at 0xFFF... and count back + return Result; } public static ulong UMulHi128(ulong LHS, ulong RHS) { - return (ulong)(BigInteger.Multiply(LHS, RHS) >> 64); + //long multiplication + //multiply 32 bits at a time in 64 bit, the result is what's carried over 64 bits. + ulong LHigh = LHS >> 32; + ulong LLow = LHS & 0xFFFFFFFF; + ulong RHigh = RHS >> 32; + ulong RLow = RHS & 0xFFFFFFFF; + ulong Z2 = LLow * RLow; + ulong T = LHigh * RLow + (Z2 >> 32); + ulong Z1 = T & 0xFFFFFFFF; + ulong Z0 = T >> 32; + Z1 += LLow * RHigh; + return LHigh * RHigh + Z0 + (Z1 >> 32); } } } diff --git a/Ryujinx.HLE/Gpu/NvGpu.cs b/Ryujinx.HLE/Gpu/NvGpu.cs index 1e433fa4b..92071e8eb 100644 --- a/Ryujinx.HLE/Gpu/NvGpu.cs +++ b/Ryujinx.HLE/Gpu/NvGpu.cs @@ -9,8 +9,9 @@ namespace Ryujinx.HLE.Gpu public NvGpuFifo Fifo { get; private set; } - public NvGpuEngine2d Engine2d { get; private set; } - public NvGpuEngine3d Engine3d { get; private set; } + public NvGpuEngine2d Engine2d { get; private set; } + public NvGpuEngine3d Engine3d { get; private set; } + public NvGpuEngineDma EngineDma { get; private set; } private Thread FifoProcessing; @@ -22,8 +23,10 @@ namespace Ryujinx.HLE.Gpu Fifo = new NvGpuFifo(this); - Engine2d = new NvGpuEngine2d(this); - Engine3d = new NvGpuEngine3d(this); + + Engine2d = new NvGpuEngine2d(this); + Engine3d = new NvGpuEngine3d(this); + EngineDma = new NvGpuEngineDma(this); KeepRunning = true; diff --git a/Ryujinx.HLE/Gpu/NvGpuEngineDma.cs b/Ryujinx.HLE/Gpu/NvGpuEngineDma.cs new file mode 100644 index 000000000..48a19047b --- /dev/null +++ b/Ryujinx.HLE/Gpu/NvGpuEngineDma.cs @@ -0,0 +1,142 @@ +using Ryujinx.Graphics.Gal; +using System.Collections.Generic; + +namespace Ryujinx.HLE.Gpu +{ + class NvGpuEngineDma : INvGpuEngine + { + public int[] Registers { get; private set; } + + private NvGpu Gpu; + + private Dictionary Methods; + + public NvGpuEngineDma(NvGpu Gpu) + { + this.Gpu = Gpu; + + Registers = new int[0x1d6]; + + Methods = new Dictionary(); + + void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method) + { + while (Count-- > 0) + { + Methods.Add(Meth, Method); + + Meth += Stride; + } + } + + AddMethod(0xc0, 1, 1, Execute); + } + + public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method)) + { + Method(Vmm, PBEntry); + } + else + { + WriteRegister(PBEntry); + } + } + + private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + int Control = PBEntry.Arguments[0]; + + bool SrcLinear = ((Control >> 7) & 1) != 0; + bool DstLinear = ((Control >> 8) & 1) != 0; + + long SrcAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.SrcAddress); + long DstAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.DstAddress); + + int SrcPitch = ReadRegister(NvGpuEngineDmaReg.SrcPitch); + int DstPitch = ReadRegister(NvGpuEngineDmaReg.DstPitch); + + int DstBlkDim = ReadRegister(NvGpuEngineDmaReg.DstBlkDim); + int DstSizeX = ReadRegister(NvGpuEngineDmaReg.DstSizeX); + int DstSizeY = ReadRegister(NvGpuEngineDmaReg.DstSizeY); + int DstSizeZ = ReadRegister(NvGpuEngineDmaReg.DstSizeZ); + int DstPosXY = ReadRegister(NvGpuEngineDmaReg.DstPosXY); + int DstPosZ = ReadRegister(NvGpuEngineDmaReg.DstPosZ); + + int SrcBlkDim = ReadRegister(NvGpuEngineDmaReg.SrcBlkDim); + int SrcSizeX = ReadRegister(NvGpuEngineDmaReg.SrcSizeX); + int SrcSizeY = ReadRegister(NvGpuEngineDmaReg.SrcSizeY); + int SrcSizeZ = ReadRegister(NvGpuEngineDmaReg.SrcSizeZ); + int SrcPosXY = ReadRegister(NvGpuEngineDmaReg.SrcPosXY); + int SrcPosZ = ReadRegister(NvGpuEngineDmaReg.SrcPosZ); + + int DstPosX = (DstPosXY >> 0) & 0xffff; + int DstPosY = (DstPosXY >> 16) & 0xffff; + + int SrcPosX = (SrcPosXY >> 0) & 0xffff; + int SrcPosY = (SrcPosXY >> 16) & 0xffff; + + int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf); + int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); + + ISwizzle SrcSwizzle; + + if (SrcLinear) + { + SrcSwizzle = new LinearSwizzle(SrcPitch, 1); + } + else + { + SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, 1, SrcBlockHeight); + } + + ISwizzle DstSwizzle; + + if (DstLinear) + { + DstSwizzle = new LinearSwizzle(DstPitch, 1); + } + else + { + DstSwizzle = new BlockLinearSwizzle(DstSizeX, 1, DstBlockHeight); + } + + for (int Y = 0; Y < DstSizeY; Y++) + for (int X = 0; X < DstSizeX; X++) + { + long SrcOffset = SrcAddress + (uint)SrcSwizzle.GetSwizzleOffset(X, Y); + long DstOffset = DstAddress + (uint)DstSwizzle.GetSwizzleOffset(X, Y); + + Vmm.WriteByte(DstOffset, Vmm.ReadByte(SrcOffset)); + } + } + + private long MakeInt64From2xInt32(NvGpuEngineDmaReg Reg) + { + return + (long)Registers[(int)Reg + 0] << 32 | + (uint)Registers[(int)Reg + 1]; + } + + private void WriteRegister(NvGpuPBEntry PBEntry) + { + int ArgsCount = PBEntry.Arguments.Count; + + if (ArgsCount > 0) + { + Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1]; + } + } + + private int ReadRegister(NvGpuEngineDmaReg Reg) + { + return Registers[(int)Reg]; + } + + private void WriteRegister(NvGpuEngineDmaReg Reg, int Value) + { + Registers[(int)Reg] = Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/NvGpuEngineDmaReg.cs b/Ryujinx.HLE/Gpu/NvGpuEngineDmaReg.cs new file mode 100644 index 000000000..55b404c5e --- /dev/null +++ b/Ryujinx.HLE/Gpu/NvGpuEngineDmaReg.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.HLE.Gpu +{ + enum NvGpuEngineDmaReg + { + SrcAddress = 0x100, + DstAddress = 0x102, + SrcPitch = 0x104, + DstPitch = 0x105, + DstBlkDim = 0x1c3, + DstSizeX = 0x1c4, + DstSizeY = 0x1c5, + DstSizeZ = 0x1c6, + DstPosZ = 0x1c7, + DstPosXY = 0x1c8, + SrcBlkDim = 0x1ca, + SrcSizeX = 0x1cb, + SrcSizeY = 0x1cc, + SrcSizeZ = 0x1cd, + SrcPosZ = 0x1ce, + SrcPosXY = 0x1cf + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/NvGpuFifo.cs b/Ryujinx.HLE/Gpu/NvGpuFifo.cs index 0df37edc7..cf3a36486 100644 --- a/Ryujinx.HLE/Gpu/NvGpuFifo.cs +++ b/Ryujinx.HLE/Gpu/NvGpuFifo.cs @@ -136,8 +136,9 @@ namespace Ryujinx.HLE.Gpu { switch (SubChannels[PBEntry.SubChannel]) { - case NvGpuEngine._2d: Call2dMethod(Vmm, PBEntry); break; - case NvGpuEngine._3d: Call3dMethod(Vmm, PBEntry); break; + case NvGpuEngine._2d: Call2dMethod (Vmm, PBEntry); break; + case NvGpuEngine._3d: Call3dMethod (Vmm, PBEntry); break; + case NvGpuEngine.Dma: CallDmaMethod(Vmm, PBEntry); break; } } } @@ -170,5 +171,9 @@ namespace Ryujinx.HLE.Gpu } } } + private void CallDmaMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + Gpu.EngineDma.CallMethod(Vmm, PBEntry); + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/ICommonStateGetter.cs b/Ryujinx.HLE/OsHle/Services/Am/ICommonStateGetter.cs index 2b575cb7c..e1a13c597 100644 --- a/Ryujinx.HLE/OsHle/Services/Am/ICommonStateGetter.cs +++ b/Ryujinx.HLE/OsHle/Services/Am/ICommonStateGetter.cs @@ -13,17 +13,23 @@ namespace Ryujinx.HLE.OsHle.Services.Am public override IReadOnlyDictionary Commands => m_Commands; + private KEvent DisplayResolutionChangeEvent; + public ICommonStateGetter() { m_Commands = new Dictionary() { - { 0, GetEventHandle }, - { 1, ReceiveMessage }, - { 5, GetOperationMode }, - { 6, GetPerformanceMode }, - { 8, GetBootMode }, - { 9, GetCurrentFocusState } + { 0, GetEventHandle }, + { 1, ReceiveMessage }, + { 5, GetOperationMode }, + { 6, GetPerformanceMode }, + { 8, GetBootMode }, + { 9, GetCurrentFocusState }, + { 60, GetDefaultDisplayResolution }, + { 61, GetDefaultDisplayResolutionChangeEvent } }; + + DisplayResolutionChangeEvent = new KEvent(); } public long GetEventHandle(ServiceCtx Context) @@ -78,5 +84,24 @@ namespace Ryujinx.HLE.OsHle.Services.Am return 0; } + + public long GetDefaultDisplayResolution(ServiceCtx Context) + { + Context.ResponseData.Write(1280); + Context.ResponseData.Write(720); + + return 0; + } + + public long GetDefaultDisplayResolutionChangeEvent(ServiceCtx Context) + { + int Handle = Context.Process.HandleTable.OpenHandle(DisplayResolutionChangeEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlService.cs b/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlService.cs index eb363ade1..60a69f58c 100644 --- a/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlService.cs +++ b/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlService.cs @@ -1,3 +1,4 @@ +using Ryujinx.HLE.Logging; using Ryujinx.HLE.OsHle.Ipc; using System.Collections.Generic; @@ -9,12 +10,32 @@ namespace Ryujinx.HLE.OsHle.Services.Pctl public override IReadOnlyDictionary Commands => m_Commands; - public IParentalControlService() + private bool Initialized = false; + + private bool NeedInitialize; + + public IParentalControlService(bool NeedInitialize = true) { m_Commands = new Dictionary() { - //... + { 1, Initialize } }; + + this.NeedInitialize = NeedInitialize; + } + + public long Initialize(ServiceCtx Context) + { + if (NeedInitialize && !Initialized) + { + Initialized = true; + } + else + { + Context.Ns.Log.PrintWarning(LogClass.ServicePctl, "Service is already initialized!"); + } + + return 0; } } } \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlServiceFactory.cs b/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlServiceFactory.cs index 094245f6b..7ef91d7fb 100644 --- a/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlServiceFactory.cs +++ b/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlServiceFactory.cs @@ -13,15 +13,23 @@ namespace Ryujinx.HLE.OsHle.Services.Pctl { m_Commands = new Dictionary() { - { 0, CreateService } + { 0, CreateService }, + { 1, CreateServiceWithoutInitialize } }; } - public static long CreateService(ServiceCtx Context) + public long CreateService(ServiceCtx Context) { MakeObject(Context, new IParentalControlService()); return 0; } + + public long CreateServiceWithoutInitialize(ServiceCtx Context) + { + MakeObject(Context, new IParentalControlService(false)); + + return 0; + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Set/ISettingsServer.cs b/Ryujinx.HLE/OsHle/Services/Set/ISettingsServer.cs index 96297ad2b..abab93822 100644 --- a/Ryujinx.HLE/OsHle/Services/Set/ISettingsServer.cs +++ b/Ryujinx.HLE/OsHle/Services/Set/ISettingsServer.cs @@ -15,7 +15,8 @@ namespace Ryujinx.HLE.OsHle.Services.Set { { 0, GetLanguageCode }, { 1, GetAvailableLanguageCodes }, - { 3, GetAvailableLanguageCodeCount } + { 3, GetAvailableLanguageCodeCount }, + { 5, GetAvailableLanguageCodes2 } }; } @@ -27,10 +28,28 @@ namespace Ryujinx.HLE.OsHle.Services.Set } public static long GetAvailableLanguageCodes(ServiceCtx Context) - { - long Position = Context.Request.RecvListBuff[0].Position; - long Size = Context.Request.RecvListBuff[0].Size; + { + GetAvailableLanguagesCodesMethod(Context, Context.Request.RecvListBuff[0].Position, Context.Request.RecvListBuff[0].Size); + + return 0; + } + public static long GetAvailableLanguageCodeCount(ServiceCtx Context) + { + Context.ResponseData.Write(SystemStateMgr.LanguageCodes.Length); + + return 0; + } + + public static long GetAvailableLanguageCodes2(ServiceCtx Context) + { + GetAvailableLanguagesCodesMethod(Context, Context.Request.ReceiveBuff[0].Position, Context.Request.ReceiveBuff[0].Size); + + return 0; + } + + public static long GetAvailableLanguagesCodesMethod(ServiceCtx Context, long Position, long Size) + { int Count = (int)(Size / 8); if (Count > SystemStateMgr.LanguageCodes.Length) @@ -46,15 +65,8 @@ namespace Ryujinx.HLE.OsHle.Services.Set } Context.ResponseData.Write(Count); - - return 0; - } - - public static long GetAvailableLanguageCodeCount(ServiceCtx Context) - { - Context.ResponseData.Write(SystemStateMgr.LanguageCodes.Length); - - return 0; - } + + return 0; + } } -} \ No newline at end of file +}