From c2c765b30fdfa9184df580133e22ae946eebc022 Mon Sep 17 00:00:00 2001 From: Thomas Guillemard Date: Tue, 17 Jul 2018 21:14:27 +0200 Subject: [PATCH 1/3] hbabi: Implement argv (#272) This commit implements the argv config key in Ryujinx (by creating a temporary copy of the homebrew executable in the sdmc VFS) to make it possible to load libnx's "romfs" files. This commit also call Os.Dispose in Ns.OnFinish to dispose all resources when exiting --- Ryujinx.HLE/Loaders/Executable.cs | 6 +++- .../Loaders/Executables/IExecutable.cs | 2 +- Ryujinx.HLE/Loaders/Executables/Nro.cs | 6 ++-- Ryujinx.HLE/Loaders/Executables/Nso.cs | 4 +-- Ryujinx.HLE/OsHle/Homebrew.cs | 10 ++++++- Ryujinx.HLE/OsHle/Horizon.cs | 29 +++++++++++++++---- Ryujinx.HLE/OsHle/Process.cs | 10 ++++++- Ryujinx.HLE/Switch.cs | 3 +- Ryujinx.HLE/VirtualFileSystem.cs | 29 +++++++++++++++++++ Ryujinx/Ui/Program.cs | 1 + 10 files changed, 84 insertions(+), 16 deletions(-) diff --git a/Ryujinx.HLE/Loaders/Executable.cs b/Ryujinx.HLE/Loaders/Executable.cs index 618ee241a..43193245a 100644 --- a/Ryujinx.HLE/Loaders/Executable.cs +++ b/Ryujinx.HLE/Loaders/Executable.cs @@ -2,6 +2,7 @@ using ChocolArm64.Memory; using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.OsHle; using System.Collections.Generic; +using System.IO; namespace Ryujinx.HLE.Loaders { @@ -15,6 +16,8 @@ namespace Ryujinx.HLE.Loaders public string Name { get; private set; } + public string FilePath { get; private set; } + private AMemory Memory; public long ImageBase { get; private set; } @@ -26,8 +29,9 @@ namespace Ryujinx.HLE.Loaders m_SymbolTable = new Dictionary(); - Name = Exe.Name; + FilePath = Exe.FilePath; + Name = Path.GetFileNameWithoutExtension(FilePath.Replace(Homebrew.TemporaryNroSuffix, "")); this.Memory = Memory; this.ImageBase = ImageBase; this.ImageEnd = ImageBase; diff --git a/Ryujinx.HLE/Loaders/Executables/IExecutable.cs b/Ryujinx.HLE/Loaders/Executables/IExecutable.cs index 1e8e569a5..44bad6149 100644 --- a/Ryujinx.HLE/Loaders/Executables/IExecutable.cs +++ b/Ryujinx.HLE/Loaders/Executables/IExecutable.cs @@ -2,7 +2,7 @@ namespace Ryujinx.HLE.Loaders.Executables { public interface IExecutable { - string Name { get; } + string FilePath { get; } byte[] Text { get; } byte[] RO { get; } diff --git a/Ryujinx.HLE/Loaders/Executables/Nro.cs b/Ryujinx.HLE/Loaders/Executables/Nro.cs index 9e2b7e907..0b5068d7b 100644 --- a/Ryujinx.HLE/Loaders/Executables/Nro.cs +++ b/Ryujinx.HLE/Loaders/Executables/Nro.cs @@ -4,7 +4,7 @@ namespace Ryujinx.HLE.Loaders.Executables { class Nro : IExecutable { - public string Name { get; private set; } + public string FilePath { get; private set; } public byte[] Text { get; private set; } public byte[] RO { get; private set; } @@ -16,9 +16,9 @@ namespace Ryujinx.HLE.Loaders.Executables public int DataOffset { get; private set; } public int BssSize { get; private set; } - public Nro(Stream Input, string Name) + public Nro(Stream Input, string FilePath) { - this.Name = Name; + this.FilePath = FilePath; BinaryReader Reader = new BinaryReader(Input); diff --git a/Ryujinx.HLE/Loaders/Executables/Nso.cs b/Ryujinx.HLE/Loaders/Executables/Nso.cs index a5e1a361e..6a55c755a 100644 --- a/Ryujinx.HLE/Loaders/Executables/Nso.cs +++ b/Ryujinx.HLE/Loaders/Executables/Nso.cs @@ -6,7 +6,7 @@ namespace Ryujinx.HLE.Loaders.Executables { class Nso : IExecutable { - public string Name { get; private set; } + public string FilePath { get; private set; } public byte[] Text { get; private set; } public byte[] RO { get; private set; } @@ -31,7 +31,7 @@ namespace Ryujinx.HLE.Loaders.Executables public Nso(Stream Input, string Name) { - this.Name = Name; + this.FilePath = FilePath; BinaryReader Reader = new BinaryReader(Input); diff --git a/Ryujinx.HLE/OsHle/Homebrew.cs b/Ryujinx.HLE/OsHle/Homebrew.cs index 4266c8db4..778e52fe5 100644 --- a/Ryujinx.HLE/OsHle/Homebrew.cs +++ b/Ryujinx.HLE/OsHle/Homebrew.cs @@ -1,11 +1,14 @@ using ChocolArm64.Memory; +using System.Text; namespace Ryujinx.HLE.OsHle { static class Homebrew { + public const string TemporaryNroSuffix = ".ryu_tmp.nro"; + //http://switchbrew.org/index.php?title=Homebrew_ABI - public static void WriteHbAbiData(AMemory Memory, long Position, int MainThreadHandle) + public static void WriteHbAbiData(AMemory Memory, long Position, int MainThreadHandle, string SwitchPath) { Memory.Manager.Map(Position, AMemoryMgr.PageSize, (int)MemoryType.Normal, AMemoryPerm.RW); @@ -15,6 +18,11 @@ namespace Ryujinx.HLE.OsHle //NextLoadPath WriteConfigEntry(Memory, ref Position, 2, 0, Position + 0x200, Position + 0x400); + // Argv + long ArgvPosition = Position + 0xC00; + WriteConfigEntry(Memory, ref Position, 5, 0, 0, ArgvPosition); + Memory.WriteBytes(ArgvPosition, Encoding.ASCII.GetBytes(SwitchPath + "\0")); + //AppletType WriteConfigEntry(Memory, ref Position, 7); diff --git a/Ryujinx.HLE/OsHle/Horizon.cs b/Ryujinx.HLE/OsHle/Horizon.cs index a5bf0616c..9d8a937ff 100644 --- a/Ryujinx.HLE/OsHle/Horizon.cs +++ b/Ryujinx.HLE/OsHle/Horizon.cs @@ -87,19 +87,36 @@ namespace Ryujinx.HLE.OsHle MainProcess.Run(); } - public void LoadProgram(string FileName) + public void LoadProgram(string FilePath) { - bool IsNro = Path.GetExtension(FileName).ToLower() == ".nro"; + bool IsNro = Path.GetExtension(FilePath).ToLower() == ".nro"; - string Name = Path.GetFileNameWithoutExtension(FileName); + string Name = Path.GetFileNameWithoutExtension(FilePath); + string SwitchFilePath = Ns.VFs.SystemPathToSwitchPath(FilePath); + + if (IsNro && (SwitchFilePath == null || !SwitchFilePath.StartsWith("sdmc:/"))) + { + // TODO: avoid copying the file if we are already inside a sdmc directory + string SwitchPath = $"sdmc:/switch/{Name}{Homebrew.TemporaryNroSuffix}"; + string TempPath = Ns.VFs.SwitchPathToSystemPath(SwitchPath); + + string SwitchDir = Path.GetDirectoryName(TempPath); + if (!Directory.Exists(SwitchDir)) + { + Directory.CreateDirectory(SwitchDir); + } + File.Copy(FilePath, TempPath, true); + + FilePath = TempPath; + } Process MainProcess = MakeProcess(); - using (FileStream Input = new FileStream(FileName, FileMode.Open)) + using (FileStream Input = new FileStream(FilePath, FileMode.Open)) { MainProcess.LoadProgram(IsNro - ? (IExecutable)new Nro(Input, Name) - : (IExecutable)new Nso(Input, Name)); + ? (IExecutable)new Nro(Input, FilePath) + : (IExecutable)new Nso(Input, FilePath)); } MainProcess.SetEmptyArgs(); diff --git a/Ryujinx.HLE/OsHle/Process.cs b/Ryujinx.HLE/OsHle/Process.cs index 53e357ab9..be27dcc28 100644 --- a/Ryujinx.HLE/OsHle/Process.cs +++ b/Ryujinx.HLE/OsHle/Process.cs @@ -13,6 +13,7 @@ using Ryujinx.HLE.OsHle.Services.Nv; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Text; namespace Ryujinx.HLE.OsHle @@ -155,7 +156,9 @@ namespace Ryujinx.HLE.OsHle { HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd); - Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle); + string SwitchPath = Ns.VFs.SystemPathToSwitchPath(Executables[0].FilePath); + + Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle, SwitchPath); MainThread.Thread.ThreadState.X0 = (ulong)HbAbiDataPosition; MainThread.Thread.ThreadState.X1 = ulong.MaxValue; @@ -400,6 +403,11 @@ namespace Ryujinx.HLE.OsHle { if (Disposing && !Disposed) { + if (NeedsHbAbi && Executables[0].FilePath.EndsWith(Homebrew.TemporaryNroSuffix)) + { + File.Delete(Executables[0].FilePath); + } + //If there is still some thread running, disposing the objects is not //safe as the thread may try to access those resources. Instead, we set //the flag to have the Process disposed when all threads finishes. diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index 1946b187b..74c0564a9 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -81,8 +81,9 @@ namespace Ryujinx.HLE Gpu.Fifo.DispatchCalls(); } - internal virtual void OnFinish(EventArgs e) + public virtual void OnFinish(EventArgs e) { + Os.Dispose(); Finish?.Invoke(this, e); } diff --git a/Ryujinx.HLE/VirtualFileSystem.cs b/Ryujinx.HLE/VirtualFileSystem.cs index 8b71caa97..38df81f87 100644 --- a/Ryujinx.HLE/VirtualFileSystem.cs +++ b/Ryujinx.HLE/VirtualFileSystem.cs @@ -45,6 +45,35 @@ namespace Ryujinx.HLE public string GetGameSavesPath() => MakeDirAndGetFullPath(NandPath); + public string SwitchPathToSystemPath(string SwitchPath) + { + string[] Parts = SwitchPath.Split(":"); + if (Parts.Length != 2) + { + return null; + } + return GetFullPath(MakeDirAndGetFullPath(Parts[0]), Parts[1]); + } + + public string SystemPathToSwitchPath(string SystemPath) + { + string BaseSystemPath = GetBasePath() + "/"; + if (SystemPath.StartsWith(BaseSystemPath)) + { + string RawPath = SystemPath.Replace(BaseSystemPath, ""); + int FirstSeparatorOffset = RawPath.IndexOf('/'); + if (FirstSeparatorOffset == -1) + { + return $"{RawPath}:/"; + } + + string BasePath = RawPath.Substring(0, FirstSeparatorOffset); + string FileName = RawPath.Substring(FirstSeparatorOffset + 1); + return $"{BasePath}:/{FileName}"; + } + return null; + } + private string MakeDirAndGetFullPath(string Dir) { string FullPath = Path.Combine(GetBasePath(), Dir); diff --git a/Ryujinx/Ui/Program.cs b/Ryujinx/Ui/Program.cs index 5cacc6228..879b9c20b 100644 --- a/Ryujinx/Ui/Program.cs +++ b/Ryujinx/Ui/Program.cs @@ -68,6 +68,7 @@ namespace Ryujinx }; Screen.MainLoop(); + Ns.OnFinish(EventArgs.Empty); } Environment.Exit(0); From 571848536b347a85c85955745a16d4f7b9a0c04a Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Tue, 17 Jul 2018 16:50:00 -0300 Subject: [PATCH 2/3] Implement some shader instructions (#252) * Add IADDI32, IADD and SEL shader instructions * Add LOP shader instruction and fix LOP32I pass_b * Add ISET shader instruction * Add IADD3 shader instruction * Address feedback * Fixup OperA in Iadd_I32 --- .../Gal/Shader/ShaderDecodeAlu.cs | 214 +++++++++++++++++- .../Gal/Shader/ShaderDecodeHelper.cs | 5 + .../Gal/Shader/ShaderDecodeMove.cs | 37 +++ .../Gal/Shader/ShaderOpCodeTable.cs | 16 ++ 4 files changed, 269 insertions(+), 3 deletions(-) diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs index 2e022fbd4..a44073513 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs @@ -144,6 +144,50 @@ namespace Ryujinx.Graphics.Gal.Shader EmitFsetp(Block, OpCode, ShaderOper.RR); } + public static void Iadd_C(ShaderIrBlock Block, long OpCode) + { + EmitIadd(Block, OpCode, ShaderOper.CR); + } + + public static void Iadd_I(ShaderIrBlock Block, long OpCode) + { + EmitIadd(Block, OpCode, ShaderOper.Imm); + } + + public static void Iadd_I32(ShaderIrBlock Block, long OpCode) + { + ShaderIrNode OperA = GetOperGpr8 (OpCode); + ShaderIrNode OperB = GetOperImm32_20(OpCode); + + bool NegA = ((OpCode >> 56) & 1) != 0; + + OperA = GetAluIneg(OperA, NegA); + + ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB); + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); + } + + public static void Iadd_R(ShaderIrBlock Block, long OpCode) + { + EmitIadd(Block, OpCode, ShaderOper.RR); + } + + public static void Iadd3_C(ShaderIrBlock Block, long OpCode) + { + EmitIadd3(Block, OpCode, ShaderOper.CR); + } + + public static void Iadd3_I(ShaderIrBlock Block, long OpCode) + { + EmitIadd3(Block, OpCode, ShaderOper.Imm); + } + + public static void Iadd3_R(ShaderIrBlock Block, long OpCode) + { + EmitIadd3(Block, OpCode, ShaderOper.RR); + } + public static void Imnmx_C(ShaderIrBlock Block, long OpCode) { EmitImnmx(Block, OpCode, ShaderOper.CR); @@ -184,6 +228,21 @@ namespace Ryujinx.Graphics.Gal.Shader EmitIscadd(Block, OpCode, ShaderOper.RR); } + public static void Iset_C(ShaderIrBlock Block, long OpCode) + { + EmitIset(Block, OpCode, ShaderOper.CR); + } + + public static void Iset_I(ShaderIrBlock Block, long OpCode) + { + EmitIset(Block, OpCode, ShaderOper.Imm); + } + + public static void Iset_R(ShaderIrBlock Block, long OpCode) + { + EmitIset(Block, OpCode, ShaderOper.RR); + } + public static void Isetp_C(ShaderIrBlock Block, long OpCode) { EmitIsetp(Block, OpCode, ShaderOper.CR); @@ -215,13 +274,13 @@ namespace Ryujinx.Graphics.Gal.Shader case 2: Inst = ShaderIrInst.Xor; break; } - ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), InvA); + ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), InvB); //SubOp == 3 is pass, used by the not instruction //which just moves the inverted register value. if (SubOp < 3) { - ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), InvB); + ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), InvA); ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB); @@ -229,10 +288,25 @@ namespace Ryujinx.Graphics.Gal.Shader } else { - Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode)); + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperB), OpCode)); } } + public static void Lop_C(ShaderIrBlock Block, long OpCode) + { + EmitLop(Block, OpCode, ShaderOper.CR); + } + + public static void Lop_I(ShaderIrBlock Block, long OpCode) + { + EmitLop(Block, OpCode, ShaderOper.Imm); + } + + public static void Lop_R(ShaderIrBlock Block, long OpCode) + { + EmitLop(Block, OpCode, ShaderOper.RR); + } + public static void Mufu(ShaderIrBlock Block, long OpCode) { int SubOp = (int)(OpCode >> 20) & 0xf; @@ -533,6 +607,92 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); } + private static void EmitIadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + ShaderIrNode OperA = GetOperGpr8(OpCode); + ShaderIrNode OperB; + + switch (Oper) + { + case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break; + case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; + + default: throw new ArgumentException(nameof(Oper)); + } + + bool NegA = ((OpCode >> 49) & 1) != 0; + bool NegB = ((OpCode >> 48) & 1) != 0; + + OperA = GetAluIneg(OperA, NegA); + OperB = GetAluIneg(OperB, NegB); + + ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB); + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); + } + + private static void EmitIadd3(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + int Mode = (int)((OpCode >> 37) & 3); + + bool Neg1 = ((OpCode >> 51) & 1) != 0; + bool Neg2 = ((OpCode >> 50) & 1) != 0; + bool Neg3 = ((OpCode >> 49) & 1) != 0; + + int Height1 = (int)((OpCode >> 35) & 3); + int Height2 = (int)((OpCode >> 33) & 3); + int Height3 = (int)((OpCode >> 31) & 3); + + ShaderIrNode OperB; + + switch (Oper) + { + case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break; + case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; + + default: throw new ArgumentException(nameof(Oper)); + } + + ShaderIrNode ApplyHeight(ShaderIrNode Src, int Height) + { + if (Oper != ShaderOper.RR) + { + return Src; + } + + switch (Height) + { + case 0: return Src; + case 1: return new ShaderIrOp(ShaderIrInst.And, Src, new ShaderIrOperImm(0xffff)); + case 2: return new ShaderIrOp(ShaderIrInst.Lsr, Src, new ShaderIrOperImm(16)); + + default: throw new InvalidOperationException(); + } + } + + ShaderIrNode Src1 = GetAluIneg(ApplyHeight(GetOperGpr8(OpCode), Height1), Neg1); + ShaderIrNode Src2 = GetAluIneg(ApplyHeight(OperB, Height2), Neg2); + ShaderIrNode Src3 = GetAluIneg(ApplyHeight(GetOperGpr39(OpCode), Height3), Neg3); + + ShaderIrOp Sum = new ShaderIrOp(ShaderIrInst.Add, Src1, Src2); + + if (Oper == ShaderOper.RR) + { + switch (Mode) + { + case 1: Sum = new ShaderIrOp(ShaderIrInst.Lsr, Sum, new ShaderIrOperImm(16)); break; + case 2: Sum = new ShaderIrOp(ShaderIrInst.Lsl, Sum, new ShaderIrOperImm(16)); break; + } + } + + //Note: Here there should be a "+ 1" when carry flag is set + //but since carry is mostly ignored by other instructions, it's excluded for now + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), new ShaderIrOp(ShaderIrInst.Add, Sum, Src3)), OpCode)); + } + private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { bool NegB = ((OpCode >> 48) & 1) != 0; @@ -821,6 +981,54 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode)); } + private static void EmitLop(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + int SubOp = (int)(OpCode >> 41) & 3; + + bool InvA = ((OpCode >> 39) & 1) != 0; + bool InvB = ((OpCode >> 40) & 1) != 0; + + ShaderIrInst Inst = 0; + + switch (SubOp) + { + case 0: Inst = ShaderIrInst.And; break; + case 1: Inst = ShaderIrInst.Or; break; + case 2: Inst = ShaderIrInst.Xor; break; + } + + ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), InvA); + ShaderIrNode OperB; + + switch (Oper) + { + case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break; + case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; + + default: throw new ArgumentException(nameof(Oper)); + } + + OperB = GetAluNot(OperB, InvB); + + ShaderIrNode Op; + + if (SubOp < 3) + { + Op = new ShaderIrOp(Inst, OperA, OperB); + } + else + { + Op = OperB; + } + + ShaderIrNode Compare = new ShaderIrOp(ShaderIrInst.Cne, Op, new ShaderIrOperImm(0)); + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperPred48(OpCode), Compare), OpCode)); + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); + } + private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { //TODO: Confirm SignAB/C, it is just a guess. diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs index a8ad5ec2e..1f1b158ef 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs @@ -156,6 +156,11 @@ namespace Ryujinx.Graphics.Gal.Shader return new ShaderIrOperPred((int)(OpCode >> 39) & 7); } + public static ShaderIrOperPred GetOperPred48(long OpCode) + { + return new ShaderIrOperPred((int)((OpCode >> 48) & 7)); + } + public static ShaderIrInst GetCmp(long OpCode) { switch ((int)(OpCode >> 49) & 7) diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs index dfcea905a..4c9e59cf0 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs @@ -113,6 +113,21 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), OpCode)); } + public static void Sel_C(ShaderIrBlock Block, long OpCode) + { + EmitSel(Block, OpCode, ShaderOper.CR); + } + + public static void Sel_I(ShaderIrBlock Block, long OpCode) + { + EmitSel(Block, OpCode, ShaderOper.Imm); + } + + public static void Sel_R(ShaderIrBlock Block, long OpCode) + { + EmitSel(Block, OpCode, ShaderOper.RR); + } + private static void EmitF2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { bool NegA = ((OpCode >> 45) & 1) != 0; @@ -340,6 +355,28 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode)); } + private static void EmitSel(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + ShaderIrOperGpr Dst = GetOperGpr0 (OpCode); + ShaderIrNode Pred = GetOperPred39N(OpCode); + + ShaderIrNode ResultA = GetOperGpr8(OpCode); + ShaderIrNode ResultB; + + switch (Oper) + { + case ShaderOper.CR: ResultB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Imm: ResultB = GetOperImm19_20(OpCode); break; + case ShaderOper.RR: ResultB = GetOperGpr20 (OpCode); break; + + default: throw new ArgumentException(nameof(Oper)); + } + + Block.AddNode(GetPredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultA), false), OpCode)); + + Block.AddNode(GetPredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultB), true), OpCode)); + } + private static IntType GetIntType(long OpCode) { bool Signed = ((OpCode >> 13) & 1) != 0; diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs index b4f51e508..1ac117851 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs @@ -64,6 +64,13 @@ namespace Ryujinx.Graphics.Gal.Shader Set("0100110011100x", ShaderDecode.I2i_C); Set("0011100x11100x", ShaderDecode.I2i_I); Set("0101110011100x", ShaderDecode.I2i_R); + Set("0100110000010x", ShaderDecode.Iadd_C); + Set("0011100000010x", ShaderDecode.Iadd_I); + Set("0001110x0xxxxx", ShaderDecode.Iadd_I32); + Set("0101110000010x", ShaderDecode.Iadd_R); + Set("010011001100xx", ShaderDecode.Iadd3_C); + Set("001110001100xx", ShaderDecode.Iadd3_I); + Set("010111001100xx", ShaderDecode.Iadd3_R); Set("0100110000100x", ShaderDecode.Imnmx_C); Set("0011100x00100x", ShaderDecode.Imnmx_I); Set("0101110000100x", ShaderDecode.Imnmx_R); @@ -71,13 +78,19 @@ namespace Ryujinx.Graphics.Gal.Shader Set("0100110000011x", ShaderDecode.Iscadd_C); Set("0011100x00011x", ShaderDecode.Iscadd_I); Set("0101110000011x", ShaderDecode.Iscadd_R); + Set("010010110101xx", ShaderDecode.Iset_C); + Set("001101100101xx", ShaderDecode.Iset_I); + Set("010110110101xx", ShaderDecode.Iset_R); Set("010010110110xx", ShaderDecode.Isetp_C); Set("0011011x0110xx", ShaderDecode.Isetp_I); Set("010110110110xx", ShaderDecode.Isetp_R); Set("111000110011xx", ShaderDecode.Kil); Set("1110111111011x", ShaderDecode.Ld_A); Set("1110111110010x", ShaderDecode.Ld_C); + Set("0100110001000x", ShaderDecode.Lop_C); + Set("0011100001000x", ShaderDecode.Lop_I); Set("000001xxxxxxxx", ShaderDecode.Lop_I32); + Set("0101110001000x", ShaderDecode.Lop_R); Set("0100110010011x", ShaderDecode.Mov_C); Set("0011100x10011x", ShaderDecode.Mov_I); Set("000000010000xx", ShaderDecode.Mov_I32); @@ -87,6 +100,9 @@ namespace Ryujinx.Graphics.Gal.Shader Set("0100110010010x", ShaderDecode.Rro_C); Set("0011100x10010x", ShaderDecode.Rro_I); Set("0101110010010x", ShaderDecode.Rro_R); + Set("0100110010100x", ShaderDecode.Sel_C); + Set("0011100010100x", ShaderDecode.Sel_I); + Set("0101110010100x", ShaderDecode.Sel_R); Set("0100110001001x", ShaderDecode.Shl_C); Set("0011100x01001x", ShaderDecode.Shl_I); Set("0101110001001x", ShaderDecode.Shl_R); From 98223b0e7ddcba50a591413894c20519bc9d653d Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 17 Jul 2018 17:28:41 -0300 Subject: [PATCH 3/3] Fix wrong assignment and allow null FilePaths on Executable --- Ryujinx.HLE/Loaders/Executable.cs | 6 +++++- Ryujinx.HLE/Loaders/Executables/Nso.cs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Ryujinx.HLE/Loaders/Executable.cs b/Ryujinx.HLE/Loaders/Executable.cs index 43193245a..84f5ff390 100644 --- a/Ryujinx.HLE/Loaders/Executable.cs +++ b/Ryujinx.HLE/Loaders/Executable.cs @@ -31,7 +31,11 @@ namespace Ryujinx.HLE.Loaders FilePath = Exe.FilePath; - Name = Path.GetFileNameWithoutExtension(FilePath.Replace(Homebrew.TemporaryNroSuffix, "")); + if (FilePath != null) + { + Name = Path.GetFileNameWithoutExtension(FilePath.Replace(Homebrew.TemporaryNroSuffix, "")); + } + this.Memory = Memory; this.ImageBase = ImageBase; this.ImageEnd = ImageBase; diff --git a/Ryujinx.HLE/Loaders/Executables/Nso.cs b/Ryujinx.HLE/Loaders/Executables/Nso.cs index 6a55c755a..fef9c4b85 100644 --- a/Ryujinx.HLE/Loaders/Executables/Nso.cs +++ b/Ryujinx.HLE/Loaders/Executables/Nso.cs @@ -29,7 +29,7 @@ namespace Ryujinx.HLE.Loaders.Executables HasDataHash = 1 << 5 } - public Nso(Stream Input, string Name) + public Nso(Stream Input, string FilePath) { this.FilePath = FilePath;