Merge remote-tracking branch 'upstream/master'
Merge lol
This commit is contained in:
commit
cd63f0a41f
73 changed files with 1689 additions and 1226 deletions
|
@ -142,11 +142,13 @@ namespace ChocolArm64
|
||||||
Set("0>101110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmhs_V, typeof(AOpCodeSimdReg));
|
Set("0>101110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmhs_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0>101110<<100000100110xxxxxxxxxx", AInstEmit.Cmle_V, typeof(AOpCodeSimd));
|
Set("0>101110<<100000100110xxxxxxxxxx", AInstEmit.Cmle_V, typeof(AOpCodeSimd));
|
||||||
Set("0>001110<<100000101010xxxxxxxxxx", AInstEmit.Cmlt_V, typeof(AOpCodeSimd));
|
Set("0>001110<<100000101010xxxxxxxxxx", AInstEmit.Cmlt_V, typeof(AOpCodeSimd));
|
||||||
|
Set("0>001110<<1xxxxx100011xxxxxxxxxx", AInstEmit.Cmtst_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x00111000100000010110xxxxxxxxxx", AInstEmit.Cnt_V, typeof(AOpCodeSimd));
|
Set("0x00111000100000010110xxxxxxxxxx", AInstEmit.Cnt_V, typeof(AOpCodeSimd));
|
||||||
Set("0x001110000xxxxx000011xxxxxxxxxx", AInstEmit.Dup_Gp, typeof(AOpCodeSimdIns));
|
Set("0x001110000xxxxx000011xxxxxxxxxx", AInstEmit.Dup_Gp, typeof(AOpCodeSimdIns));
|
||||||
Set("01011110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_S, typeof(AOpCodeSimdIns));
|
Set("01011110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_S, typeof(AOpCodeSimdIns));
|
||||||
Set("0x001110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_V, typeof(AOpCodeSimdIns));
|
Set("0x001110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_V, typeof(AOpCodeSimdIns));
|
||||||
Set("0x101110001xxxxx000111xxxxxxxxxx", AInstEmit.Eor_V, typeof(AOpCodeSimdReg));
|
Set("0x101110001xxxxx000111xxxxxxxxxx", AInstEmit.Eor_V, typeof(AOpCodeSimdReg));
|
||||||
|
Set("0>101110000xxxxx0<xxx0xxxxxxxxxx", AInstEmit.Ext_V, typeof(AOpCodeSimdExt));
|
||||||
Set("011111101x1xxxxx110101xxxxxxxxxx", AInstEmit.Fabd_S, typeof(AOpCodeSimdReg));
|
Set("011111101x1xxxxx110101xxxxxxxxxx", AInstEmit.Fabd_S, typeof(AOpCodeSimdReg));
|
||||||
Set("000111100x100000110000xxxxxxxxxx", AInstEmit.Fabs_S, typeof(AOpCodeSimd));
|
Set("000111100x100000110000xxxxxxxxxx", AInstEmit.Fabs_S, typeof(AOpCodeSimd));
|
||||||
Set("000111100x1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg));
|
Set("000111100x1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg));
|
||||||
|
@ -228,6 +230,7 @@ namespace ChocolArm64
|
||||||
Set("0x10111000100000010110xxxxxxxxxx", AInstEmit.Not_V, typeof(AOpCodeSimd));
|
Set("0x10111000100000010110xxxxxxxxxx", AInstEmit.Not_V, typeof(AOpCodeSimd));
|
||||||
Set("0x001110101xxxxx000111xxxxxxxxxx", AInstEmit.Orr_V, typeof(AOpCodeSimdReg));
|
Set("0x001110101xxxxx000111xxxxxxxxxx", AInstEmit.Orr_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x00111100000xxx<<x101xxxxxxxxxx", AInstEmit.Orr_Vi, typeof(AOpCodeSimdImm));
|
Set("0x00111100000xxx<<x101xxxxxxxxxx", AInstEmit.Orr_Vi, typeof(AOpCodeSimdImm));
|
||||||
|
Set("0x001110<<100000000010xxxxxxxxxx", AInstEmit.Rev64_V, typeof(AOpCodeSimd));
|
||||||
Set("0x001110<<1xxxxx000100xxxxxxxxxx", AInstEmit.Saddw_V, typeof(AOpCodeSimdReg));
|
Set("0x001110<<1xxxxx000100xxxxxxxxxx", AInstEmit.Saddw_V, typeof(AOpCodeSimdReg));
|
||||||
Set("x0011110xx100010000000xxxxxxxxxx", AInstEmit.Scvtf_Gp, typeof(AOpCodeSimdCvt));
|
Set("x0011110xx100010000000xxxxxxxxxx", AInstEmit.Scvtf_Gp, typeof(AOpCodeSimdCvt));
|
||||||
Set("010111100x100001110110xxxxxxxxxx", AInstEmit.Scvtf_S, typeof(AOpCodeSimd));
|
Set("010111100x100001110110xxxxxxxxxx", AInstEmit.Scvtf_S, typeof(AOpCodeSimd));
|
||||||
|
@ -262,6 +265,7 @@ namespace ChocolArm64
|
||||||
Set("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_S, typeof(AOpCodeSimd));
|
Set("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_S, typeof(AOpCodeSimd));
|
||||||
Set("0x1011100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimd));
|
Set("0x1011100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimd));
|
||||||
Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns));
|
Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns));
|
||||||
|
Set("0x101110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Umull_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg));
|
Set("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm));
|
Set("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm));
|
||||||
Set("011111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm));
|
Set("011111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm));
|
||||||
|
|
|
@ -2,6 +2,7 @@ using ChocolArm64.Memory;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
|
@ -13,35 +14,47 @@ namespace ChocolArm64
|
||||||
|
|
||||||
private AA64Subroutine ExecDelegate;
|
private AA64Subroutine ExecDelegate;
|
||||||
|
|
||||||
private bool HasDelegate;
|
|
||||||
|
|
||||||
public static Type[] FixedArgTypes { get; private set; }
|
|
||||||
|
|
||||||
public static int StateArgIdx { get; private set; }
|
public static int StateArgIdx { get; private set; }
|
||||||
public static int MemoryArgIdx { get; private set; }
|
public static int MemoryArgIdx { get; private set; }
|
||||||
|
|
||||||
|
public static Type[] FixedArgTypes { get; private set; }
|
||||||
|
|
||||||
public DynamicMethod Method { get; private set; }
|
public DynamicMethod Method { get; private set; }
|
||||||
|
|
||||||
public HashSet<long> SubCalls { get; private set; }
|
public ReadOnlyCollection<ARegister> Params { get; private set; }
|
||||||
|
|
||||||
public List<ARegister> Params { get; private set; }
|
private HashSet<long> Callees;
|
||||||
|
|
||||||
public bool NeedsReJit { get; private set; }
|
private ATranslatedSubType Type;
|
||||||
|
|
||||||
public ATranslatedSub()
|
private int CallCount;
|
||||||
|
|
||||||
|
private bool NeedsReJit;
|
||||||
|
|
||||||
|
private int MinCallCountForReJit = 250;
|
||||||
|
|
||||||
|
public ATranslatedSub(DynamicMethod Method, List<ARegister> Params, HashSet<long> Callees)
|
||||||
{
|
{
|
||||||
SubCalls = new HashSet<long>();
|
if (Method == null)
|
||||||
}
|
{
|
||||||
|
throw new ArgumentNullException(nameof(Method));
|
||||||
|
}
|
||||||
|
|
||||||
public ATranslatedSub(DynamicMethod Method, List<ARegister> Params) : this()
|
|
||||||
{
|
|
||||||
if (Params == null)
|
if (Params == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(Params));
|
throw new ArgumentNullException(nameof(Params));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Method = Method;
|
if (Callees == null)
|
||||||
this.Params = Params;
|
{
|
||||||
|
throw new ArgumentNullException(nameof(Callees));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Method = Method;
|
||||||
|
this.Params = Params.AsReadOnly();
|
||||||
|
this.Callees = Callees;
|
||||||
|
|
||||||
|
PrepareDelegate();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ATranslatedSub()
|
static ATranslatedSub()
|
||||||
|
@ -69,36 +82,53 @@ namespace ChocolArm64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long Execute(AThreadState ThreadState, AMemory Memory)
|
private void PrepareDelegate()
|
||||||
{
|
{
|
||||||
if (!HasDelegate)
|
string Name = $"{Method.Name}_Dispatch";
|
||||||
|
|
||||||
|
DynamicMethod Mthd = new DynamicMethod(Name, typeof(long), FixedArgTypes);
|
||||||
|
|
||||||
|
ILGenerator Generator = Mthd.GetILGenerator();
|
||||||
|
|
||||||
|
Generator.EmitLdargSeq(FixedArgTypes.Length);
|
||||||
|
|
||||||
|
foreach (ARegister Reg in Params)
|
||||||
{
|
{
|
||||||
string Name = $"{Method.Name}_Dispatch";
|
Generator.EmitLdarg(StateArgIdx);
|
||||||
|
|
||||||
DynamicMethod Mthd = new DynamicMethod(Name, typeof(long), FixedArgTypes);
|
Generator.Emit(OpCodes.Ldfld, Reg.GetField());
|
||||||
|
|
||||||
ILGenerator Generator = Mthd.GetILGenerator();
|
|
||||||
|
|
||||||
Generator.EmitLdargSeq(FixedArgTypes.Length);
|
|
||||||
|
|
||||||
foreach (ARegister Reg in Params)
|
|
||||||
{
|
|
||||||
Generator.EmitLdarg(StateArgIdx);
|
|
||||||
|
|
||||||
Generator.Emit(OpCodes.Ldfld, Reg.GetField());
|
|
||||||
}
|
|
||||||
|
|
||||||
Generator.Emit(OpCodes.Call, Method);
|
|
||||||
Generator.Emit(OpCodes.Ret);
|
|
||||||
|
|
||||||
ExecDelegate = (AA64Subroutine)Mthd.CreateDelegate(typeof(AA64Subroutine));
|
|
||||||
|
|
||||||
HasDelegate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Generator.Emit(OpCodes.Call, Method);
|
||||||
|
Generator.Emit(OpCodes.Ret);
|
||||||
|
|
||||||
|
ExecDelegate = (AA64Subroutine)Mthd.CreateDelegate(typeof(AA64Subroutine));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldReJit()
|
||||||
|
{
|
||||||
|
if (Type == ATranslatedSubType.SubTier0)
|
||||||
|
{
|
||||||
|
if (CallCount < MinCallCountForReJit)
|
||||||
|
{
|
||||||
|
CallCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallCount == MinCallCountForReJit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Type == ATranslatedSubType.SubTier1 && NeedsReJit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long Execute(AThreadState ThreadState, AMemory Memory)
|
||||||
|
{
|
||||||
return ExecDelegate(ThreadState, Memory);
|
return ExecDelegate(ThreadState, Memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MarkForReJit() => NeedsReJit = true;
|
public void SetType(ATranslatedSubType Type) => this.Type = Type;
|
||||||
|
|
||||||
|
public bool HasCallee(long Position) => Callees.Contains(Position);
|
||||||
|
|
||||||
|
public void MarkForReJit() => NeedsReJit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
9
ChocolArm64/ATranslatedSubType.cs
Normal file
9
ChocolArm64/ATranslatedSubType.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace ChocolArm64
|
||||||
|
{
|
||||||
|
enum ATranslatedSubType
|
||||||
|
{
|
||||||
|
SubBlock,
|
||||||
|
SubTier0,
|
||||||
|
SubTier1
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,11 +7,14 @@ using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace ChocolArm64
|
namespace ChocolArm64
|
||||||
{
|
{
|
||||||
public class ATranslator
|
public class ATranslator
|
||||||
{
|
{
|
||||||
|
private HashSet<long> SubBlocks;
|
||||||
|
|
||||||
private ConcurrentDictionary<long, ATranslatedSub> CachedSubs;
|
private ConcurrentDictionary<long, ATranslatedSub> CachedSubs;
|
||||||
|
|
||||||
private ConcurrentDictionary<long, string> SymbolTable;
|
private ConcurrentDictionary<long, string> SymbolTable;
|
||||||
|
@ -24,6 +27,8 @@ namespace ChocolArm64
|
||||||
|
|
||||||
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
|
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
|
||||||
{
|
{
|
||||||
|
SubBlocks = new HashSet<long>();
|
||||||
|
|
||||||
CachedSubs = new ConcurrentDictionary<long, ATranslatedSub>();
|
CachedSubs = new ConcurrentDictionary<long, ATranslatedSub>();
|
||||||
|
|
||||||
if (SymbolTable != null)
|
if (SymbolTable != null)
|
||||||
|
@ -38,9 +43,9 @@ namespace ChocolArm64
|
||||||
KeepRunning = true;
|
KeepRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopExecution() => KeepRunning = false;
|
internal void StopExecution() => KeepRunning = false;
|
||||||
|
|
||||||
public void ExecuteSubroutine(AThread Thread, long Position)
|
internal void ExecuteSubroutine(AThread Thread, long Position)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -54,9 +59,14 @@ namespace ChocolArm64
|
||||||
CpuTrace?.Invoke(this, new ACpuTraceEventArgs(Position, SubName));
|
CpuTrace?.Invoke(this, new ACpuTraceEventArgs(Position, SubName));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CachedSubs.TryGetValue(Position, out ATranslatedSub Sub) || Sub.NeedsReJit)
|
if (!CachedSubs.TryGetValue(Position, out ATranslatedSub Sub))
|
||||||
{
|
{
|
||||||
Sub = TranslateSubroutine(Thread.Memory, Position);
|
Sub = TranslateTier0(Thread.Memory, Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Sub.ShouldReJit())
|
||||||
|
{
|
||||||
|
TranslateTier1(Thread.Memory, Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
|
Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
|
||||||
|
@ -86,19 +96,57 @@ namespace ChocolArm64
|
||||||
return CachedSubs.ContainsKey(Position);
|
return CachedSubs.ContainsKey(Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ATranslatedSub TranslateSubroutine(AMemory Memory, long Position)
|
private ATranslatedSub TranslateTier0(AMemory Memory, long Position)
|
||||||
|
{
|
||||||
|
ABlock Block = ADecoder.DecodeBasicBlock(this, Memory, Position);
|
||||||
|
|
||||||
|
ABlock[] Graph = new ABlock[] { Block };
|
||||||
|
|
||||||
|
string SubName = GetSubName(Position);
|
||||||
|
|
||||||
|
AILEmitterCtx Context = new AILEmitterCtx(this, Graph, Block, SubName);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Context.EmitOpCode();
|
||||||
|
}
|
||||||
|
while (Context.AdvanceOpCode());
|
||||||
|
|
||||||
|
ATranslatedSub Subroutine = Context.GetSubroutine();
|
||||||
|
|
||||||
|
if (SubBlocks.Contains(Position))
|
||||||
|
{
|
||||||
|
SubBlocks.Remove(Position);
|
||||||
|
|
||||||
|
Subroutine.SetType(ATranslatedSubType.SubBlock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Subroutine.SetType(ATranslatedSubType.SubTier0);
|
||||||
|
}
|
||||||
|
|
||||||
|
CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine);
|
||||||
|
|
||||||
|
AOpCode LastOp = Block.GetLastOp();
|
||||||
|
|
||||||
|
if (LastOp.Emitter != AInstEmit.Ret &&
|
||||||
|
LastOp.Emitter != AInstEmit.Br)
|
||||||
|
{
|
||||||
|
SubBlocks.Add(LastOp.Position + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Subroutine;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TranslateTier1(AMemory Memory, long Position)
|
||||||
{
|
{
|
||||||
(ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(this, Memory, Position);
|
(ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(this, Memory, Position);
|
||||||
|
|
||||||
string SubName = SymbolTable.GetOrAdd(Position, $"Sub{Position:x16}");
|
string SubName = GetSubName(Position);
|
||||||
|
|
||||||
PropagateName(Cfg.Graph, SubName);
|
PropagateName(Cfg.Graph, SubName);
|
||||||
|
|
||||||
AILEmitterCtx Context = new AILEmitterCtx(
|
AILEmitterCtx Context = new AILEmitterCtx(this, Cfg.Graph, Cfg.Root, SubName);
|
||||||
this,
|
|
||||||
Cfg.Graph,
|
|
||||||
Cfg.Root,
|
|
||||||
SubName);
|
|
||||||
|
|
||||||
if (Context.CurrBlock.Position != Position)
|
if (Context.CurrBlock.Position != Position)
|
||||||
{
|
{
|
||||||
|
@ -115,7 +163,7 @@ namespace ChocolArm64
|
||||||
//since we can now call it directly which is faster.
|
//since we can now call it directly which is faster.
|
||||||
foreach (ATranslatedSub TS in CachedSubs.Values)
|
foreach (ATranslatedSub TS in CachedSubs.Values)
|
||||||
{
|
{
|
||||||
if (TS.SubCalls.Contains(Position))
|
if (TS.HasCallee(Position))
|
||||||
{
|
{
|
||||||
TS.MarkForReJit();
|
TS.MarkForReJit();
|
||||||
}
|
}
|
||||||
|
@ -123,9 +171,14 @@ namespace ChocolArm64
|
||||||
|
|
||||||
ATranslatedSub Subroutine = Context.GetSubroutine();
|
ATranslatedSub Subroutine = Context.GetSubroutine();
|
||||||
|
|
||||||
CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine);
|
Subroutine.SetType(ATranslatedSubType.SubTier1);
|
||||||
|
|
||||||
return Subroutine;
|
CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetSubName(long Position)
|
||||||
|
{
|
||||||
|
return SymbolTable.GetOrAdd(Position, $"Sub{Position:x16}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PropagateName(ABlock[] Graph, string Name)
|
private void PropagateName(ABlock[] Graph, string Name)
|
||||||
|
|
|
@ -18,6 +18,18 @@ namespace ChocolArm64.Decoder
|
||||||
OpActivators = new ConcurrentDictionary<Type, OpActivator>();
|
OpActivators = new ConcurrentDictionary<Type, OpActivator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ABlock DecodeBasicBlock(
|
||||||
|
ATranslator Translator,
|
||||||
|
AMemory Memory,
|
||||||
|
long Start)
|
||||||
|
{
|
||||||
|
ABlock Block = new ABlock(Start);
|
||||||
|
|
||||||
|
FillBlock(Memory, Block);
|
||||||
|
|
||||||
|
return Block;
|
||||||
|
}
|
||||||
|
|
||||||
public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(
|
public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(
|
||||||
ATranslator Translator,
|
ATranslator Translator,
|
||||||
AMemory Memory,
|
AMemory Memory,
|
||||||
|
@ -72,8 +84,8 @@ namespace ChocolArm64.Decoder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!(LastOp is AOpCodeBImmAl) &&
|
if (!((LastOp is AOpCodeBImmAl) ||
|
||||||
!(LastOp is AOpCodeBReg)) || HasCachedSub)
|
(LastOp is AOpCodeBReg)) || HasCachedSub)
|
||||||
{
|
{
|
||||||
Current.Next = Enqueue(Current.EndPosition);
|
Current.Next = Enqueue(Current.EndPosition);
|
||||||
}
|
}
|
||||||
|
|
14
ChocolArm64/Decoder/AOpCodeSimdExt.cs
Normal file
14
ChocolArm64/Decoder/AOpCodeSimdExt.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using ChocolArm64.Instruction;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoder
|
||||||
|
{
|
||||||
|
class AOpCodeSimdExt : AOpCodeSimdReg
|
||||||
|
{
|
||||||
|
public int Imm4 { get; private set; }
|
||||||
|
|
||||||
|
public AOpCodeSimdExt(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||||
|
{
|
||||||
|
int Imm4 = (OpCode >> 11) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ using ChocolArm64.Decoder;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using ChocolArm64.Translation;
|
using ChocolArm64.Translation;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
namespace ChocolArm64.Instruction
|
namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
|
@ -37,6 +38,12 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Context.EmitLdc_I8(Op.Position + 4);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Und(AILEmitterCtx Context)
|
public static void Und(AILEmitterCtx Context)
|
||||||
|
@ -60,6 +67,12 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Context.EmitLdc_I8(Op.Position + 4);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,14 +11,24 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp;
|
AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp;
|
||||||
|
|
||||||
Context.Emit(OpCodes.Br, Context.GetLabel(Op.Imm));
|
if (Context.CurrBlock.Branch != null)
|
||||||
|
{
|
||||||
|
Context.Emit(OpCodes.Br, Context.GetLabel(Op.Imm));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Context.EmitStoreState();
|
||||||
|
Context.EmitLdc_I8(Op.Imm);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void B_Cond(AILEmitterCtx Context)
|
public static void B_Cond(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
AOpCodeBImmCond Op = (AOpCodeBImmCond)Context.CurrOp;
|
AOpCodeBImmCond Op = (AOpCodeBImmCond)Context.CurrOp;
|
||||||
|
|
||||||
Context.EmitCondBranch(Context.GetLabel(Op.Imm), Op.Cond);
|
EmitBranch(Context, Op.Cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Bl(AILEmitterCtx Context)
|
public static void Bl(AILEmitterCtx Context)
|
||||||
|
@ -48,10 +58,7 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
Context.Emit(OpCodes.Pop);
|
Context.Emit(OpCodes.Pop);
|
||||||
|
|
||||||
if (Context.CurrBlock.Next != null)
|
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||||
{
|
|
||||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -93,7 +100,7 @@ namespace ChocolArm64.Instruction
|
||||||
Context.EmitLdintzr(Op.Rt);
|
Context.EmitLdintzr(Op.Rt);
|
||||||
Context.EmitLdc_I(0);
|
Context.EmitLdc_I(0);
|
||||||
|
|
||||||
Context.Emit(ILOp, Context.GetLabel(Op.Imm));
|
EmitBranch(Context, ILOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ret(AILEmitterCtx Context)
|
public static void Ret(AILEmitterCtx Context)
|
||||||
|
@ -118,7 +125,65 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
Context.EmitLdc_I(0);
|
Context.EmitLdc_I(0);
|
||||||
|
|
||||||
Context.Emit(ILOp, Context.GetLabel(Op.Imm));
|
EmitBranch(Context, ILOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitBranch(AILEmitterCtx Context, ACond Cond)
|
||||||
|
{
|
||||||
|
AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp;
|
||||||
|
|
||||||
|
if (Context.CurrBlock.Next != null &&
|
||||||
|
Context.CurrBlock.Branch != null)
|
||||||
|
{
|
||||||
|
Context.EmitCondBranch(Context.GetLabel(Op.Imm), Cond);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Context.EmitStoreState();
|
||||||
|
|
||||||
|
AILLabel LblTaken = new AILLabel();
|
||||||
|
|
||||||
|
Context.EmitCondBranch(LblTaken, Cond);
|
||||||
|
|
||||||
|
Context.EmitLdc_I8(Op.Position + 4);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ret);
|
||||||
|
|
||||||
|
Context.MarkLabel(LblTaken);
|
||||||
|
|
||||||
|
Context.EmitLdc_I8(Op.Imm);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitBranch(AILEmitterCtx Context, OpCode ILOp)
|
||||||
|
{
|
||||||
|
AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp;
|
||||||
|
|
||||||
|
if (Context.CurrBlock.Next != null &&
|
||||||
|
Context.CurrBlock.Branch != null)
|
||||||
|
{
|
||||||
|
Context.Emit(ILOp, Context.GetLabel(Op.Imm));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Context.EmitStoreState();
|
||||||
|
|
||||||
|
AILLabel LblTaken = new AILLabel();
|
||||||
|
|
||||||
|
Context.Emit(ILOp, LblTaken);
|
||||||
|
|
||||||
|
Context.EmitLdc_I8(Op.Position + 4);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ret);
|
||||||
|
|
||||||
|
Context.MarkLabel(LblTaken);
|
||||||
|
|
||||||
|
Context.EmitLdc_I8(Op.Imm);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -406,5 +406,10 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
|
EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Umull_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -46,6 +46,45 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorCmp(Context, OpCodes.Blt_S);
|
EmitVectorCmp(Context, OpCodes.Blt_S);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Cmtst_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||||
|
|
||||||
|
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||||
|
|
||||||
|
ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size));
|
||||||
|
|
||||||
|
for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
|
||||||
|
{
|
||||||
|
EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
|
||||||
|
EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size);
|
||||||
|
|
||||||
|
AILLabel LblTrue = new AILLabel();
|
||||||
|
AILLabel LblEnd = new AILLabel();
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.And);
|
||||||
|
|
||||||
|
Context.EmitLdc_I4(0);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Bne_Un_S, LblTrue);
|
||||||
|
|
||||||
|
EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||||
|
|
||||||
|
Context.MarkLabel(LblTrue);
|
||||||
|
|
||||||
|
EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask);
|
||||||
|
|
||||||
|
Context.MarkLabel(LblEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||||
|
{
|
||||||
|
EmitVectorZeroUpper(Context, Op.Rd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fccmp_S(AILEmitterCtx Context)
|
public static void Fccmp_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
|
AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using ChocolArm64.Decoder;
|
||||||
|
using ChocolArm64.State;
|
||||||
using ChocolArm64.Translation;
|
using ChocolArm64.Translation;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
|
@ -65,5 +67,28 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
EmitVectorImmBinaryOp(Context, () => Context.Emit(OpCodes.Or));
|
EmitVectorImmBinaryOp(Context, () => Context.Emit(OpCodes.Or));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Rev64_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||||
|
|
||||||
|
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||||
|
|
||||||
|
int Elems = Bytes >> Op.Size;
|
||||||
|
|
||||||
|
int RevIndex = Elems - 1;
|
||||||
|
|
||||||
|
for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
|
||||||
|
{
|
||||||
|
EmitVectorExtractZx(Context, Op.Rn, RevIndex--, Op.Size);
|
||||||
|
|
||||||
|
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||||
|
{
|
||||||
|
EmitVectorZeroUpper(Context, Op.Rd);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -57,6 +57,31 @@ namespace ChocolArm64.Instruction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Ext_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
AOpCodeSimdExt Op = (AOpCodeSimdExt)Context.CurrOp;
|
||||||
|
|
||||||
|
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||||
|
|
||||||
|
for (int Index = 0; Index < Bytes; Index++)
|
||||||
|
{
|
||||||
|
int Position = Op.Imm4 + Index;
|
||||||
|
|
||||||
|
int Reg = Position < Bytes ? Op.Rn : Op.Rm;
|
||||||
|
|
||||||
|
Position &= Bytes - 1;
|
||||||
|
|
||||||
|
EmitVectorExtractZx(Context, Reg, Position, 0);
|
||||||
|
|
||||||
|
EmitVectorInsert(Context, Op.Rd, Index, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||||
|
{
|
||||||
|
EmitVectorZeroUpper(Context, Op.Rd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fcsel_S(AILEmitterCtx Context)
|
public static void Fcsel_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
|
AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
|
||||||
|
|
|
@ -75,7 +75,7 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
private static ulong ReverseBytes(ulong Value, RevSize Size)
|
private static ulong ReverseBytes(ulong Value, RevSize Size)
|
||||||
{
|
{
|
||||||
Value = ((Value & 0xff00ff00ff00ff00) >> 8) | ((Value & 0x00ff00ff00ff00ff) << 8);
|
Value = ((Value & 0xff00ff00ff00ff00) >> 8) | ((Value & 0x00ff00ff00ff00ff) << 8);
|
||||||
|
|
||||||
if (Size == RevSize.Rev16)
|
if (Size == RevSize.Rev16)
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,9 +41,9 @@ namespace ChocolArm64.Memory
|
||||||
|
|
||||||
private byte* RamPtr;
|
private byte* RamPtr;
|
||||||
|
|
||||||
public AMemory(IntPtr Ram, AMemoryAlloc Allocator)
|
public AMemory(IntPtr Ram)
|
||||||
{
|
{
|
||||||
Manager = new AMemoryMgr(Allocator);
|
Manager = new AMemoryMgr();
|
||||||
|
|
||||||
Monitors = new Dictionary<int, ExMonitor>();
|
Monitors = new Dictionary<int, ExMonitor>();
|
||||||
|
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
using ChocolArm64.Exceptions;
|
|
||||||
|
|
||||||
namespace ChocolArm64.Memory
|
|
||||||
{
|
|
||||||
public class AMemoryAlloc
|
|
||||||
{
|
|
||||||
private long PhysPos;
|
|
||||||
|
|
||||||
public long Alloc(long Size)
|
|
||||||
{
|
|
||||||
long Position = PhysPos;
|
|
||||||
|
|
||||||
Size = AMemoryHelper.PageRoundUp(Size);
|
|
||||||
|
|
||||||
PhysPos += Size;
|
|
||||||
|
|
||||||
if (PhysPos > AMemoryMgr.RamSize || PhysPos < 0)
|
|
||||||
{
|
|
||||||
throw new VmmOutOfMemoryException(Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Free(long Position)
|
|
||||||
{
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
public long GetFreeMem()
|
|
||||||
{
|
|
||||||
return AMemoryMgr.RamSize - PhysPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace ChocolArm64.Memory
|
namespace ChocolArm64.Memory
|
||||||
{
|
{
|
||||||
public struct AMemoryMapInfo
|
public class AMemoryMapInfo
|
||||||
{
|
{
|
||||||
public long Position { get; private set; }
|
public long Position { get; private set; }
|
||||||
public long Size { get; private set; }
|
public long Size { get; private set; }
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace ChocolArm64.Memory
|
namespace ChocolArm64.Memory
|
||||||
{
|
{
|
||||||
public class AMemoryMgr
|
public class AMemoryMgr
|
||||||
|
@ -5,22 +7,20 @@ namespace ChocolArm64.Memory
|
||||||
public const long AddrSize = RamSize;
|
public const long AddrSize = RamSize;
|
||||||
public const long RamSize = 4L * 1024 * 1024 * 1024;
|
public const long RamSize = 4L * 1024 * 1024 * 1024;
|
||||||
|
|
||||||
private const int PTLvl0Bits = 11;
|
private const int PTLvl0Bits = 10;
|
||||||
private const int PTLvl1Bits = 13;
|
private const int PTLvl1Bits = 10;
|
||||||
private const int PTPageBits = 12;
|
private const int PTPageBits = 12;
|
||||||
|
|
||||||
private const int PTLvl0Size = 1 << PTLvl0Bits;
|
private const int PTLvl0Size = 1 << PTLvl0Bits;
|
||||||
private const int PTLvl1Size = 1 << PTLvl1Bits;
|
private const int PTLvl1Size = 1 << PTLvl1Bits;
|
||||||
public const int PageSize = 1 << PTPageBits;
|
public const int PageSize = 1 << PTPageBits;
|
||||||
|
|
||||||
private const int PTLvl0Mask = PTLvl0Size - 1;
|
private const int PTLvl0Mask = PTLvl0Size - 1;
|
||||||
private const int PTLvl1Mask = PTLvl1Size - 1;
|
private const int PTLvl1Mask = PTLvl1Size - 1;
|
||||||
public const int PageMask = PageSize - 1;
|
public const int PageMask = PageSize - 1;
|
||||||
|
|
||||||
private const int PTLvl0Bit = PTPageBits + PTLvl0Bits;
|
private const int PTLvl0Bit = PTPageBits + PTLvl1Bits;
|
||||||
private const int PTLvl1Bit = PTPageBits;
|
private const int PTLvl1Bit = PTPageBits;
|
||||||
|
|
||||||
private AMemoryAlloc Allocator;
|
|
||||||
|
|
||||||
private enum PTMap
|
private enum PTMap
|
||||||
{
|
{
|
||||||
|
@ -47,132 +47,24 @@ namespace ChocolArm64.Memory
|
||||||
|
|
||||||
private PTEntry[][] PageTable;
|
private PTEntry[][] PageTable;
|
||||||
|
|
||||||
private bool IsHeapInitialized;
|
public AMemoryMgr()
|
||||||
|
|
||||||
public long HeapAddr { get; private set; }
|
|
||||||
public long HeapSize { get; private set; }
|
|
||||||
|
|
||||||
public AMemoryMgr(AMemoryAlloc Allocator)
|
|
||||||
{
|
{
|
||||||
this.Allocator = Allocator;
|
|
||||||
|
|
||||||
PageTable = new PTEntry[PTLvl0Size][];
|
PageTable = new PTEntry[PTLvl0Size][];
|
||||||
}
|
}
|
||||||
|
|
||||||
public long GetTotalMemorySize()
|
public void Map(long Position, long Size, int Type, AMemoryPerm Perm)
|
||||||
{
|
{
|
||||||
return Allocator.GetFreeMem() + GetUsedMemorySize();
|
SetPTEntry(Position, Size, new PTEntry(PTMap.Mapped, Perm, Type, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public long GetUsedMemorySize()
|
public void Unmap(long Position, long Size)
|
||||||
{
|
{
|
||||||
long Size = 0;
|
SetPTEntry(Position, Size, new PTEntry(PTMap.Unmapped, 0, 0, 0));
|
||||||
|
|
||||||
for (int L0 = 0; L0 < PageTable.Length; L0++)
|
|
||||||
{
|
|
||||||
if (PageTable[L0] == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int L1 = 0; L1 < PageTable[L0].Length; L1++)
|
|
||||||
{
|
|
||||||
Size += PageTable[L0][L1].Map != PTMap.Unmapped ? PageSize : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SetHeapAddr(long Position)
|
public void Unmap(long Position, long Size, int Type)
|
||||||
{
|
{
|
||||||
if (!IsHeapInitialized)
|
SetPTEntry(Position, Size, Type, new PTEntry(PTMap.Unmapped, 0, 0, 0));
|
||||||
{
|
|
||||||
HeapAddr = Position;
|
|
||||||
|
|
||||||
IsHeapInitialized = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetHeapSize(long Size, int Type)
|
|
||||||
{
|
|
||||||
//TODO: Return error when theres no enough space to allocate heap.
|
|
||||||
Size = AMemoryHelper.PageRoundUp(Size);
|
|
||||||
|
|
||||||
long Position = HeapAddr;
|
|
||||||
|
|
||||||
if ((ulong)Size < (ulong)HeapSize)
|
|
||||||
{
|
|
||||||
//Try to free now free area if size is smaller than old size.
|
|
||||||
Position += Size;
|
|
||||||
|
|
||||||
while ((ulong)Size < (ulong)HeapSize)
|
|
||||||
{
|
|
||||||
Allocator.Free(Position);
|
|
||||||
|
|
||||||
Position += PageSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Allocate extra needed size.
|
|
||||||
Position += HeapSize;
|
|
||||||
Size -= HeapSize;
|
|
||||||
|
|
||||||
MapPhys(Position, Size, Type, AMemoryPerm.RW);
|
|
||||||
}
|
|
||||||
|
|
||||||
HeapSize = Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MapPhys(long Position, long Size, int Type, AMemoryPerm Perm)
|
|
||||||
{
|
|
||||||
while (Size > 0)
|
|
||||||
{
|
|
||||||
if (!IsMapped(Position))
|
|
||||||
{
|
|
||||||
SetPTEntry(Position, new PTEntry(PTMap.Mapped, Perm, Type, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
long CPgSize = PageSize - (Position & PageMask);
|
|
||||||
|
|
||||||
Position += CPgSize;
|
|
||||||
Size -= CPgSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MapMirror(long Src, long Dst, long Size, int Type)
|
|
||||||
{
|
|
||||||
Src = AMemoryHelper.PageRoundDown(Src);
|
|
||||||
Dst = AMemoryHelper.PageRoundDown(Dst);
|
|
||||||
|
|
||||||
Size = AMemoryHelper.PageRoundUp(Size);
|
|
||||||
|
|
||||||
long PagesCount = Size / PageSize;
|
|
||||||
|
|
||||||
while (PagesCount-- > 0)
|
|
||||||
{
|
|
||||||
PTEntry SrcEntry = GetPTEntry(Src);
|
|
||||||
PTEntry DstEntry = GetPTEntry(Dst);
|
|
||||||
|
|
||||||
DstEntry.Map = PTMap.Mapped;
|
|
||||||
DstEntry.Type = Type;
|
|
||||||
DstEntry.Perm = SrcEntry.Perm;
|
|
||||||
|
|
||||||
SrcEntry.Perm = AMemoryPerm.None;
|
|
||||||
|
|
||||||
SrcEntry.Attr |= 1;
|
|
||||||
|
|
||||||
SetPTEntry(Src, SrcEntry);
|
|
||||||
SetPTEntry(Dst, DstEntry);
|
|
||||||
|
|
||||||
Src += PageSize;
|
|
||||||
Dst += PageSize;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reprotect(long Position, long Size, AMemoryPerm Perm)
|
public void Reprotect(long Position, long Size, AMemoryPerm Perm)
|
||||||
|
@ -197,12 +89,22 @@ namespace ChocolArm64.Memory
|
||||||
|
|
||||||
public AMemoryMapInfo GetMapInfo(long Position)
|
public AMemoryMapInfo GetMapInfo(long Position)
|
||||||
{
|
{
|
||||||
|
if (!IsValidPosition(Position))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Position = AMemoryHelper.PageRoundDown(Position);
|
Position = AMemoryHelper.PageRoundDown(Position);
|
||||||
|
|
||||||
PTEntry BaseEntry = GetPTEntry(Position);
|
PTEntry BaseEntry = GetPTEntry(Position);
|
||||||
|
|
||||||
bool IsSameSegment(long Pos)
|
bool IsSameSegment(long Pos)
|
||||||
{
|
{
|
||||||
|
if (!IsValidPosition(Pos))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
PTEntry Entry = GetPTEntry(Pos);
|
PTEntry Entry = GetPTEntry(Pos);
|
||||||
|
|
||||||
return Entry.Map == BaseEntry.Map &&
|
return Entry.Map == BaseEntry.Map &&
|
||||||
|
@ -269,6 +171,16 @@ namespace ChocolArm64.Memory
|
||||||
return GetPTEntry(Position).Perm.HasFlag(Perm);
|
return GetPTEntry(Position).Perm.HasFlag(Perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsValidPosition(long Position)
|
||||||
|
{
|
||||||
|
if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsMapped(long Position)
|
public bool IsMapped(long Position)
|
||||||
{
|
{
|
||||||
if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
|
if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
|
||||||
|
@ -300,8 +212,38 @@ namespace ChocolArm64.Memory
|
||||||
return PageTable[L0][L1];
|
return PageTable[L0][L1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetPTEntry(long Position, long Size, PTEntry Entry)
|
||||||
|
{
|
||||||
|
while (Size > 0)
|
||||||
|
{
|
||||||
|
SetPTEntry(Position, Entry);
|
||||||
|
|
||||||
|
Position += PageSize;
|
||||||
|
Size -= PageSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPTEntry(long Position, long Size, int Type, PTEntry Entry)
|
||||||
|
{
|
||||||
|
while (Size > 0)
|
||||||
|
{
|
||||||
|
if (GetPTEntry(Position).Type == Type)
|
||||||
|
{
|
||||||
|
SetPTEntry(Position, Entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += PageSize;
|
||||||
|
Size -= PageSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SetPTEntry(long Position, PTEntry Entry)
|
private void SetPTEntry(long Position, PTEntry Entry)
|
||||||
{
|
{
|
||||||
|
if (!IsValidPosition(Position))
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(Position));
|
||||||
|
}
|
||||||
|
|
||||||
long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
|
long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
|
||||||
long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
|
long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
|
||||||
|
|
||||||
|
|
|
@ -58,11 +58,13 @@ namespace ChocolArm64.Translation
|
||||||
this.Root = ILBlocks[Array.IndexOf(Graph, Root)];
|
this.Root = ILBlocks[Array.IndexOf(Graph, Root)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public ATranslatedSub GetSubroutine()
|
public AILBlock GetILBlock(int Index) => ILBlocks[Index];
|
||||||
|
|
||||||
|
public ATranslatedSub GetSubroutine(HashSet<long> Callees)
|
||||||
{
|
{
|
||||||
LocalAlloc = new ALocalAlloc(ILBlocks, Root);
|
LocalAlloc = new ALocalAlloc(ILBlocks, Root);
|
||||||
|
|
||||||
InitSubroutine();
|
InitSubroutine(Callees);
|
||||||
InitLocals();
|
InitLocals();
|
||||||
|
|
||||||
foreach (AILBlock ILBlock in ILBlocks)
|
foreach (AILBlock ILBlock in ILBlocks)
|
||||||
|
@ -73,24 +75,7 @@ namespace ChocolArm64.Translation
|
||||||
return Subroutine;
|
return Subroutine;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AILBlock GetILBlock(int Index) => ILBlocks[Index];
|
private void InitSubroutine(HashSet<long> Callees)
|
||||||
|
|
||||||
private void InitLocals()
|
|
||||||
{
|
|
||||||
int ParamsStart = ATranslatedSub.FixedArgTypes.Length;
|
|
||||||
|
|
||||||
Locals = new Dictionary<ARegister, int>();
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Subroutine.Params.Count; Index++)
|
|
||||||
{
|
|
||||||
ARegister Reg = Subroutine.Params[Index];
|
|
||||||
|
|
||||||
Generator.EmitLdarg(Index + ParamsStart);
|
|
||||||
Generator.EmitStloc(GetLocalIndex(Reg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitSubroutine()
|
|
||||||
{
|
{
|
||||||
List<ARegister> Params = new List<ARegister>();
|
List<ARegister> Params = new List<ARegister>();
|
||||||
|
|
||||||
|
@ -114,9 +99,24 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
Generator = Mthd.GetILGenerator();
|
Generator = Mthd.GetILGenerator();
|
||||||
|
|
||||||
Subroutine = new ATranslatedSub(Mthd, Params);
|
Subroutine = new ATranslatedSub(Mthd, Params, Callees);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitLocals()
|
||||||
|
{
|
||||||
|
int ParamsStart = ATranslatedSub.FixedArgTypes.Length;
|
||||||
|
|
||||||
|
Locals = new Dictionary<ARegister, int>();
|
||||||
|
|
||||||
|
for (int Index = 0; Index < Subroutine.Params.Count; Index++)
|
||||||
|
{
|
||||||
|
ARegister Reg = Subroutine.Params[Index];
|
||||||
|
|
||||||
|
Generator.EmitLdarg(Index + ParamsStart);
|
||||||
|
Generator.EmitStloc(GetLocalIndex(Reg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Type[] GetParamTypes(IList<ARegister> Params)
|
private Type[] GetParamTypes(IList<ARegister> Params)
|
||||||
{
|
{
|
||||||
Type[] FixedArgs = ATranslatedSub.FixedArgTypes;
|
Type[] FixedArgs = ATranslatedSub.FixedArgTypes;
|
||||||
|
|
|
@ -12,14 +12,9 @@ namespace ChocolArm64.Translation
|
||||||
{
|
{
|
||||||
private ATranslator Translator;
|
private ATranslator Translator;
|
||||||
|
|
||||||
private Dictionary<long, AILLabel> Labels;
|
private HashSet<long> Callees;
|
||||||
|
|
||||||
private AILEmitter Emitter;
|
private Dictionary<long, AILLabel> Labels;
|
||||||
|
|
||||||
private AILBlock ILBlock;
|
|
||||||
|
|
||||||
private AOpCode OptOpLastCompare;
|
|
||||||
private AOpCode OptOpLastFlagSet;
|
|
||||||
|
|
||||||
private int BlkIndex;
|
private int BlkIndex;
|
||||||
private int OpcIndex;
|
private int OpcIndex;
|
||||||
|
@ -29,6 +24,13 @@ namespace ChocolArm64.Translation
|
||||||
public ABlock CurrBlock => Graph[BlkIndex];
|
public ABlock CurrBlock => Graph[BlkIndex];
|
||||||
public AOpCode CurrOp => Graph[BlkIndex].OpCodes[OpcIndex];
|
public AOpCode CurrOp => Graph[BlkIndex].OpCodes[OpcIndex];
|
||||||
|
|
||||||
|
private AILEmitter Emitter;
|
||||||
|
|
||||||
|
private AILBlock ILBlock;
|
||||||
|
|
||||||
|
private AOpCode OptOpLastCompare;
|
||||||
|
private AOpCode OptOpLastFlagSet;
|
||||||
|
|
||||||
//This is the index of the temporary register, used to store temporary
|
//This is the index of the temporary register, used to store temporary
|
||||||
//values needed by some functions, since IL doesn't have a swap instruction.
|
//values needed by some functions, since IL doesn't have a swap instruction.
|
||||||
//You can use any value here as long it doesn't conflict with the indices
|
//You can use any value here as long it doesn't conflict with the indices
|
||||||
|
@ -45,10 +47,27 @@ namespace ChocolArm64.Translation
|
||||||
ABlock Root,
|
ABlock Root,
|
||||||
string SubName)
|
string SubName)
|
||||||
{
|
{
|
||||||
|
if (Translator == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(Translator));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Graph == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(Graph));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Root == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(Root));
|
||||||
|
}
|
||||||
|
|
||||||
this.Translator = Translator;
|
this.Translator = Translator;
|
||||||
this.Graph = Graph;
|
this.Graph = Graph;
|
||||||
this.Root = Root;
|
this.Root = Root;
|
||||||
|
|
||||||
|
Callees = new HashSet<long>();
|
||||||
|
|
||||||
Labels = new Dictionary<long, AILLabel>();
|
Labels = new Dictionary<long, AILLabel>();
|
||||||
|
|
||||||
Emitter = new AILEmitter(Graph, Root, SubName);
|
Emitter = new AILEmitter(Graph, Root, SubName);
|
||||||
|
@ -57,23 +76,27 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
OpcIndex = -1;
|
OpcIndex = -1;
|
||||||
|
|
||||||
if (!AdvanceOpCode())
|
if (Graph.Length == 0 || !AdvanceOpCode())
|
||||||
{
|
{
|
||||||
throw new ArgumentException(nameof(Graph));
|
throw new ArgumentException(nameof(Graph));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ATranslatedSub GetSubroutine() => Emitter.GetSubroutine();
|
public ATranslatedSub GetSubroutine()
|
||||||
|
{
|
||||||
|
return Emitter.GetSubroutine(Callees);
|
||||||
|
}
|
||||||
|
|
||||||
public bool AdvanceOpCode()
|
public bool AdvanceOpCode()
|
||||||
{
|
{
|
||||||
|
if (OpcIndex + 1 == CurrBlock.OpCodes.Count &&
|
||||||
|
BlkIndex + 1 == Graph.Length)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
while (++OpcIndex >= (CurrBlock?.OpCodes.Count ?? 0))
|
while (++OpcIndex >= (CurrBlock?.OpCodes.Count ?? 0))
|
||||||
{
|
{
|
||||||
if (BlkIndex + 1 >= Graph.Length)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlkIndex++;
|
BlkIndex++;
|
||||||
OpcIndex = -1;
|
OpcIndex = -1;
|
||||||
|
|
||||||
|
@ -100,6 +123,13 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
public bool TryOptEmitSubroutineCall()
|
public bool TryOptEmitSubroutineCall()
|
||||||
{
|
{
|
||||||
|
Callees.Add(((AOpCodeBImm)CurrOp).Imm);
|
||||||
|
|
||||||
|
if (CurrBlock.Next == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Translator.TryGetCachedSub(CurrOp, out ATranslatedSub Sub))
|
if (!Translator.TryGetCachedSub(CurrOp, out ATranslatedSub Sub))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -67,14 +67,15 @@ namespace ChocolArm64.Translation
|
||||||
public long VecOutputs;
|
public long VecOutputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private const int MaxOptGraphLength = 55;
|
private const int MaxOptGraphLength = 40;
|
||||||
|
|
||||||
public ALocalAlloc(AILBlock[] Graph, AILBlock Root)
|
public ALocalAlloc(AILBlock[] Graph, AILBlock Root)
|
||||||
{
|
{
|
||||||
IntPaths = new Dictionary<AILBlock, PathIo>();
|
IntPaths = new Dictionary<AILBlock, PathIo>();
|
||||||
VecPaths = new Dictionary<AILBlock, PathIo>();
|
VecPaths = new Dictionary<AILBlock, PathIo>();
|
||||||
|
|
||||||
if (Graph.Length < MaxOptGraphLength)
|
if (Graph.Length > 1 &&
|
||||||
|
Graph.Length < MaxOptGraphLength)
|
||||||
{
|
{
|
||||||
InitializeOptimal(Graph, Root);
|
InitializeOptimal(Graph, Root);
|
||||||
}
|
}
|
||||||
|
@ -179,10 +180,8 @@ namespace ChocolArm64.Translation
|
||||||
{
|
{
|
||||||
//This is WAY faster than InitializeOptimal, but results in
|
//This is WAY faster than InitializeOptimal, but results in
|
||||||
//uneeded loads and stores, so the resulting code will be slower.
|
//uneeded loads and stores, so the resulting code will be slower.
|
||||||
long IntInputs = 0;
|
long IntInputs = 0, IntOutputs = 0;
|
||||||
long IntOutputs = 0;
|
long VecInputs = 0, VecOutputs = 0;
|
||||||
long VecInputs = 0;
|
|
||||||
long VecOutputs = 0;
|
|
||||||
|
|
||||||
foreach (AILBlock Block in Graph)
|
foreach (AILBlock Block in Graph)
|
||||||
{
|
{
|
||||||
|
@ -196,8 +195,11 @@ namespace ChocolArm64.Translation
|
||||||
//in those cases if we attempt to write an output registers that was
|
//in those cases if we attempt to write an output registers that was
|
||||||
//not written, we will be just writing zero and messing up the old register value.
|
//not written, we will be just writing zero and messing up the old register value.
|
||||||
//So we just need to ensure that all outputs are loaded.
|
//So we just need to ensure that all outputs are loaded.
|
||||||
IntInputs |= IntOutputs;
|
if (Graph.Length > 1)
|
||||||
VecInputs |= VecOutputs;
|
{
|
||||||
|
IntInputs |= IntOutputs;
|
||||||
|
VecInputs |= VecOutputs;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (AILBlock Block in Graph)
|
foreach (AILBlock Block in Graph)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using Ryujinx.Core.Input;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
|
@ -1,225 +0,0 @@
|
||||||
using Ryujinx.Core.OsHle;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Core
|
|
||||||
{
|
|
||||||
public class Hid
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Thanks to:
|
|
||||||
https://github.com/reswitched/libtransistor/blob/development/lib/hid.c
|
|
||||||
https://github.com/reswitched/libtransistor/blob/development/include/libtransistor/hid.h
|
|
||||||
https://github.com/switchbrew/libnx/blob/master/nx/source/services/hid.c
|
|
||||||
https://github.com/switchbrew/libnx/blob/master/nx/include/switch/services/hid.h
|
|
||||||
|
|
||||||
struct HidSharedMemory
|
|
||||||
{
|
|
||||||
header[0x400];
|
|
||||||
touchscreen[0x3000];
|
|
||||||
mouse[0x400];
|
|
||||||
keyboard[0x400];
|
|
||||||
unkSection1[0x400];
|
|
||||||
unkSection2[0x400];
|
|
||||||
unkSection3[0x400];
|
|
||||||
unkSection4[0x400];
|
|
||||||
unkSection5[0x200];
|
|
||||||
unkSection6[0x200];
|
|
||||||
unkSection7[0x200];
|
|
||||||
unkSection8[0x800];
|
|
||||||
controllerSerials[0x4000];
|
|
||||||
controllers[0x5000 * 10];
|
|
||||||
unkSection9[0x4600];
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
private const int Hid_Num_Entries = 17;
|
|
||||||
private Switch Ns;
|
|
||||||
private long SharedMemOffset;
|
|
||||||
|
|
||||||
public Hid(Switch Ns)
|
|
||||||
{
|
|
||||||
this.Ns = Ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Init(long HidOffset)
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
if (HidOffset == 0 || HidOffset + Horizon.HidSize > uint.MaxValue)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedMemOffset = HidOffset;
|
|
||||||
|
|
||||||
uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader));
|
|
||||||
|
|
||||||
IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
|
|
||||||
|
|
||||||
HidTouchScreen TouchScreen = new HidTouchScreen();
|
|
||||||
TouchScreen.Header.TimestampTicks = (ulong)Environment.TickCount;
|
|
||||||
TouchScreen.Header.NumEntries = (ulong)Hid_Num_Entries;
|
|
||||||
TouchScreen.Header.LatestEntry = 0;
|
|
||||||
TouchScreen.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1;
|
|
||||||
TouchScreen.Header.Timestamp = (ulong)Environment.TickCount;
|
|
||||||
|
|
||||||
Marshal.StructureToPtr(TouchScreen, HidPtr, false);
|
|
||||||
|
|
||||||
InnerOffset += (uint)Marshal.SizeOf(typeof(HidTouchScreen));
|
|
||||||
HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
|
|
||||||
|
|
||||||
HidMouse Mouse = new HidMouse();
|
|
||||||
Mouse.Header.TimestampTicks = (ulong)Environment.TickCount;
|
|
||||||
Mouse.Header.NumEntries = (ulong)Hid_Num_Entries;
|
|
||||||
Mouse.Header.LatestEntry = 0;
|
|
||||||
Mouse.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1;
|
|
||||||
|
|
||||||
//TODO: Write this structure when the input is implemented
|
|
||||||
//Marshal.StructureToPtr(Mouse, HidPtr, false);
|
|
||||||
|
|
||||||
InnerOffset += (uint)Marshal.SizeOf(typeof(HidMouse));
|
|
||||||
HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
|
|
||||||
|
|
||||||
HidKeyboard Keyboard = new HidKeyboard();
|
|
||||||
Keyboard.Header.TimestampTicks = (ulong)Environment.TickCount;
|
|
||||||
Keyboard.Header.NumEntries = (ulong)Hid_Num_Entries;
|
|
||||||
Keyboard.Header.LatestEntry = 0;
|
|
||||||
Keyboard.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1;
|
|
||||||
|
|
||||||
//TODO: Write this structure when the input is implemented
|
|
||||||
//Marshal.StructureToPtr(Keyboard, HidPtr, false);
|
|
||||||
|
|
||||||
InnerOffset += (uint)Marshal.SizeOf(typeof(HidKeyboard)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection1)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection2)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection3)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection4)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection5)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection6)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection7)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection8)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidControllerSerials));
|
|
||||||
|
|
||||||
//Increase the loop to initialize more controller.
|
|
||||||
for (int i = 8; i < Enum.GetNames(typeof(HidControllerID)).Length - 1; i++)
|
|
||||||
{
|
|
||||||
HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset + (uint)(Marshal.SizeOf(typeof(HidController)) * i));
|
|
||||||
|
|
||||||
HidController Controller = new HidController();
|
|
||||||
Controller.Header.Type = (uint)(HidControllerType.ControllerType_Handheld | HidControllerType.ControllerType_JoyconPair);
|
|
||||||
Controller.Header.IsHalf = 0;
|
|
||||||
Controller.Header.SingleColorsDescriptor = (uint)(HidControllerColorDescription.ColorDesc_ColorsNonexistent);
|
|
||||||
Controller.Header.SingleColorBody = 0;
|
|
||||||
Controller.Header.SingleColorButtons = 0;
|
|
||||||
Controller.Header.SplitColorsDescriptor = 0;
|
|
||||||
Controller.Header.LeftColorBody = (uint)JoyConColor.Body_Neon_Red;
|
|
||||||
Controller.Header.LeftColorButtons = (uint)JoyConColor.Buttons_Neon_Red;
|
|
||||||
Controller.Header.RightColorBody = (uint)JoyConColor.Body_Neon_Blue;
|
|
||||||
Controller.Header.RightColorButtons = (uint)JoyConColor.Buttons_Neon_Blue;
|
|
||||||
|
|
||||||
Controller.Layouts = new HidControllerLayout[Enum.GetNames(typeof(HidControllerLayouts)).Length];
|
|
||||||
Controller.Layouts[(int)HidControllerLayouts.Main] = new HidControllerLayout();
|
|
||||||
Controller.Layouts[(int)HidControllerLayouts.Main].Header.LatestEntry = (ulong)Hid_Num_Entries;
|
|
||||||
|
|
||||||
Marshal.StructureToPtr(Controller, HidPtr, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Logging.Info("HID Initialized!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendControllerButtons(HidControllerID ControllerId,
|
|
||||||
HidControllerLayouts Layout,
|
|
||||||
HidControllerKeys Buttons,
|
|
||||||
JoystickPosition LeftJoystick,
|
|
||||||
JoystickPosition RightJoystick)
|
|
||||||
{
|
|
||||||
uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidTouchScreen)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidMouse)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidKeyboard)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection1)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection2)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection3)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection4)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection5)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection6)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection7)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidUnknownSection8)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidControllerSerials)) +
|
|
||||||
((uint)(Marshal.SizeOf(typeof(HidController)) * (int)ControllerId)) +
|
|
||||||
(uint)Marshal.SizeOf(typeof(HidControllerHeader)) +
|
|
||||||
(uint)Layout * (uint)Marshal.SizeOf(typeof(HidControllerLayout));
|
|
||||||
|
|
||||||
IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
|
|
||||||
|
|
||||||
HidControllerLayoutHeader OldControllerHeaderLayout = (HidControllerLayoutHeader)Marshal.PtrToStructure(HidPtr, typeof(HidControllerLayoutHeader));
|
|
||||||
|
|
||||||
HidControllerLayoutHeader ControllerLayoutHeader = new HidControllerLayoutHeader
|
|
||||||
{
|
|
||||||
TimestampTicks = (ulong)Environment.TickCount,
|
|
||||||
NumEntries = (ulong)Hid_Num_Entries,
|
|
||||||
MaxEntryIndex = (ulong)Hid_Num_Entries - 1,
|
|
||||||
LatestEntry = (OldControllerHeaderLayout.LatestEntry < (ulong)Hid_Num_Entries ? OldControllerHeaderLayout.LatestEntry + 1 : 0)
|
|
||||||
};
|
|
||||||
|
|
||||||
Marshal.StructureToPtr(ControllerLayoutHeader, HidPtr, false);
|
|
||||||
|
|
||||||
InnerOffset += (uint)Marshal.SizeOf(typeof(HidControllerLayoutHeader)) + (uint)((uint)(ControllerLayoutHeader.LatestEntry) * Marshal.SizeOf(typeof(HidControllerInputEntry)));
|
|
||||||
HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
|
|
||||||
|
|
||||||
HidControllerInputEntry ControllerInputEntry = new HidControllerInputEntry
|
|
||||||
{
|
|
||||||
Timestamp = (ulong)Environment.TickCount,
|
|
||||||
Timestamp_2 = (ulong)Environment.TickCount,
|
|
||||||
Buttons = (ulong)Buttons,
|
|
||||||
Joysticks = new JoystickPosition[(int)HidControllerJoystick.Joystick_Num_Sticks]
|
|
||||||
};
|
|
||||||
ControllerInputEntry.Joysticks[(int)HidControllerJoystick.Joystick_Left] = LeftJoystick;
|
|
||||||
ControllerInputEntry.Joysticks[(int)HidControllerJoystick.Joystick_Right] = RightJoystick;
|
|
||||||
ControllerInputEntry.ConnectionState = (ulong)(HidControllerConnectionState.Controller_State_Connected | HidControllerConnectionState.Controller_State_Wired);
|
|
||||||
|
|
||||||
Marshal.StructureToPtr(ControllerInputEntry, HidPtr, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendTouchPoint(HidTouchScreenEntryTouch TouchPoint)
|
|
||||||
{
|
|
||||||
uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader));
|
|
||||||
|
|
||||||
IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
|
|
||||||
|
|
||||||
HidTouchScreenHeader OldTouchScreenHeader = (HidTouchScreenHeader)Marshal.PtrToStructure(HidPtr,typeof(HidTouchScreenHeader));
|
|
||||||
|
|
||||||
HidTouchScreenHeader TouchScreenHeader = new HidTouchScreenHeader()
|
|
||||||
{
|
|
||||||
TimestampTicks = (ulong)Environment.TickCount,
|
|
||||||
NumEntries = (ulong)Hid_Num_Entries,
|
|
||||||
MaxEntryIndex = (ulong)Hid_Num_Entries - 1,
|
|
||||||
Timestamp = (ulong)Environment.TickCount,
|
|
||||||
LatestEntry = OldTouchScreenHeader.LatestEntry < Hid_Num_Entries-1 ? OldTouchScreenHeader.LatestEntry + 1 : 0
|
|
||||||
};
|
|
||||||
|
|
||||||
Marshal.StructureToPtr(TouchScreenHeader, HidPtr, false);
|
|
||||||
|
|
||||||
InnerOffset += (uint)Marshal.SizeOf(typeof(HidTouchScreenHeader))
|
|
||||||
+ (uint)((uint)(OldTouchScreenHeader.LatestEntry) * Marshal.SizeOf(typeof(HidTouchScreenEntry)));
|
|
||||||
HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
|
|
||||||
|
|
||||||
HidTouchScreenEntry hidTouchScreenEntry = new HidTouchScreenEntry()
|
|
||||||
{
|
|
||||||
Header = new HidTouchScreenEntryHeader()
|
|
||||||
{
|
|
||||||
Timestamp = (ulong)Environment.TickCount,
|
|
||||||
NumTouches = 1
|
|
||||||
},
|
|
||||||
Touches = new HidTouchScreenEntryTouch[16]
|
|
||||||
};
|
|
||||||
|
|
||||||
//Only supports single touch
|
|
||||||
hidTouchScreenEntry.Touches[0] = TouchPoint;
|
|
||||||
|
|
||||||
Marshal.StructureToPtr(hidTouchScreenEntry, HidPtr, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
239
Ryujinx.Core/Hid/Hid.cs
Normal file
239
Ryujinx.Core/Hid/Hid.cs
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
using ChocolArm64.Memory;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.Input
|
||||||
|
{
|
||||||
|
public class Hid
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Reference:
|
||||||
|
* https://github.com/reswitched/libtransistor/blob/development/lib/hid.c
|
||||||
|
* https://github.com/reswitched/libtransistor/blob/development/include/libtransistor/hid.h
|
||||||
|
* https://github.com/switchbrew/libnx/blob/master/nx/source/services/hid.c
|
||||||
|
* https://github.com/switchbrew/libnx/blob/master/nx/include/switch/services/hid.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
private const int HidHeaderSize = 0x400;
|
||||||
|
private const int HidTouchScreenSize = 0x3000;
|
||||||
|
private const int HidMouseSize = 0x400;
|
||||||
|
private const int HidKeyboardSize = 0x400;
|
||||||
|
private const int HidUnkSection1Size = 0x400;
|
||||||
|
private const int HidUnkSection2Size = 0x400;
|
||||||
|
private const int HidUnkSection3Size = 0x400;
|
||||||
|
private const int HidUnkSection4Size = 0x400;
|
||||||
|
private const int HidUnkSection5Size = 0x200;
|
||||||
|
private const int HidUnkSection6Size = 0x200;
|
||||||
|
private const int HidUnkSection7Size = 0x200;
|
||||||
|
private const int HidUnkSection8Size = 0x800;
|
||||||
|
private const int HidControllerSerialsSize = 0x4000;
|
||||||
|
private const int HidControllersSize = 0x32000;
|
||||||
|
private const int HidUnkSection9Size = 0x800;
|
||||||
|
|
||||||
|
private const int HidTouchHeaderSize = 0x28;
|
||||||
|
private const int HidTouchEntrySize = 0x298;
|
||||||
|
|
||||||
|
private const int HidTouchEntryHeaderSize = 0x10;
|
||||||
|
private const int HidTouchEntryTouchSize = 0x28;
|
||||||
|
|
||||||
|
private const int HidControllerSize = 0x5000;
|
||||||
|
private const int HidControllerHeaderSize = 0x28;
|
||||||
|
private const int HidControllerLayoutsSize = 0x350;
|
||||||
|
|
||||||
|
private const int HidControllersLayoutHeaderSize = 0x20;
|
||||||
|
private const int HidControllersInputEntrySize = 0x30;
|
||||||
|
|
||||||
|
private const int HidHeaderOffset = 0;
|
||||||
|
private const int HidTouchScreenOffset = HidHeaderOffset + HidHeaderSize;
|
||||||
|
private const int HidMouseOffset = HidTouchScreenOffset + HidTouchScreenSize;
|
||||||
|
private const int HidKeyboardOffset = HidMouseOffset + HidMouseSize;
|
||||||
|
private const int HidUnkSection1Offset = HidKeyboardOffset + HidKeyboardSize;
|
||||||
|
private const int HidUnkSection2Offset = HidUnkSection1Offset + HidUnkSection1Size;
|
||||||
|
private const int HidUnkSection3Offset = HidUnkSection2Offset + HidUnkSection2Size;
|
||||||
|
private const int HidUnkSection4Offset = HidUnkSection3Offset + HidUnkSection3Size;
|
||||||
|
private const int HidUnkSection5Offset = HidUnkSection4Offset + HidUnkSection4Size;
|
||||||
|
private const int HidUnkSection6Offset = HidUnkSection5Offset + HidUnkSection5Size;
|
||||||
|
private const int HidUnkSection7Offset = HidUnkSection6Offset + HidUnkSection6Size;
|
||||||
|
private const int HidUnkSection8Offset = HidUnkSection7Offset + HidUnkSection7Size;
|
||||||
|
private const int HidControllerSerialsOffset = HidUnkSection8Offset + HidUnkSection8Size;
|
||||||
|
private const int HidControllersOffset = HidControllerSerialsOffset + HidControllerSerialsSize;
|
||||||
|
private const int HidUnkSection9Offset = HidControllersOffset + HidControllersSize;
|
||||||
|
|
||||||
|
private const int HidEntryCount = 17;
|
||||||
|
|
||||||
|
private long SharedMemOffset;
|
||||||
|
|
||||||
|
private Switch Ns;
|
||||||
|
|
||||||
|
public Hid(Switch Ns)
|
||||||
|
{
|
||||||
|
this.Ns = Ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(long HidOffset)
|
||||||
|
{
|
||||||
|
SharedMemOffset = HidOffset;
|
||||||
|
|
||||||
|
InitializeJoyconPair(
|
||||||
|
JoyConColor.Body_Neon_Red,
|
||||||
|
JoyConColor.Buttons_Neon_Red,
|
||||||
|
JoyConColor.Body_Neon_Blue,
|
||||||
|
JoyConColor.Buttons_Neon_Blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitializeJoyconPair(
|
||||||
|
JoyConColor LeftColorBody,
|
||||||
|
JoyConColor LeftColorButtons,
|
||||||
|
JoyConColor RightColorBody,
|
||||||
|
JoyConColor RightColorButtons)
|
||||||
|
{
|
||||||
|
long BaseControllerOffset = HidControllersOffset + 8 * HidControllerSize;
|
||||||
|
|
||||||
|
HidControllerType Type =
|
||||||
|
HidControllerType.ControllerType_Handheld |
|
||||||
|
HidControllerType.ControllerType_JoyconPair;
|
||||||
|
|
||||||
|
bool IsHalf = false;
|
||||||
|
|
||||||
|
HidControllerColorDesc SingleColorDesc =
|
||||||
|
HidControllerColorDesc.ColorDesc_ColorsNonexistent;
|
||||||
|
|
||||||
|
JoyConColor SingleColorBody = JoyConColor.Black;
|
||||||
|
JoyConColor SingleColorButtons = JoyConColor.Black;
|
||||||
|
|
||||||
|
HidControllerColorDesc SplitColorDesc = 0;
|
||||||
|
|
||||||
|
WriteInt32(BaseControllerOffset + 0x0, (int)Type);
|
||||||
|
|
||||||
|
WriteInt32(BaseControllerOffset + 0x4, IsHalf ? 1 : 0);
|
||||||
|
|
||||||
|
WriteInt32(BaseControllerOffset + 0x8, (int)SingleColorDesc);
|
||||||
|
WriteInt32(BaseControllerOffset + 0xc, (int)SingleColorBody);
|
||||||
|
WriteInt32(BaseControllerOffset + 0x10, (int)SingleColorButtons);
|
||||||
|
WriteInt32(BaseControllerOffset + 0x14, (int)SplitColorDesc);
|
||||||
|
|
||||||
|
WriteInt32(BaseControllerOffset + 0x18, (int)LeftColorBody);
|
||||||
|
WriteInt32(BaseControllerOffset + 0x1c, (int)LeftColorButtons);
|
||||||
|
|
||||||
|
WriteInt32(BaseControllerOffset + 0x20, (int)RightColorBody);
|
||||||
|
WriteInt32(BaseControllerOffset + 0x24, (int)RightColorButtons);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetJoyconButton(
|
||||||
|
HidControllerId ControllerId,
|
||||||
|
HidControllerLayouts ControllerLayout,
|
||||||
|
HidControllerButtons Buttons,
|
||||||
|
HidJoystickPosition LeftStick,
|
||||||
|
HidJoystickPosition RightStick)
|
||||||
|
{
|
||||||
|
long ControllerOffset = HidControllersOffset + (int)ControllerId * HidControllerSize;
|
||||||
|
|
||||||
|
ControllerOffset += HidControllerHeaderSize;
|
||||||
|
|
||||||
|
ControllerOffset += (int)ControllerLayout * HidControllerLayoutsSize;
|
||||||
|
|
||||||
|
long LastEntry = ReadInt64(ControllerOffset + 0x10);
|
||||||
|
|
||||||
|
long CurrEntry = (LastEntry + 1) % HidEntryCount;
|
||||||
|
|
||||||
|
long Timestamp = Stopwatch.GetTimestamp();
|
||||||
|
|
||||||
|
WriteInt64(ControllerOffset + 0x0, Timestamp);
|
||||||
|
WriteInt64(ControllerOffset + 0x8, HidEntryCount);
|
||||||
|
WriteInt64(ControllerOffset + 0x10, CurrEntry);
|
||||||
|
WriteInt64(ControllerOffset + 0x18, HidEntryCount - 1);
|
||||||
|
|
||||||
|
ControllerOffset += HidControllersLayoutHeaderSize;
|
||||||
|
|
||||||
|
ControllerOffset += CurrEntry * HidControllersInputEntrySize;
|
||||||
|
|
||||||
|
WriteInt64(ControllerOffset + 0x0, Timestamp);
|
||||||
|
WriteInt64(ControllerOffset + 0x8, Timestamp);
|
||||||
|
|
||||||
|
WriteInt64(ControllerOffset + 0x10, (uint)Buttons);
|
||||||
|
|
||||||
|
WriteInt32(ControllerOffset + 0x18, LeftStick.DX);
|
||||||
|
WriteInt32(ControllerOffset + 0x1c, LeftStick.DY);
|
||||||
|
|
||||||
|
WriteInt64(ControllerOffset + 0x20, RightStick.DX);
|
||||||
|
WriteInt64(ControllerOffset + 0x24, RightStick.DY);
|
||||||
|
|
||||||
|
WriteInt64(ControllerOffset + 0x28,
|
||||||
|
(uint)HidControllerConnState.Controller_State_Connected |
|
||||||
|
(uint)HidControllerConnState.Controller_State_Wired);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTouchPoints(params HidTouchPoint[] Points)
|
||||||
|
{
|
||||||
|
long LastEntry = ReadInt64(HidTouchScreenOffset + 0x10);
|
||||||
|
|
||||||
|
long CurrEntry = (LastEntry + 1) % HidEntryCount;
|
||||||
|
|
||||||
|
long Timestamp = Stopwatch.GetTimestamp();
|
||||||
|
|
||||||
|
WriteInt64(HidTouchScreenOffset + 0x0, Timestamp);
|
||||||
|
WriteInt64(HidTouchScreenOffset + 0x8, HidEntryCount);
|
||||||
|
WriteInt64(HidTouchScreenOffset + 0x10, CurrEntry);
|
||||||
|
WriteInt64(HidTouchScreenOffset + 0x18, HidEntryCount - 1);
|
||||||
|
WriteInt64(HidTouchScreenOffset + 0x20, Timestamp);
|
||||||
|
|
||||||
|
long TouchEntryOffset = HidTouchScreenOffset + HidTouchHeaderSize;
|
||||||
|
|
||||||
|
long LastEntryOffset = TouchEntryOffset + LastEntry * HidTouchEntrySize;
|
||||||
|
|
||||||
|
long LastTimestamp = ReadInt64(LastEntryOffset);
|
||||||
|
|
||||||
|
TouchEntryOffset += CurrEntry * HidTouchEntrySize;
|
||||||
|
|
||||||
|
WriteInt64(TouchEntryOffset + 0x0, LastTimestamp + 1);
|
||||||
|
WriteInt64(TouchEntryOffset + 0x8, Points.Length);
|
||||||
|
|
||||||
|
TouchEntryOffset += HidTouchEntryHeaderSize;
|
||||||
|
|
||||||
|
const int Padding = 0;
|
||||||
|
|
||||||
|
int Index = 0;
|
||||||
|
|
||||||
|
foreach (HidTouchPoint Point in Points)
|
||||||
|
{
|
||||||
|
WriteInt64(TouchEntryOffset + 0x0, Timestamp);
|
||||||
|
WriteInt32(TouchEntryOffset + 0x8, Padding);
|
||||||
|
WriteInt32(TouchEntryOffset + 0xc, Index++);
|
||||||
|
WriteInt32(TouchEntryOffset + 0x10, Point.X);
|
||||||
|
WriteInt32(TouchEntryOffset + 0x14, Point.Y);
|
||||||
|
WriteInt32(TouchEntryOffset + 0x18, Point.DiameterX);
|
||||||
|
WriteInt32(TouchEntryOffset + 0x1c, Point.DiameterY);
|
||||||
|
WriteInt32(TouchEntryOffset + 0x20, Point.Angle);
|
||||||
|
WriteInt32(TouchEntryOffset + 0x24, Padding);
|
||||||
|
|
||||||
|
TouchEntryOffset += HidTouchEntryTouchSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe long ReadInt64(long Position)
|
||||||
|
{
|
||||||
|
Position += SharedMemOffset;
|
||||||
|
|
||||||
|
if ((ulong)Position + 8 > AMemoryMgr.AddrSize) return 0;
|
||||||
|
|
||||||
|
return *((long*)((byte*)Ns.Ram + Position));
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe void WriteInt32(long Position, int Value)
|
||||||
|
{
|
||||||
|
Position += SharedMemOffset;
|
||||||
|
|
||||||
|
if ((ulong)Position + 4 > AMemoryMgr.AddrSize) return;
|
||||||
|
|
||||||
|
*((int*)((byte*)Ns.Ram + Position)) = Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe void WriteInt64(long Position, long Value)
|
||||||
|
{
|
||||||
|
Position += SharedMemOffset;
|
||||||
|
|
||||||
|
if ((ulong)Position + 8 > AMemoryMgr.AddrSize) return;
|
||||||
|
|
||||||
|
*((long*)((byte*)Ns.Ram + Position)) = Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,188 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Core
|
|
||||||
{
|
|
||||||
[Flags]
|
|
||||||
public enum HidControllerKeys
|
|
||||||
{
|
|
||||||
KEY_A = (1 << 0),
|
|
||||||
KEY_B = (1 << 1),
|
|
||||||
KEY_X = (1 << 2),
|
|
||||||
KEY_Y = (1 << 3),
|
|
||||||
KEY_LSTICK = (1 << 4),
|
|
||||||
KEY_RSTICK = (1 << 5),
|
|
||||||
KEY_L = (1 << 6),
|
|
||||||
KEY_R = (1 << 7),
|
|
||||||
KEY_ZL = (1 << 8),
|
|
||||||
KEY_ZR = (1 << 9),
|
|
||||||
KEY_PLUS = (1 << 10),
|
|
||||||
KEY_MINUS = (1 << 11),
|
|
||||||
KEY_DLEFT = (1 << 12),
|
|
||||||
KEY_DUP = (1 << 13),
|
|
||||||
KEY_DRIGHT = (1 << 14),
|
|
||||||
KEY_DDOWN = (1 << 15),
|
|
||||||
KEY_LSTICK_LEFT = (1 << 16),
|
|
||||||
KEY_LSTICK_UP = (1 << 17),
|
|
||||||
KEY_LSTICK_RIGHT = (1 << 18),
|
|
||||||
KEY_LSTICK_DOWN = (1 << 19),
|
|
||||||
KEY_RSTICK_LEFT = (1 << 20),
|
|
||||||
KEY_RSTICK_UP = (1 << 21),
|
|
||||||
KEY_RSTICK_RIGHT = (1 << 22),
|
|
||||||
KEY_RSTICK_DOWN = (1 << 23),
|
|
||||||
KEY_SL = (1 << 24),
|
|
||||||
KEY_SR = (1 << 25),
|
|
||||||
|
|
||||||
// Pseudo-key for at least one finger on the touch screen
|
|
||||||
KEY_TOUCH = (1 << 26),
|
|
||||||
|
|
||||||
// Buttons by orientation (for single Joy-Con), also works with Joy-Con pairs, Pro Controller
|
|
||||||
KEY_JOYCON_RIGHT = (1 << 0),
|
|
||||||
KEY_JOYCON_DOWN = (1 << 1),
|
|
||||||
KEY_JOYCON_UP = (1 << 2),
|
|
||||||
KEY_JOYCON_LEFT = (1 << 3),
|
|
||||||
|
|
||||||
// Generic catch-all directions, also works for single Joy-Con
|
|
||||||
KEY_UP = KEY_DUP | KEY_LSTICK_UP | KEY_RSTICK_UP,
|
|
||||||
KEY_DOWN = KEY_DDOWN | KEY_LSTICK_DOWN | KEY_RSTICK_DOWN,
|
|
||||||
KEY_LEFT = KEY_DLEFT | KEY_LSTICK_LEFT | KEY_RSTICK_LEFT,
|
|
||||||
KEY_RIGHT = KEY_DRIGHT | KEY_LSTICK_RIGHT | KEY_RSTICK_RIGHT,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum HidControllerID
|
|
||||||
{
|
|
||||||
CONTROLLER_PLAYER_1 = 0,
|
|
||||||
CONTROLLER_PLAYER_2 = 1,
|
|
||||||
CONTROLLER_PLAYER_3 = 2,
|
|
||||||
CONTROLLER_PLAYER_4 = 3,
|
|
||||||
CONTROLLER_PLAYER_5 = 4,
|
|
||||||
CONTROLLER_PLAYER_6 = 5,
|
|
||||||
CONTROLLER_PLAYER_7 = 6,
|
|
||||||
CONTROLLER_PLAYER_8 = 7,
|
|
||||||
CONTROLLER_HANDHELD = 8,
|
|
||||||
CONTROLLER_UNKNOWN = 9
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum HidControllerJoystick
|
|
||||||
{
|
|
||||||
Joystick_Left = 0,
|
|
||||||
Joystick_Right = 1,
|
|
||||||
Joystick_Num_Sticks = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum HidControllerLayouts
|
|
||||||
{
|
|
||||||
Pro_Controller,
|
|
||||||
Handheld_Joined,
|
|
||||||
Joined,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Main_No_Analog,
|
|
||||||
Main
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum HidControllerConnectionState
|
|
||||||
{
|
|
||||||
Controller_State_Connected = (1 << 0),
|
|
||||||
Controller_State_Wired = (1 << 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum HidControllerType
|
|
||||||
{
|
|
||||||
ControllerType_ProController = (1 << 0),
|
|
||||||
ControllerType_Handheld = (1 << 1),
|
|
||||||
ControllerType_JoyconPair = (1 << 2),
|
|
||||||
ControllerType_JoyconLeft = (1 << 3),
|
|
||||||
ControllerType_JoyconRight = (1 << 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum HidControllerColorDescription
|
|
||||||
{
|
|
||||||
ColorDesc_ColorsNonexistent = (1 << 1),
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x8)]
|
|
||||||
public struct JoystickPosition
|
|
||||||
{
|
|
||||||
public int DX;
|
|
||||||
public int DY;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
|
|
||||||
public struct HidControllerMAC
|
|
||||||
{
|
|
||||||
public ulong Timestamp;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
|
||||||
public byte[] MAC;
|
|
||||||
public ulong Unknown;
|
|
||||||
public ulong Timestamp_2;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x28)]
|
|
||||||
public struct HidControllerHeader
|
|
||||||
{
|
|
||||||
public uint Type;
|
|
||||||
public uint IsHalf;
|
|
||||||
public uint SingleColorsDescriptor;
|
|
||||||
public uint SingleColorBody;
|
|
||||||
public uint SingleColorButtons;
|
|
||||||
public uint SplitColorsDescriptor;
|
|
||||||
public uint LeftColorBody;
|
|
||||||
public uint LeftColorButtons;
|
|
||||||
public uint RightColorBody;
|
|
||||||
public uint RightColorButtons;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
|
|
||||||
public struct HidControllerLayoutHeader
|
|
||||||
{
|
|
||||||
public ulong TimestampTicks;
|
|
||||||
public ulong NumEntries;
|
|
||||||
public ulong LatestEntry;
|
|
||||||
public ulong MaxEntryIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x30)]
|
|
||||||
public struct HidControllerInputEntry
|
|
||||||
{
|
|
||||||
public ulong Timestamp;
|
|
||||||
public ulong Timestamp_2;
|
|
||||||
public ulong Buttons;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)HidControllerJoystick.Joystick_Num_Sticks)]
|
|
||||||
public JoystickPosition[] Joysticks;
|
|
||||||
public ulong ConnectionState;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x350)]
|
|
||||||
public struct HidControllerLayout
|
|
||||||
{
|
|
||||||
public HidControllerLayoutHeader Header;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
|
|
||||||
public HidControllerInputEntry[] Entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x5000)]
|
|
||||||
public struct HidController
|
|
||||||
{
|
|
||||||
public HidControllerHeader Header;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
|
|
||||||
public HidControllerLayout[] Layouts;
|
|
||||||
/*
|
|
||||||
pro_controller
|
|
||||||
handheld_joined
|
|
||||||
joined
|
|
||||||
left
|
|
||||||
right
|
|
||||||
main_no_analog
|
|
||||||
main
|
|
||||||
*/
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x2A70)]
|
|
||||||
public byte[] Unknown_1;
|
|
||||||
public HidControllerMAC MacLeft;
|
|
||||||
public HidControllerMAC MacRight;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xDF8)]
|
|
||||||
public byte[] Unknown_2;
|
|
||||||
}
|
|
||||||
}
|
|
35
Ryujinx.Core/Hid/HidControllerButtons.cs
Normal file
35
Ryujinx.Core/Hid/HidControllerButtons.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.Input
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum HidControllerButtons
|
||||||
|
{
|
||||||
|
KEY_A = (1 << 0),
|
||||||
|
KEY_B = (1 << 1),
|
||||||
|
KEY_X = (1 << 2),
|
||||||
|
KEY_Y = (1 << 3),
|
||||||
|
KEY_LSTICK = (1 << 4),
|
||||||
|
KEY_RSTICK = (1 << 5),
|
||||||
|
KEY_L = (1 << 6),
|
||||||
|
KEY_R = (1 << 7),
|
||||||
|
KEY_ZL = (1 << 8),
|
||||||
|
KEY_ZR = (1 << 9),
|
||||||
|
KEY_PLUS = (1 << 10),
|
||||||
|
KEY_MINUS = (1 << 11),
|
||||||
|
KEY_DLEFT = (1 << 12),
|
||||||
|
KEY_DUP = (1 << 13),
|
||||||
|
KEY_DRIGHT = (1 << 14),
|
||||||
|
KEY_DDOWN = (1 << 15),
|
||||||
|
KEY_LSTICK_LEFT = (1 << 16),
|
||||||
|
KEY_LSTICK_UP = (1 << 17),
|
||||||
|
KEY_LSTICK_RIGHT = (1 << 18),
|
||||||
|
KEY_LSTICK_DOWN = (1 << 19),
|
||||||
|
KEY_RSTICK_LEFT = (1 << 20),
|
||||||
|
KEY_RSTICK_UP = (1 << 21),
|
||||||
|
KEY_RSTICK_RIGHT = (1 << 22),
|
||||||
|
KEY_RSTICK_DOWN = (1 << 23),
|
||||||
|
KEY_SL = (1 << 24),
|
||||||
|
KEY_SR = (1 << 25)
|
||||||
|
}
|
||||||
|
}
|
10
Ryujinx.Core/Hid/HidControllerColorDesc.cs
Normal file
10
Ryujinx.Core/Hid/HidControllerColorDesc.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.Input
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum HidControllerColorDesc
|
||||||
|
{
|
||||||
|
ColorDesc_ColorsNonexistent = (1 << 1)
|
||||||
|
}
|
||||||
|
}
|
11
Ryujinx.Core/Hid/HidControllerConnState.cs
Normal file
11
Ryujinx.Core/Hid/HidControllerConnState.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.Input
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum HidControllerConnState
|
||||||
|
{
|
||||||
|
Controller_State_Connected = (1 << 0),
|
||||||
|
Controller_State_Wired = (1 << 1)
|
||||||
|
}
|
||||||
|
}
|
16
Ryujinx.Core/Hid/HidControllerId.cs
Normal file
16
Ryujinx.Core/Hid/HidControllerId.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
namespace Ryujinx.Core.Input
|
||||||
|
{
|
||||||
|
public enum HidControllerId
|
||||||
|
{
|
||||||
|
CONTROLLER_PLAYER_1 = 0,
|
||||||
|
CONTROLLER_PLAYER_2 = 1,
|
||||||
|
CONTROLLER_PLAYER_3 = 2,
|
||||||
|
CONTROLLER_PLAYER_4 = 3,
|
||||||
|
CONTROLLER_PLAYER_5 = 4,
|
||||||
|
CONTROLLER_PLAYER_6 = 5,
|
||||||
|
CONTROLLER_PLAYER_7 = 6,
|
||||||
|
CONTROLLER_PLAYER_8 = 7,
|
||||||
|
CONTROLLER_HANDHELD = 8,
|
||||||
|
CONTROLLER_UNKNOWN = 9
|
||||||
|
}
|
||||||
|
}
|
13
Ryujinx.Core/Hid/HidControllerLayouts.cs
Normal file
13
Ryujinx.Core/Hid/HidControllerLayouts.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
namespace Ryujinx.Core.Input
|
||||||
|
{
|
||||||
|
public enum HidControllerLayouts
|
||||||
|
{
|
||||||
|
Pro_Controller = 0,
|
||||||
|
Handheld_Joined = 1,
|
||||||
|
Joined = 2,
|
||||||
|
Left = 3,
|
||||||
|
Right = 4,
|
||||||
|
Main_No_Analog = 5,
|
||||||
|
Main = 6
|
||||||
|
}
|
||||||
|
}
|
14
Ryujinx.Core/Hid/HidControllerType.cs
Normal file
14
Ryujinx.Core/Hid/HidControllerType.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.Input
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum HidControllerType
|
||||||
|
{
|
||||||
|
ControllerType_ProController = (1 << 0),
|
||||||
|
ControllerType_Handheld = (1 << 1),
|
||||||
|
ControllerType_JoyconPair = (1 << 2),
|
||||||
|
ControllerType_JoyconLeft = (1 << 3),
|
||||||
|
ControllerType_JoyconRight = (1 << 4)
|
||||||
|
}
|
||||||
|
}
|
8
Ryujinx.Core/Hid/HidJoystickPosition.cs
Normal file
8
Ryujinx.Core/Hid/HidJoystickPosition.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ryujinx.Core.Input
|
||||||
|
{
|
||||||
|
public struct HidJoystickPosition
|
||||||
|
{
|
||||||
|
public int DX;
|
||||||
|
public int DY;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,33 +0,0 @@
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Core
|
|
||||||
{
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
|
|
||||||
public struct HidKeyboardHeader
|
|
||||||
{
|
|
||||||
public ulong TimestampTicks;
|
|
||||||
public ulong NumEntries;
|
|
||||||
public ulong LatestEntry;
|
|
||||||
public ulong MaxEntryIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x38)]
|
|
||||||
public struct HidKeyboardEntry
|
|
||||||
{
|
|
||||||
public ulong Timestamp;
|
|
||||||
public ulong Timestamp_2;
|
|
||||||
public ulong Modifier;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
|
||||||
public uint[] Keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
|
|
||||||
public struct HidKeyboard
|
|
||||||
{
|
|
||||||
public HidKeyboardHeader Header;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
|
|
||||||
public HidKeyboardEntry[] Entries;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x28)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Core
|
|
||||||
{
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
|
|
||||||
public struct HidMouseHeader
|
|
||||||
{
|
|
||||||
public ulong TimestampTicks;
|
|
||||||
public ulong NumEntries;
|
|
||||||
public ulong LatestEntry;
|
|
||||||
public ulong MaxEntryIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x30)]
|
|
||||||
public struct HidMouseEntry
|
|
||||||
{
|
|
||||||
public ulong Timestamp;
|
|
||||||
public ulong Timestamp_2;
|
|
||||||
public uint X;
|
|
||||||
public uint Y;
|
|
||||||
public uint VelocityX;
|
|
||||||
public uint VelocityY;
|
|
||||||
public uint ScrollVelocityX;
|
|
||||||
public uint ScrollVelocityY;
|
|
||||||
public ulong Buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
|
|
||||||
public struct HidMouse
|
|
||||||
{
|
|
||||||
public HidMouseHeader Header;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
|
|
||||||
public HidMouseEntry[] Entries;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xB0)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
}
|
|
11
Ryujinx.Core/Hid/HidTouchPoint.cs
Normal file
11
Ryujinx.Core/Hid/HidTouchPoint.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace Ryujinx.Core.Input
|
||||||
|
{
|
||||||
|
public struct HidTouchPoint
|
||||||
|
{
|
||||||
|
public int X;
|
||||||
|
public int Y;
|
||||||
|
public int DiameterX;
|
||||||
|
public int DiameterY;
|
||||||
|
public int Angle;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,55 +0,0 @@
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Core
|
|
||||||
{
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x28)]
|
|
||||||
public struct HidTouchScreenHeader
|
|
||||||
{
|
|
||||||
public ulong TimestampTicks;
|
|
||||||
public ulong NumEntries;
|
|
||||||
public ulong LatestEntry;
|
|
||||||
public ulong MaxEntryIndex;
|
|
||||||
public ulong Timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
|
||||||
public struct HidTouchScreenEntryHeader
|
|
||||||
{
|
|
||||||
public ulong Timestamp;
|
|
||||||
public ulong NumTouches;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x28)]
|
|
||||||
public struct HidTouchScreenEntryTouch
|
|
||||||
{
|
|
||||||
public ulong Timestamp;
|
|
||||||
public uint Padding;
|
|
||||||
public uint TouchIndex;
|
|
||||||
public uint X;
|
|
||||||
public uint Y;
|
|
||||||
public uint DiameterX;
|
|
||||||
public uint DiameterY;
|
|
||||||
public uint Angle;
|
|
||||||
public uint Padding_2;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x298)]
|
|
||||||
public struct HidTouchScreenEntry
|
|
||||||
{
|
|
||||||
public HidTouchScreenEntryHeader Header;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
|
||||||
public HidTouchScreenEntryTouch[] Touches;
|
|
||||||
public ulong Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x3000)]
|
|
||||||
public struct HidTouchScreen
|
|
||||||
{
|
|
||||||
public HidTouchScreenHeader Header;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
|
|
||||||
public HidTouchScreenEntry[] Entries;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3C0)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Core
|
|
||||||
{
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
|
|
||||||
public struct HidSharedMemHeader
|
|
||||||
{
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
|
|
||||||
public struct HidUnknownSection1
|
|
||||||
{
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
|
|
||||||
public struct HidUnknownSection2
|
|
||||||
{
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
|
|
||||||
public struct HidUnknownSection3
|
|
||||||
{
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
|
|
||||||
public struct HidUnknownSection4
|
|
||||||
{
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x200)]
|
|
||||||
public struct HidUnknownSection5
|
|
||||||
{
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x200)]
|
|
||||||
public struct HidUnknownSection6
|
|
||||||
{
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x200)]
|
|
||||||
public struct HidUnknownSection7
|
|
||||||
{
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x800)]
|
|
||||||
public struct HidUnknownSection8
|
|
||||||
{
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x800)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x4000)]
|
|
||||||
public struct HidControllerSerials
|
|
||||||
{
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4000)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0x4600)]
|
|
||||||
public struct HidUnknownSection9
|
|
||||||
{
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4600)]
|
|
||||||
public byte[] Padding;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +1,6 @@
|
||||||
namespace Ryujinx
|
//TODO: This is only used by Config, it doesn't belong to Core.
|
||||||
|
namespace Ryujinx.Core.Input
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Common RGB color hex codes for JoyCon coloring.
|
|
||||||
/// </summary>
|
|
||||||
public enum JoyConColor //Thanks to CTCaer
|
|
||||||
{
|
|
||||||
Body_Grey = 0x828282,
|
|
||||||
Body_Neon_Blue = 0x0AB9E6,
|
|
||||||
Body_Neon_Red = 0xFF3C28,
|
|
||||||
Body_Neon_Yellow = 0xE6FF00,
|
|
||||||
Body_Neon_Pink = 0xFF3278,
|
|
||||||
Body_Neon_Green = 0x1EDC00,
|
|
||||||
Body_Red = 0xE10F00,
|
|
||||||
|
|
||||||
Buttons_Grey = 0x0F0F0F,
|
|
||||||
Buttons_Neon_Blue = 0x001E1E,
|
|
||||||
Buttons_Neon_Red = 0x1E0A0A,
|
|
||||||
Buttons_Neon_Yellow = 0x142800,
|
|
||||||
Buttons_Neon_Pink = 0x28001E,
|
|
||||||
Buttons_Neon_Green = 0x002800,
|
|
||||||
Buttons_Red = 0x280A0A
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct JoyConLeft
|
public struct JoyConLeft
|
||||||
{
|
{
|
||||||
public int StickUp;
|
public int StickUp;
|
||||||
|
|
23
Ryujinx.Core/Hid/JoyConColor.cs
Normal file
23
Ryujinx.Core/Hid/JoyConColor.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
namespace Ryujinx.Core.Input
|
||||||
|
{
|
||||||
|
public enum JoyConColor //Thanks to CTCaer
|
||||||
|
{
|
||||||
|
Black = 0,
|
||||||
|
|
||||||
|
Body_Grey = 0x828282,
|
||||||
|
Body_Neon_Blue = 0x0AB9E6,
|
||||||
|
Body_Neon_Red = 0xFF3C28,
|
||||||
|
Body_Neon_Yellow = 0xE6FF00,
|
||||||
|
Body_Neon_Pink = 0xFF3278,
|
||||||
|
Body_Neon_Green = 0x1EDC00,
|
||||||
|
Body_Red = 0xE10F00,
|
||||||
|
|
||||||
|
Buttons_Grey = 0x0F0F0F,
|
||||||
|
Buttons_Neon_Blue = 0x001E1E,
|
||||||
|
Buttons_Neon_Red = 0x1E0A0A,
|
||||||
|
Buttons_Neon_Yellow = 0x142800,
|
||||||
|
Buttons_Neon_Pink = 0x28001E,
|
||||||
|
Buttons_Neon_Green = 0x002800,
|
||||||
|
Buttons_Red = 0x280A0A
|
||||||
|
}
|
||||||
|
}
|
|
@ -96,7 +96,7 @@ namespace Ryujinx.Core.Loaders
|
||||||
MemoryType Type,
|
MemoryType Type,
|
||||||
AMemoryPerm Perm)
|
AMemoryPerm Perm)
|
||||||
{
|
{
|
||||||
Memory.Manager.MapPhys(Position, Data.Count, (int)Type, AMemoryPerm.Write);
|
Memory.Manager.Map(Position, Data.Count, (int)Type, AMemoryPerm.Write);
|
||||||
|
|
||||||
for (int Index = 0; Index < Data.Count; Index++)
|
for (int Index = 0; Index < Data.Count; Index++)
|
||||||
{
|
{
|
||||||
|
@ -108,7 +108,7 @@ namespace Ryujinx.Core.Loaders
|
||||||
|
|
||||||
private void MapBss(long Position, long Size)
|
private void MapBss(long Position, long Size)
|
||||||
{
|
{
|
||||||
Memory.Manager.MapPhys(Position, Size, (int)MemoryType.Normal, AMemoryPerm.RW);
|
Memory.Manager.Map(Position, Size, (int)MemoryType.Normal, AMemoryPerm.RW);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ElfRel GetRelocation(long Position)
|
private ElfRel GetRelocation(long Position)
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
||||||
public EventHandler<EventArgs> MemoryMapped;
|
public EventHandler<EventArgs> MemoryMapped;
|
||||||
public EventHandler<EventArgs> MemoryUnmapped;
|
public EventHandler<EventArgs> MemoryUnmapped;
|
||||||
|
|
||||||
public HSharedMem(long PhysPos)
|
public HSharedMem()
|
||||||
{
|
{
|
||||||
Positions = new List<long>();
|
Positions = new List<long>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
//http://switchbrew.org/index.php?title=Homebrew_ABI
|
//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)
|
||||||
{
|
{
|
||||||
Memory.Manager.MapPhys(Position, AMemoryMgr.PageSize, (int)MemoryType.Normal, AMemoryPerm.RW);
|
Memory.Manager.Map(Position, AMemoryMgr.PageSize, (int)MemoryType.Normal, AMemoryPerm.RW);
|
||||||
|
|
||||||
//MainThreadHandle
|
//MainThreadHandle
|
||||||
WriteConfigEntry(Memory, ref Position, 1, 0, MainThreadHandle);
|
WriteConfigEntry(Memory, ref Position, 1, 0, MainThreadHandle);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using ChocolArm64.Memory;
|
|
||||||
using Ryujinx.Core.Loaders.Executables;
|
using Ryujinx.Core.Loaders.Executables;
|
||||||
using Ryujinx.Core.OsHle.Handles;
|
using Ryujinx.Core.OsHle.Handles;
|
||||||
using Ryujinx.Core.OsHle.Utilities;
|
using Ryujinx.Core.OsHle.Utilities;
|
||||||
|
@ -16,9 +15,6 @@ namespace Ryujinx.Core.OsHle
|
||||||
internal int HidHandle { get; private set; }
|
internal int HidHandle { get; private set; }
|
||||||
internal int FontHandle { get; private set; }
|
internal int FontHandle { get; private set; }
|
||||||
|
|
||||||
public long HidOffset { get; private set; }
|
|
||||||
public long FontOffset { get; private set; }
|
|
||||||
|
|
||||||
internal IdPool IdGen { get; private set; }
|
internal IdPool IdGen { get; private set; }
|
||||||
internal IdPool NvMapIds { get; private set; }
|
internal IdPool NvMapIds { get; private set; }
|
||||||
|
|
||||||
|
@ -33,8 +29,6 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
private HSharedMem HidSharedMem;
|
private HSharedMem HidSharedMem;
|
||||||
|
|
||||||
private AMemoryAlloc Allocator;
|
|
||||||
|
|
||||||
private Switch Ns;
|
private Switch Ns;
|
||||||
|
|
||||||
public Horizon(Switch Ns)
|
public Horizon(Switch Ns)
|
||||||
|
@ -53,18 +47,13 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
Processes = new ConcurrentDictionary<int, Process>();
|
Processes = new ConcurrentDictionary<int, Process>();
|
||||||
|
|
||||||
Allocator = new AMemoryAlloc();
|
HidSharedMem = new HSharedMem();
|
||||||
|
|
||||||
HidOffset = Allocator.Alloc(HidSize);
|
|
||||||
FontOffset = Allocator.Alloc(FontSize);
|
|
||||||
|
|
||||||
HidSharedMem = new HSharedMem(HidOffset);
|
|
||||||
|
|
||||||
HidSharedMem.MemoryMapped += HidInit;
|
HidSharedMem.MemoryMapped += HidInit;
|
||||||
|
|
||||||
HidHandle = Handles.GenerateId(HidSharedMem);
|
HidHandle = Handles.GenerateId(HidSharedMem);
|
||||||
|
|
||||||
FontHandle = Handles.GenerateId(new HSharedMem(FontOffset));
|
FontHandle = Handles.GenerateId(new HSharedMem());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadCart(string ExeFsDir, string RomFsFile = null)
|
public void LoadCart(string ExeFsDir, string RomFsFile = null)
|
||||||
|
@ -76,7 +65,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
int ProcessId = IdGen.GenerateId();
|
int ProcessId = IdGen.GenerateId();
|
||||||
|
|
||||||
Process MainProcess = new Process(Ns, Allocator, ProcessId);
|
Process MainProcess = new Process(Ns, ProcessId);
|
||||||
|
|
||||||
void LoadNso(string FileName)
|
void LoadNso(string FileName)
|
||||||
{
|
{
|
||||||
|
@ -106,7 +95,6 @@ namespace Ryujinx.Core.OsHle
|
||||||
LoadNso("subsdk*");
|
LoadNso("subsdk*");
|
||||||
LoadNso("sdk");
|
LoadNso("sdk");
|
||||||
|
|
||||||
MainProcess.InitializeHeap();
|
|
||||||
MainProcess.Run();
|
MainProcess.Run();
|
||||||
|
|
||||||
Processes.TryAdd(ProcessId, MainProcess);
|
Processes.TryAdd(ProcessId, MainProcess);
|
||||||
|
@ -118,7 +106,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
int ProcessId = IdGen.GenerateId();
|
int ProcessId = IdGen.GenerateId();
|
||||||
|
|
||||||
Process MainProcess = new Process(Ns, Allocator, ProcessId);
|
Process MainProcess = new Process(Ns, ProcessId);
|
||||||
|
|
||||||
using (FileStream Input = new FileStream(FileName, FileMode.Open))
|
using (FileStream Input = new FileStream(FileName, FileMode.Open))
|
||||||
{
|
{
|
||||||
|
@ -128,7 +116,6 @@ namespace Ryujinx.Core.OsHle
|
||||||
}
|
}
|
||||||
|
|
||||||
MainProcess.SetEmptyArgs();
|
MainProcess.SetEmptyArgs();
|
||||||
MainProcess.InitializeHeap();
|
|
||||||
MainProcess.Run(IsNro);
|
MainProcess.Run(IsNro);
|
||||||
|
|
||||||
Processes.TryAdd(ProcessId, MainProcess);
|
Processes.TryAdd(ProcessId, MainProcess);
|
||||||
|
@ -186,7 +173,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
if (SharedMem.TryGetLastVirtualPosition(out long Position))
|
if (SharedMem.TryGetLastVirtualPosition(out long Position))
|
||||||
{
|
{
|
||||||
Logging.Info($"HID shared memory successfully mapped to {Position:x16}!");
|
Logging.Info($"HID shared memory successfully mapped to 0x{Position:x16}!");
|
||||||
|
|
||||||
Ns.Hid.Init(Position);
|
Ns.Hid.Init(Position);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
using ChocolArm64.Memory;
|
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle
|
|
||||||
{
|
|
||||||
struct MemoryInfo
|
|
||||||
{
|
|
||||||
public long BaseAddress;
|
|
||||||
public long Size;
|
|
||||||
public int MemType;
|
|
||||||
public int MemAttr;
|
|
||||||
public int MemPerm;
|
|
||||||
public int IpcRefCount;
|
|
||||||
public int DeviceRefCount;
|
|
||||||
public int Padding; //SBZ
|
|
||||||
|
|
||||||
public MemoryInfo(AMemoryMapInfo MapInfo)
|
|
||||||
{
|
|
||||||
BaseAddress = MapInfo.Position;
|
|
||||||
Size = MapInfo.Size;
|
|
||||||
MemType = MapInfo.Type;
|
|
||||||
MemAttr = MapInfo.Attr;
|
|
||||||
MemPerm = (int)MapInfo.Perm;
|
|
||||||
IpcRefCount = 0;
|
|
||||||
DeviceRefCount = 0;
|
|
||||||
Padding = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +1,28 @@
|
||||||
|
using ChocolArm64.Memory;
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle
|
namespace Ryujinx.Core.OsHle
|
||||||
{
|
{
|
||||||
static class MemoryRegions
|
static class MemoryRegions
|
||||||
{
|
{
|
||||||
public const long MapRegionAddress = 0x80000000;
|
public const long AddrSpaceStart = 0x08000000;
|
||||||
public const long MapRegionSize = 0x40000000;
|
|
||||||
|
public const long MapRegionAddress = 0x10000000;
|
||||||
|
public const long MapRegionSize = 0x10000000;
|
||||||
|
|
||||||
|
public const long MainStackSize = 0x100000;
|
||||||
|
|
||||||
|
public const long MainStackAddress = AMemoryMgr.AddrSize - MainStackSize;
|
||||||
|
|
||||||
|
public const long TlsPagesSize = 0x4000;
|
||||||
|
|
||||||
|
public const long TlsPagesAddress = MainStackAddress - TlsPagesSize;
|
||||||
|
|
||||||
public const long HeapRegionAddress = MapRegionAddress + MapRegionSize;
|
public const long HeapRegionAddress = MapRegionAddress + MapRegionSize;
|
||||||
public const long HeapRegionSize = 0x40000000;
|
|
||||||
|
public const long TotalMemoryUsed = HeapRegionAddress + TlsPagesSize + MainStackSize;
|
||||||
|
|
||||||
|
public const long TotalMemoryAvailable = AMemoryMgr.RamSize - AddrSpaceStart;
|
||||||
|
|
||||||
|
public const long AddrSpaceSize = AMemoryMgr.AddrSize - AddrSpaceStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,19 +15,15 @@ namespace Ryujinx.Core.OsHle
|
||||||
{
|
{
|
||||||
public class Process : IDisposable
|
public class Process : IDisposable
|
||||||
{
|
{
|
||||||
private const int MaxStackSize = 8 * 1024 * 1024;
|
|
||||||
|
|
||||||
private const int TlsSize = 0x200;
|
private const int TlsSize = 0x200;
|
||||||
private const int TotalTlsSlots = 32;
|
private const int TotalTlsSlots = 32;
|
||||||
private const int TlsTotalSize = TotalTlsSlots * TlsSize;
|
|
||||||
private const long TlsPageAddr = (AMemoryMgr.AddrSize - TlsTotalSize) & ~AMemoryMgr.PageMask;
|
|
||||||
|
|
||||||
private Switch Ns;
|
private Switch Ns;
|
||||||
|
|
||||||
private ATranslator Translator;
|
|
||||||
|
|
||||||
public int ProcessId { get; private set; }
|
public int ProcessId { get; private set; }
|
||||||
|
|
||||||
|
private ATranslator Translator;
|
||||||
|
|
||||||
public AMemory Memory { get; private set; }
|
public AMemory Memory { get; private set; }
|
||||||
|
|
||||||
public KProcessScheduler Scheduler { get; private set; }
|
public KProcessScheduler Scheduler { get; private set; }
|
||||||
|
@ -44,12 +40,12 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
private long ImageBase;
|
private long ImageBase;
|
||||||
|
|
||||||
public Process(Switch Ns, AMemoryAlloc Allocator, int ProcessId)
|
public Process(Switch Ns, int ProcessId)
|
||||||
{
|
{
|
||||||
this.Ns = Ns;
|
this.Ns = Ns;
|
||||||
this.ProcessId = ProcessId;
|
this.ProcessId = ProcessId;
|
||||||
|
|
||||||
Memory = new AMemory(Ns.Ram, Allocator);
|
Memory = new AMemory(Ns.Ram);
|
||||||
|
|
||||||
Scheduler = new KProcessScheduler();
|
Scheduler = new KProcessScheduler();
|
||||||
|
|
||||||
|
@ -61,13 +57,12 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
Executables = new List<Executable>();
|
Executables = new List<Executable>();
|
||||||
|
|
||||||
ImageBase = 0x8000000;
|
ImageBase = MemoryRegions.AddrSpaceStart;
|
||||||
|
|
||||||
Memory.Manager.MapPhys(
|
MapRWMemRegion(
|
||||||
TlsPageAddr,
|
MemoryRegions.TlsPagesAddress,
|
||||||
TlsTotalSize,
|
MemoryRegions.TlsPagesSize,
|
||||||
(int)MemoryType.ThreadLocal,
|
MemoryType.ThreadLocal);
|
||||||
AMemoryPerm.RW);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadProgram(IExecutable Program)
|
public void LoadProgram(IExecutable Program)
|
||||||
|
@ -86,11 +81,6 @@ namespace Ryujinx.Core.OsHle
|
||||||
ImageBase += AMemoryMgr.PageSize;
|
ImageBase += AMemoryMgr.PageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitializeHeap()
|
|
||||||
{
|
|
||||||
Memory.Manager.SetHeapAddr(MemoryRegions.HeapRegionAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Run(bool UseHbAbi = false)
|
public bool Run(bool UseHbAbi = false)
|
||||||
{
|
{
|
||||||
if (Executables.Count == 0)
|
if (Executables.Count == 0)
|
||||||
|
@ -98,11 +88,14 @@ namespace Ryujinx.Core.OsHle
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
long StackBot = TlsPageAddr - MaxStackSize;
|
MapRWMemRegion(
|
||||||
|
MemoryRegions.MainStackAddress,
|
||||||
|
MemoryRegions.MainStackSize,
|
||||||
|
MemoryType.Normal);
|
||||||
|
|
||||||
|
long StackTop = MemoryRegions.MainStackAddress + MemoryRegions.MainStackSize;
|
||||||
|
|
||||||
Memory.Manager.MapPhys(StackBot, MaxStackSize, (int)MemoryType.Normal, AMemoryPerm.RW);
|
int Handle = MakeThread(Executables[0].ImageBase, StackTop, 0, 0, 0);
|
||||||
|
|
||||||
int Handle = MakeThread(Executables[0].ImageBase, TlsPageAddr, 0, 0, 0);
|
|
||||||
|
|
||||||
if (Handle == -1)
|
if (Handle == -1)
|
||||||
{
|
{
|
||||||
|
@ -113,7 +106,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
if (UseHbAbi)
|
if (UseHbAbi)
|
||||||
{
|
{
|
||||||
long HbAbiDataPosition = (Executables[0].ImageEnd + 0xfff) & ~0xfff;
|
long HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd);
|
||||||
|
|
||||||
Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle);
|
Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle);
|
||||||
|
|
||||||
|
@ -126,6 +119,11 @@ namespace Ryujinx.Core.OsHle
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MapRWMemRegion(long Position, long Size, MemoryType Type)
|
||||||
|
{
|
||||||
|
Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW);
|
||||||
|
}
|
||||||
|
|
||||||
public void StopAllThreads()
|
public void StopAllThreads()
|
||||||
{
|
{
|
||||||
if (MainThread != null)
|
if (MainThread != null)
|
||||||
|
@ -188,12 +186,14 @@ namespace Ryujinx.Core.OsHle
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long Tpidr = MemoryRegions.TlsPagesAddress + TlsSlot * TlsSize;
|
||||||
|
|
||||||
Thread.ThreadState.Break += BreakHandler;
|
Thread.ThreadState.Break += BreakHandler;
|
||||||
Thread.ThreadState.SvcCall += SvcHandler.SvcCall;
|
Thread.ThreadState.SvcCall += SvcHandler.SvcCall;
|
||||||
Thread.ThreadState.Undefined += UndefinedHandler;
|
Thread.ThreadState.Undefined += UndefinedHandler;
|
||||||
Thread.ThreadState.ProcessId = ProcessId;
|
Thread.ThreadState.ProcessId = ProcessId;
|
||||||
Thread.ThreadState.ThreadId = Ns.Os.IdGen.GenerateId();
|
Thread.ThreadState.ThreadId = Ns.Os.IdGen.GenerateId();
|
||||||
Thread.ThreadState.Tpidr = TlsPageAddr + TlsSlot * TlsSize;
|
Thread.ThreadState.Tpidr = Tpidr;
|
||||||
Thread.ThreadState.X0 = (ulong)ArgsPtr;
|
Thread.ThreadState.X0 = (ulong)ArgsPtr;
|
||||||
Thread.ThreadState.X1 = (ulong)Handle;
|
Thread.ThreadState.X1 = (ulong)Handle;
|
||||||
Thread.ThreadState.X31 = (ulong)StackTop;
|
Thread.ThreadState.X31 = (ulong)StackTop;
|
||||||
|
@ -239,7 +239,29 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
private void CpuTraceHandler(object sender, ACpuTraceEventArgs e)
|
private void CpuTraceHandler(object sender, ACpuTraceEventArgs e)
|
||||||
{
|
{
|
||||||
Logging.Trace($"Executing at 0x{e.Position:x16} {e.SubName}");
|
string NsoName = string.Empty;
|
||||||
|
|
||||||
|
for (int Index = Executables.Count - 1; Index >= 0; Index--)
|
||||||
|
{
|
||||||
|
if (e.Position >= Executables[Index].ImageBase)
|
||||||
|
{
|
||||||
|
NsoName = $"{(e.Position - Executables[Index].ImageBase):x16}";
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Trace($"Executing at 0x{e.Position:x16} {e.SubName} {NsoName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnableCpuTracing()
|
||||||
|
{
|
||||||
|
Translator.EnableCpuTrace = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisableCpuTracing()
|
||||||
|
{
|
||||||
|
Translator.EnableCpuTrace = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetFreeTlsSlot(AThread Thread)
|
private int GetFreeTlsSlot(AThread Thread)
|
||||||
|
@ -267,7 +289,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
private int GetTlsSlot(long Position)
|
private int GetTlsSlot(long Position)
|
||||||
{
|
{
|
||||||
return (int)((Position - TlsPageAddr) / TlsSize);
|
return (int)((Position - MemoryRegions.TlsPagesAddress) / TlsSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HThread GetThread(long Tpidr)
|
public HThread GetThread(long Tpidr)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.Core.OsHle.Handles;
|
using Ryujinx.Core.OsHle.Handles;
|
||||||
using Ryujinx.Core.OsHle.Ipc;
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
using OpenTK.Audio;
|
using OpenTK.Audio;
|
||||||
|
@ -9,7 +9,7 @@ using System.IO;
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||||
{
|
{
|
||||||
class IAudioOut : IIpcService
|
class IAudioOut : IIpcService, IDisposable
|
||||||
{
|
{
|
||||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||||
|
|
||||||
//IAudioOut
|
//IAudioOut
|
||||||
private AudioOutState State = AudioOutState.Stopped;
|
private AudioOutState State = AudioOutState.Stopped;
|
||||||
private Queue<long> KeysQueue = new Queue<long>();
|
private Queue<long> BufferIdQueue = new Queue<long>();
|
||||||
|
|
||||||
//OpenAL
|
//OpenAL
|
||||||
private bool OpenALInstalled = true;
|
private bool OpenALInstalled = true;
|
||||||
|
@ -71,7 +71,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||||
OpenALInstalled = false;
|
OpenALInstalled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OpenALInstalled) AL.Listener(ALListenerf.Gain, (float)8.0); //Add more gain to it
|
if (OpenALInstalled) AL.Listener(ALListenerf.Gain, 8.0f); //Add more gain to it
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -88,6 +88,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||||
|
|
||||||
AL.SourceStop(Source);
|
AL.SourceStop(Source);
|
||||||
AL.DeleteSource(Source);
|
AL.DeleteSource(Source);
|
||||||
|
AL.DeleteBuffers(1, ref Buffer);
|
||||||
}
|
}
|
||||||
State = AudioOutState.Stopped;
|
State = AudioOutState.Stopped;
|
||||||
}
|
}
|
||||||
|
@ -99,9 +100,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||||
{
|
{
|
||||||
long BufferId = Context.RequestData.ReadInt64();
|
long BufferId = Context.RequestData.ReadInt64();
|
||||||
|
|
||||||
KeysQueue.Enqueue(BufferId);
|
|
||||||
|
|
||||||
byte[] AudioOutBuffer = AMemoryHelper.ReadBytes(Context.Memory, Context.Request.SendBuff[0].Position, sizeof(long) * 5);
|
byte[] AudioOutBuffer = AMemoryHelper.ReadBytes(Context.Memory, Context.Request.SendBuff[0].Position, sizeof(long) * 5);
|
||||||
|
|
||||||
using (MemoryStream MS = new MemoryStream(AudioOutBuffer))
|
using (MemoryStream MS = new MemoryStream(AudioOutBuffer))
|
||||||
{
|
{
|
||||||
BinaryReader Reader = new BinaryReader(MS);
|
BinaryReader Reader = new BinaryReader(MS);
|
||||||
|
@ -111,18 +111,26 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||||
long SizeDataInSampleBuffer = Reader.ReadInt64();
|
long SizeDataInSampleBuffer = Reader.ReadInt64();
|
||||||
long OffsetDataInSampleBuffer = Reader.ReadInt64();
|
long OffsetDataInSampleBuffer = Reader.ReadInt64();
|
||||||
|
|
||||||
byte[] AudioSampleBuffer = AMemoryHelper.ReadBytes(Context.Memory, PointerSampleBuffer + OffsetDataInSampleBuffer, (int)SizeDataInSampleBuffer);
|
if (SizeDataInSampleBuffer > 0)
|
||||||
|
|
||||||
if (OpenALInstalled)
|
|
||||||
{
|
{
|
||||||
if (AudioCtx == null) //Needed to call the instance of AudioContext()
|
BufferIdQueue.Enqueue(BufferId);
|
||||||
return 0;
|
|
||||||
|
|
||||||
Buffer = AL.GenBuffer();
|
byte[] AudioSampleBuffer = AMemoryHelper.ReadBytes(Context.Memory, PointerSampleBuffer + OffsetDataInSampleBuffer, (int)SizeDataInSampleBuffer);
|
||||||
AL.BufferData(Buffer, ALFormat.Stereo16, AudioSampleBuffer, AudioSampleBuffer.Length, 48000);
|
|
||||||
|
|
||||||
Source = AL.GenSource();
|
if (OpenALInstalled)
|
||||||
AL.SourceQueueBuffer(Source, Buffer);
|
{
|
||||||
|
if (AudioCtx == null) //Needed to call the instance of AudioContext()
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
EnsureAudioFinalized();
|
||||||
|
|
||||||
|
Source = AL.GenSource();
|
||||||
|
Buffer = AL.GenBuffer();
|
||||||
|
|
||||||
|
AL.BufferData(Buffer, ALFormat.Stereo16, AudioSampleBuffer, AudioSampleBuffer.Length, 48000);
|
||||||
|
AL.SourceQueueBuffer(Source, Buffer);
|
||||||
|
AL.SourcePlay(Source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,25 +148,19 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||||
|
|
||||||
public long GetReleasedAudioOutBuffer(ServiceCtx Context)
|
public long GetReleasedAudioOutBuffer(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long TempKey = 0;
|
int ReleasedBuffersCount = 0;
|
||||||
|
|
||||||
if (KeysQueue.Count > 0) TempKey = KeysQueue.Dequeue();
|
for(int i = 0; i < BufferIdQueue.Count; i++)
|
||||||
|
|
||||||
AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position, BitConverter.GetBytes(TempKey));
|
|
||||||
|
|
||||||
int ReleasedBuffersCount = 1;
|
|
||||||
Context.ResponseData.Write(ReleasedBuffersCount);
|
|
||||||
|
|
||||||
if (OpenALInstalled)
|
|
||||||
{
|
{
|
||||||
if (AudioCtx == null) //Needed to call the instance of AudioContext()
|
long BufferId = BufferIdQueue.Dequeue();
|
||||||
return 0;
|
|
||||||
|
|
||||||
AL.SourcePlay(Source);
|
AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position + (8 * i), BitConverter.GetBytes(BufferId));
|
||||||
int[] FreeBuffers = AL.SourceUnqueueBuffers(Source, 1);
|
|
||||||
AL.DeleteBuffers(FreeBuffers);
|
ReleasedBuffersCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Context.ResponseData.Write(ReleasedBuffersCount);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,5 +178,33 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EnsureAudioFinalized()
|
||||||
|
{
|
||||||
|
if (Source != 0 ||
|
||||||
|
Buffer != 0)
|
||||||
|
{
|
||||||
|
AL.SourceStop(Source);
|
||||||
|
AL.SourceUnqueueBuffer(Buffer);
|
||||||
|
AL.DeleteSource(Source);
|
||||||
|
AL.DeleteBuffers(1, ref Buffer);
|
||||||
|
|
||||||
|
Source = 0;
|
||||||
|
Buffer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
EnsureAudioFinalized();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
96
Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs
Normal file
96
Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.OsHle.IpcServices.Bsd
|
||||||
|
{
|
||||||
|
class ServiceBsd : IIpcService
|
||||||
|
{
|
||||||
|
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||||
|
|
||||||
|
public ServiceBsd()
|
||||||
|
{
|
||||||
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
|
{
|
||||||
|
{ 0, Initialize },
|
||||||
|
{ 1, StartMonitoring },
|
||||||
|
{ 2, Socket },
|
||||||
|
{ 10, Send },
|
||||||
|
{ 14, Connect }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//Initialize(u32, u32, u32, u32, u32, u32, u32, u32, u64 pid, u64 transferMemorySize, pid, KObject) -> u32 bsd_errno
|
||||||
|
public long Initialize(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
typedef struct {
|
||||||
|
u32 version; // Observed 1 on 2.0 LibAppletWeb, 2 on 3.0.
|
||||||
|
|
||||||
|
u32 tcp_tx_buf_size; // Size of the TCP transfer (send) buffer (initial or fixed).
|
||||||
|
u32 tcp_rx_buf_size; // Size of the TCP recieve buffer (initial or fixed).
|
||||||
|
u32 tcp_tx_buf_max_size; // Maximum size of the TCP transfer (send) buffer. If it is 0, the size of the buffer is fixed to its initial value.
|
||||||
|
u32 tcp_rx_buf_max_size; // Maximum size of the TCP receive buffer. If it is 0, the size of the buffer is fixed to its initial value.
|
||||||
|
|
||||||
|
u32 udp_tx_buf_size; // Size of the UDP transfer (send) buffer (typically 0x2400 bytes).
|
||||||
|
u32 udp_rx_buf_size; // Size of the UDP receive buffer (typically 0xA500 bytes).
|
||||||
|
|
||||||
|
u32 sb_efficiency; // Number of buffers for each socket (standard values range from 1 to 8).
|
||||||
|
} BsdBufferConfig;
|
||||||
|
*/
|
||||||
|
|
||||||
|
long Pid = Context.RequestData.ReadInt64();
|
||||||
|
long TransferMemorySize = Context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
// Two other args are unknown!
|
||||||
|
|
||||||
|
Context.ResponseData.Write(0);
|
||||||
|
|
||||||
|
//Todo: Stub
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//StartMonitoring(u64, pid)
|
||||||
|
public long StartMonitoring(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
//Todo: Stub
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Socket(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno)
|
||||||
|
public long Socket(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
Context.ResponseData.Write(0);
|
||||||
|
Context.ResponseData.Write(0);
|
||||||
|
|
||||||
|
//Todo: Stub
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Connect(u32 socket, buffer<sockaddr, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
|
||||||
|
public long Connect(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
Context.ResponseData.Write(0);
|
||||||
|
Context.ResponseData.Write(0);
|
||||||
|
|
||||||
|
//Todo: Stub
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send(u32 socket, u32 flags, buffer<i8, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
|
||||||
|
public long Send(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
Context.ResponseData.Write(0);
|
||||||
|
Context.ResponseData.Write(0);
|
||||||
|
|
||||||
|
//Todo: Stub
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
using ChocolArm64.Memory;
|
|
||||||
using Ryujinx.Core.OsHle.Ipc;
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
using static Ryujinx.Core.OsHle.IpcServices.ErrorCode;
|
using static Ryujinx.Core.OsHle.IpcServices.ErrorCode;
|
||||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||||
|
@ -49,7 +49,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
{
|
{
|
||||||
long Position = Context.Request.PtrBuff[0].Position;
|
long Position = Context.Request.PtrBuff[0].Position;
|
||||||
|
|
||||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
|
string Name = ReadUtf8String(Context);
|
||||||
|
|
||||||
long Mode = Context.RequestData.ReadInt64();
|
long Mode = Context.RequestData.ReadInt64();
|
||||||
int Size = Context.RequestData.ReadInt32();
|
int Size = Context.RequestData.ReadInt32();
|
||||||
|
@ -83,7 +83,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
{
|
{
|
||||||
long Position = Context.Request.PtrBuff[0].Position;
|
long Position = Context.Request.PtrBuff[0].Position;
|
||||||
|
|
||||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
|
string Name = ReadUtf8String(Context);
|
||||||
|
|
||||||
string FileName = Context.Ns.VFs.GetFullPath(Path, Name);
|
string FileName = Context.Ns.VFs.GetFullPath(Path, Name);
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
{
|
{
|
||||||
long Position = Context.Request.PtrBuff[0].Position;
|
long Position = Context.Request.PtrBuff[0].Position;
|
||||||
|
|
||||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
|
string Name = ReadUtf8String(Context);
|
||||||
|
|
||||||
string DirName = Context.Ns.VFs.GetFullPath(Path, Name);
|
string DirName = Context.Ns.VFs.GetFullPath(Path, Name);
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
{
|
{
|
||||||
long Position = Context.Request.PtrBuff[0].Position;
|
long Position = Context.Request.PtrBuff[0].Position;
|
||||||
|
|
||||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
|
string Name = ReadUtf8String(Context);
|
||||||
|
|
||||||
string DirName = Context.Ns.VFs.GetFullPath(Path, Name);
|
string DirName = Context.Ns.VFs.GetFullPath(Path, Name);
|
||||||
|
|
||||||
|
@ -165,11 +165,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
|
|
||||||
public long RenameFile(ServiceCtx Context)
|
public long RenameFile(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long OldPosition = Context.Request.PtrBuff[0].Position;
|
string OldName = ReadUtf8String(Context, 0);
|
||||||
long NewPosition = Context.Request.PtrBuff[0].Position;
|
string NewName = ReadUtf8String(Context, 1);
|
||||||
|
|
||||||
string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition);
|
|
||||||
string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition);
|
|
||||||
|
|
||||||
string OldFileName = Context.Ns.VFs.GetFullPath(Path, OldName);
|
string OldFileName = Context.Ns.VFs.GetFullPath(Path, OldName);
|
||||||
string NewFileName = Context.Ns.VFs.GetFullPath(Path, NewName);
|
string NewFileName = Context.Ns.VFs.GetFullPath(Path, NewName);
|
||||||
|
@ -196,11 +193,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
|
|
||||||
public long RenameDirectory(ServiceCtx Context)
|
public long RenameDirectory(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long OldPosition = Context.Request.PtrBuff[0].Position;
|
string OldName = ReadUtf8String(Context, 0);
|
||||||
long NewPosition = Context.Request.PtrBuff[0].Position;
|
string NewName = ReadUtf8String(Context, 1);
|
||||||
|
|
||||||
string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition);
|
|
||||||
string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition);
|
|
||||||
|
|
||||||
string OldDirName = Context.Ns.VFs.GetFullPath(Path, OldName);
|
string OldDirName = Context.Ns.VFs.GetFullPath(Path, OldName);
|
||||||
string NewDirName = Context.Ns.VFs.GetFullPath(Path, NewName);
|
string NewDirName = Context.Ns.VFs.GetFullPath(Path, NewName);
|
||||||
|
@ -229,7 +223,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
{
|
{
|
||||||
long Position = Context.Request.PtrBuff[0].Position;
|
long Position = Context.Request.PtrBuff[0].Position;
|
||||||
|
|
||||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
|
string Name = ReadUtf8String(Context);
|
||||||
|
|
||||||
string FileName = Context.Ns.VFs.GetFullPath(Path, Name);
|
string FileName = Context.Ns.VFs.GetFullPath(Path, Name);
|
||||||
|
|
||||||
|
@ -257,7 +251,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
|
|
||||||
int FilterFlags = Context.RequestData.ReadInt32();
|
int FilterFlags = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
|
string Name = ReadUtf8String(Context);
|
||||||
|
|
||||||
string FileName = Context.Ns.VFs.GetFullPath(Path, Name);
|
string FileName = Context.Ns.VFs.GetFullPath(Path, Name);
|
||||||
|
|
||||||
|
@ -293,7 +287,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
|
|
||||||
int FilterFlags = Context.RequestData.ReadInt32();
|
int FilterFlags = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
|
string Name = ReadUtf8String(Context);
|
||||||
|
|
||||||
string DirName = Context.Ns.VFs.GetFullPath(Path, Name);
|
string DirName = Context.Ns.VFs.GetFullPath(Path, Name);
|
||||||
|
|
||||||
|
@ -330,7 +324,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
{
|
{
|
||||||
long Position = Context.Request.PtrBuff[0].Position;
|
long Position = Context.Request.PtrBuff[0].Position;
|
||||||
|
|
||||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
|
string Name = ReadUtf8String(Context);
|
||||||
|
|
||||||
Context.ResponseData.Write(Context.Ns.VFs.GetDrive().AvailableFreeSpace);
|
Context.ResponseData.Write(Context.Ns.VFs.GetDrive().AvailableFreeSpace);
|
||||||
|
|
||||||
|
@ -341,7 +335,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
{
|
{
|
||||||
long Position = Context.Request.PtrBuff[0].Position;
|
long Position = Context.Request.PtrBuff[0].Position;
|
||||||
|
|
||||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
|
string Name = ReadUtf8String(Context);
|
||||||
|
|
||||||
Context.ResponseData.Write(Context.Ns.VFs.GetDrive().TotalSize);
|
Context.ResponseData.Write(Context.Ns.VFs.GetDrive().TotalSize);
|
||||||
|
|
||||||
|
@ -379,5 +373,28 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||||
OpenPaths.Remove(DirInterface.HostPath);
|
OpenPaths.Remove(DirInterface.HostPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string ReadUtf8String(ServiceCtx Context, int Index = 0)
|
||||||
|
{
|
||||||
|
long Position = Context.Request.PtrBuff[Index].Position;
|
||||||
|
long Size = Context.Request.PtrBuff[Index].Size;
|
||||||
|
|
||||||
|
using (MemoryStream MS = new MemoryStream())
|
||||||
|
{
|
||||||
|
while (Size-- > 0)
|
||||||
|
{
|
||||||
|
byte Value = Context.Memory.ReadByte(Position++);
|
||||||
|
|
||||||
|
if (Value == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
MS.WriteByte(Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Encoding.UTF8.GetString(MS.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid
|
||||||
{ 121, GetNpadJoyHoldType },
|
{ 121, GetNpadJoyHoldType },
|
||||||
{ 200, GetVibrationDeviceInfo },
|
{ 200, GetVibrationDeviceInfo },
|
||||||
{ 203, CreateActiveVibrationDeviceList },
|
{ 203, CreateActiveVibrationDeviceList },
|
||||||
|
{ 206, SendVibrationValues }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,5 +105,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long SendVibrationValues(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
34
Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs
Normal file
34
Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.OsHle.IpcServices.Nifm
|
||||||
|
{
|
||||||
|
class IGeneralService : IIpcService
|
||||||
|
{
|
||||||
|
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||||
|
|
||||||
|
public IGeneralService()
|
||||||
|
{
|
||||||
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
|
{
|
||||||
|
{ 4, CreateRequest }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//CreateRequest(i32)
|
||||||
|
public long CreateRequest(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
int Unknown = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
|
MakeObject(Context, new IRequest());
|
||||||
|
|
||||||
|
//Todo: Stub
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs
Normal file
49
Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.OsHle.IpcServices.Nifm
|
||||||
|
{
|
||||||
|
class IRequest : IIpcService
|
||||||
|
{
|
||||||
|
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||||
|
|
||||||
|
public IRequest()
|
||||||
|
{
|
||||||
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
|
{
|
||||||
|
{ 0, GetRequestState },
|
||||||
|
{ 1, GetResult },
|
||||||
|
{ 2, GetSystemEventReadableHandles }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// -> i32
|
||||||
|
public long GetRequestState(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
Context.ResponseData.Write(0);
|
||||||
|
|
||||||
|
//Todo: Stub
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long GetResult(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
//Todo: Stub
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//GetSystemEventReadableHandles() -> (KObject, KObject)
|
||||||
|
public long GetSystemEventReadableHandles(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe);
|
||||||
|
|
||||||
|
//Todo: Stub
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs
Normal file
29
Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.OsHle.IpcServices.Nifm
|
||||||
|
{
|
||||||
|
class ServiceNifm : IIpcService
|
||||||
|
{
|
||||||
|
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||||
|
|
||||||
|
public ServiceNifm()
|
||||||
|
{
|
||||||
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
|
{
|
||||||
|
{ 4, CreateGeneralServiceOld }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public long CreateGeneralServiceOld(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
MakeObject(Context, new IGeneralService());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -532,6 +532,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
|
|
||||||
Context.Memory.WriteInt32(Position + 4, Handle);
|
Context.Memory.WriteInt32(Position + 4, Handle);
|
||||||
|
|
||||||
|
Logging.Info($"NvMap {Id} created with size {Size:x8}!");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,8 +582,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
NvMap.Kind = Kind;
|
NvMap.Kind = Kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.Debug($"NvMapIocAlloc at {NvMap.Address:x16}");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,16 +2,20 @@ using Ryujinx.Core.OsHle.IpcServices.Acc;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Am;
|
using Ryujinx.Core.OsHle.IpcServices.Am;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Apm;
|
using Ryujinx.Core.OsHle.IpcServices.Apm;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Aud;
|
using Ryujinx.Core.OsHle.IpcServices.Aud;
|
||||||
|
using Ryujinx.Core.OsHle.IpcServices.Bsd;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Friend;
|
using Ryujinx.Core.OsHle.IpcServices.Friend;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.FspSrv;
|
using Ryujinx.Core.OsHle.IpcServices.FspSrv;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Hid;
|
using Ryujinx.Core.OsHle.IpcServices.Hid;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Lm;
|
using Ryujinx.Core.OsHle.IpcServices.Lm;
|
||||||
|
using Ryujinx.Core.OsHle.IpcServices.Nifm;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Ns;
|
using Ryujinx.Core.OsHle.IpcServices.Ns;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.NvServices;
|
using Ryujinx.Core.OsHle.IpcServices.NvServices;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Pctl;
|
using Ryujinx.Core.OsHle.IpcServices.Pctl;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Pl;
|
using Ryujinx.Core.OsHle.IpcServices.Pl;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Set;
|
using Ryujinx.Core.OsHle.IpcServices.Set;
|
||||||
|
using Ryujinx.Core.OsHle.IpcServices.Sfdnsres;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Sm;
|
using Ryujinx.Core.OsHle.IpcServices.Sm;
|
||||||
|
using Ryujinx.Core.OsHle.IpcServices.Ssl;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Time;
|
using Ryujinx.Core.OsHle.IpcServices.Time;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Vi;
|
using Ryujinx.Core.OsHle.IpcServices.Vi;
|
||||||
using System;
|
using System;
|
||||||
|
@ -31,16 +35,21 @@ namespace Ryujinx.Core.OsHle.IpcServices
|
||||||
case "appletOE": return new ServiceAppletOE();
|
case "appletOE": return new ServiceAppletOE();
|
||||||
case "audout:u": return new ServiceAudOut();
|
case "audout:u": return new ServiceAudOut();
|
||||||
case "audren:u": return new ServiceAudRen();
|
case "audren:u": return new ServiceAudRen();
|
||||||
|
case "bsd:u": return new ServiceBsd();
|
||||||
case "friend:a": return new ServiceFriend();
|
case "friend:a": return new ServiceFriend();
|
||||||
case "fsp-srv": return new ServiceFspSrv();
|
case "fsp-srv": return new ServiceFspSrv();
|
||||||
case "hid": return new ServiceHid();
|
case "hid": return new ServiceHid();
|
||||||
case "lm": return new ServiceLm();
|
case "lm": return new ServiceLm();
|
||||||
|
case "nifm:u": return new ServiceNifm();
|
||||||
case "nvdrv": return new ServiceNvDrv();
|
case "nvdrv": return new ServiceNvDrv();
|
||||||
case "nvdrv:a": return new ServiceNvDrv();
|
case "nvdrv:a": return new ServiceNvDrv();
|
||||||
case "pctl:a": return new ServicePctl();
|
case "pctl:a": return new ServicePctl();
|
||||||
case "pl:u": return new ServicePl();
|
case "pl:u": return new ServicePl();
|
||||||
case "set": return new ServiceSet();
|
case "set": return new ServiceSet();
|
||||||
|
case "set:sys": return new ServiceSetSys();
|
||||||
|
case "sfdnsres": return new ServiceSfdnsres();
|
||||||
case "sm:": return new ServiceSm();
|
case "sm:": return new ServiceSm();
|
||||||
|
case "ssl": return new ServiceSsl();
|
||||||
case "time:s": return new ServiceTime();
|
case "time:s": return new ServiceTime();
|
||||||
case "time:u": return new ServiceTime();
|
case "time:u": return new ServiceTime();
|
||||||
case "vi:m": return new ServiceVi();
|
case "vi:m": return new ServiceVi();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.Core.OsHle.Ipc;
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle.IpcServices.Set
|
namespace Ryujinx.Core.OsHle.IpcServices.Set
|
||||||
|
@ -30,12 +31,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Set
|
||||||
short Size = Context.Request.RecvListBuff[0].Size;
|
short Size = Context.Request.RecvListBuff[0].Size;
|
||||||
|
|
||||||
//This should return an array of ints with values matching the LanguageCode enum.
|
//This should return an array of ints with values matching the LanguageCode enum.
|
||||||
byte[] Data = new byte[Size];
|
foreach (long value in new long[] { 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L })
|
||||||
|
{
|
||||||
Data[0] = 0;
|
AMemoryHelper.WriteBytes(Context.Memory, Position += 8, BitConverter.GetBytes(value));
|
||||||
Data[1] = 1;
|
}
|
||||||
|
|
||||||
AMemoryHelper.WriteBytes(Context.Memory, Position, Data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.ResponseData.Write(LangCodesCount);
|
Context.ResponseData.Write(LangCodesCount);
|
||||||
|
|
33
Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs
Normal file
33
Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.OsHle.IpcServices.Set
|
||||||
|
{
|
||||||
|
class ServiceSetSys : IIpcService
|
||||||
|
{
|
||||||
|
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||||
|
|
||||||
|
public ServiceSetSys()
|
||||||
|
{
|
||||||
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
|
{
|
||||||
|
{ 23, GetColorSetId },
|
||||||
|
{ 24, SetColorSetId }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long GetColorSetId(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
Context.ResponseData.Write((int)Context.Ns.Settings.ThemeColor);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long SetColorSetId(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs
Normal file
20
Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.OsHle.IpcServices.Sfdnsres
|
||||||
|
{
|
||||||
|
class ServiceSfdnsres : IIpcService
|
||||||
|
{
|
||||||
|
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||||
|
|
||||||
|
public ServiceSfdnsres()
|
||||||
|
{
|
||||||
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
|
{
|
||||||
|
//{ 0, Function }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs
Normal file
20
Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.OsHle.IpcServices.Ssl
|
||||||
|
{
|
||||||
|
class ServiceSsl : IIpcService
|
||||||
|
{
|
||||||
|
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||||
|
|
||||||
|
public ServiceSsl()
|
||||||
|
{
|
||||||
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
|
{
|
||||||
|
//{ 0, Function }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,12 +35,22 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
Acquired
|
Acquired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct Rect
|
||||||
|
{
|
||||||
|
public int Top;
|
||||||
|
public int Left;
|
||||||
|
public int Right;
|
||||||
|
public int Bottom;
|
||||||
|
}
|
||||||
|
|
||||||
private struct BufferEntry
|
private struct BufferEntry
|
||||||
{
|
{
|
||||||
public BufferState State;
|
public BufferState State;
|
||||||
|
|
||||||
public HalTransform Transform;
|
public HalTransform Transform;
|
||||||
|
|
||||||
|
public Rect Crop;
|
||||||
|
|
||||||
public GbpBuffer Data;
|
public GbpBuffer Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +178,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
|
|
||||||
BufferQueue[Slot].Transform = (HalTransform)Transform;
|
BufferQueue[Slot].Transform = (HalTransform)Transform;
|
||||||
|
|
||||||
|
BufferQueue[Slot].Crop.Top = CropTop;
|
||||||
|
BufferQueue[Slot].Crop.Left = CropLeft;
|
||||||
|
BufferQueue[Slot].Crop.Right = CropRight;
|
||||||
|
BufferQueue[Slot].Crop.Bottom = CropBottom;
|
||||||
|
|
||||||
BufferQueue[Slot].State = BufferState.Queued;
|
BufferQueue[Slot].State = BufferState.Queued;
|
||||||
|
|
||||||
SendFrameBuffer(Context, Slot);
|
SendFrameBuffer(Context, Slot);
|
||||||
|
@ -256,25 +271,49 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferQueue[Slot].State = BufferState.Acquired;
|
BufferQueue[Slot].State = BufferState.Acquired;
|
||||||
|
|
||||||
|
Rect Crop = BufferQueue[Slot].Crop;
|
||||||
|
|
||||||
|
int RealWidth = FbWidth;
|
||||||
|
int RealHeight = FbHeight;
|
||||||
|
|
||||||
float ScaleX = 1;
|
float ScaleX = 1;
|
||||||
float ScaleY = 1;
|
float ScaleY = 1;
|
||||||
|
float OffsX = 0;
|
||||||
|
float OffsY = 0;
|
||||||
|
|
||||||
|
if (Crop.Right != 0 &&
|
||||||
|
Crop.Bottom != 0)
|
||||||
|
{
|
||||||
|
RealWidth = Crop.Right - Crop.Left;
|
||||||
|
RealHeight = Crop.Bottom - Crop.Top;
|
||||||
|
|
||||||
|
ScaleX = (float)FbWidth / RealWidth;
|
||||||
|
ScaleY = (float)FbHeight / RealHeight;
|
||||||
|
|
||||||
|
OffsX = -(float)Crop.Left / Crop.Right;
|
||||||
|
OffsY = -(float)Crop.Top / Crop.Bottom;
|
||||||
|
|
||||||
|
OffsX += ScaleX - 1;
|
||||||
|
OffsY += ScaleY - 1;
|
||||||
|
}
|
||||||
|
|
||||||
float Rotate = 0;
|
float Rotate = 0;
|
||||||
|
|
||||||
if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX))
|
if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX))
|
||||||
{
|
{
|
||||||
ScaleX = -1;
|
ScaleX = -ScaleX;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY))
|
if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY))
|
||||||
{
|
{
|
||||||
ScaleY = -1;
|
ScaleY = -ScaleY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BufferQueue[Slot].Transform.HasFlag(HalTransform.Rotate90))
|
if (BufferQueue[Slot].Transform.HasFlag(HalTransform.Rotate90))
|
||||||
{
|
{
|
||||||
Rotate = MathF.PI * 0.5f;
|
Rotate = -MathF.PI * 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte* Fb = (byte*)Context.Ns.Ram + NvMap.Address;
|
byte* Fb = (byte*)Context.Ns.Ram + NvMap.Address;
|
||||||
|
@ -287,6 +326,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
FbHeight,
|
FbHeight,
|
||||||
ScaleX,
|
ScaleX,
|
||||||
ScaleY,
|
ScaleY,
|
||||||
|
OffsX,
|
||||||
|
OffsY,
|
||||||
Rotate);
|
Rotate);
|
||||||
|
|
||||||
BufferQueue[Slot].State = BufferState.Free;
|
BufferQueue[Slot].State = BufferState.Free;
|
||||||
|
|
|
@ -17,6 +17,8 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
private AMemory Memory;
|
private AMemory Memory;
|
||||||
|
|
||||||
private static Random Rng;
|
private static Random Rng;
|
||||||
|
|
||||||
|
private ulong CurrentHeapSize;
|
||||||
|
|
||||||
public SvcHandler(Switch Ns, Process Process)
|
public SvcHandler(Switch Ns, Process Process)
|
||||||
{
|
{
|
||||||
|
@ -25,6 +27,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
{ 0x01, SvcSetHeapSize },
|
{ 0x01, SvcSetHeapSize },
|
||||||
{ 0x03, SvcSetMemoryAttribute },
|
{ 0x03, SvcSetMemoryAttribute },
|
||||||
{ 0x04, SvcMapMemory },
|
{ 0x04, SvcMapMemory },
|
||||||
|
{ 0x05, SvcUnmapMemory },
|
||||||
{ 0x06, SvcQueryMemory },
|
{ 0x06, SvcQueryMemory },
|
||||||
{ 0x07, SvcExitProcess },
|
{ 0x07, SvcExitProcess },
|
||||||
{ 0x08, SvcCreateThread },
|
{ 0x08, SvcCreateThread },
|
||||||
|
|
|
@ -10,10 +10,21 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
{
|
{
|
||||||
uint Size = (uint)ThreadState.X1;
|
uint Size = (uint)ThreadState.X1;
|
||||||
|
|
||||||
Memory.Manager.SetHeapSize(Size, (int)MemoryType.Heap);
|
long Position = MemoryRegions.HeapRegionAddress;
|
||||||
|
|
||||||
|
if (Size > CurrentHeapSize)
|
||||||
|
{
|
||||||
|
Memory.Manager.Map(Position, Size, (int)MemoryType.Heap, AMemoryPerm.RW);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Memory.Manager.Unmap(Position + Size, (long)CurrentHeapSize - Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentHeapSize = Size;
|
||||||
|
|
||||||
ThreadState.X0 = (int)SvcResult.Success;
|
ThreadState.X0 = (int)SvcResult.Success;
|
||||||
ThreadState.X1 = (ulong)Memory.Manager.HeapAddr;
|
ThreadState.X1 = (ulong)Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SvcSetMemoryAttribute(AThreadState ThreadState)
|
private void SvcSetMemoryAttribute(AThreadState ThreadState)
|
||||||
|
@ -42,7 +53,30 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
long Src = (long)ThreadState.X1;
|
long Src = (long)ThreadState.X1;
|
||||||
long Size = (long)ThreadState.X2;
|
long Size = (long)ThreadState.X2;
|
||||||
|
|
||||||
Memory.Manager.MapMirror(Src, Dst, Size, (int)MemoryType.MappedMemory);
|
AMemoryMapInfo SrcInfo = Memory.Manager.GetMapInfo(Src);
|
||||||
|
|
||||||
|
Memory.Manager.Map(Dst, Size, (int)MemoryType.MappedMemory, SrcInfo.Perm);
|
||||||
|
|
||||||
|
Memory.Manager.Reprotect(Src, Size, AMemoryPerm.None);
|
||||||
|
|
||||||
|
Memory.Manager.SetAttrBit(Src, Size, 0);
|
||||||
|
|
||||||
|
ThreadState.X0 = (int)SvcResult.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SvcUnmapMemory(AThreadState ThreadState)
|
||||||
|
{
|
||||||
|
long Dst = (long)ThreadState.X0;
|
||||||
|
long Src = (long)ThreadState.X1;
|
||||||
|
long Size = (long)ThreadState.X2;
|
||||||
|
|
||||||
|
AMemoryMapInfo DstInfo = Memory.Manager.GetMapInfo(Dst);
|
||||||
|
|
||||||
|
Memory.Manager.Unmap(Dst, Size, (int)MemoryType.MappedMemory);
|
||||||
|
|
||||||
|
Memory.Manager.Reprotect(Src, Size, DstInfo.Perm);
|
||||||
|
|
||||||
|
Memory.Manager.ClearAttrBit(Src, Size, 0);
|
||||||
|
|
||||||
ThreadState.X0 = (int)SvcResult.Success;
|
ThreadState.X0 = (int)SvcResult.Success;
|
||||||
}
|
}
|
||||||
|
@ -54,17 +88,22 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
|
|
||||||
AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position);
|
AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position);
|
||||||
|
|
||||||
MemoryInfo Info = new MemoryInfo(MapInfo);
|
if (MapInfo == null)
|
||||||
|
{
|
||||||
|
//TODO: Correct error code.
|
||||||
|
ThreadState.X0 = ulong.MaxValue;
|
||||||
|
|
||||||
Memory.WriteInt64(InfoPtr + 0x00, Info.BaseAddress);
|
return;
|
||||||
Memory.WriteInt64(InfoPtr + 0x08, Info.Size);
|
}
|
||||||
Memory.WriteInt32(InfoPtr + 0x10, Info.MemType);
|
|
||||||
Memory.WriteInt32(InfoPtr + 0x14, Info.MemAttr);
|
|
||||||
Memory.WriteInt32(InfoPtr + 0x18, Info.MemPerm);
|
|
||||||
Memory.WriteInt32(InfoPtr + 0x1c, Info.IpcRefCount);
|
|
||||||
Memory.WriteInt32(InfoPtr + 0x20, Info.DeviceRefCount);
|
|
||||||
Memory.WriteInt32(InfoPtr + 0x24, Info.Padding);
|
|
||||||
|
|
||||||
|
Memory.WriteInt64(InfoPtr + 0x00, MapInfo.Position);
|
||||||
|
Memory.WriteInt64(InfoPtr + 0x08, MapInfo.Size);
|
||||||
|
Memory.WriteInt32(InfoPtr + 0x10, MapInfo.Type);
|
||||||
|
Memory.WriteInt32(InfoPtr + 0x14, MapInfo.Attr);
|
||||||
|
Memory.WriteInt32(InfoPtr + 0x18, (int)MapInfo.Perm);
|
||||||
|
Memory.WriteInt32(InfoPtr + 0x1c, 0);
|
||||||
|
Memory.WriteInt32(InfoPtr + 0x20, 0);
|
||||||
|
Memory.WriteInt32(InfoPtr + 0x24, 0);
|
||||||
//TODO: X1.
|
//TODO: X1.
|
||||||
|
|
||||||
ThreadState.X0 = (int)SvcResult.Success;
|
ThreadState.X0 = (int)SvcResult.Success;
|
||||||
|
@ -82,9 +121,11 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
|
|
||||||
if (SharedMem != null)
|
if (SharedMem != null)
|
||||||
{
|
{
|
||||||
|
AMemoryHelper.FillWithZeros(Memory, Src, (int)Size);
|
||||||
|
|
||||||
SharedMem.AddVirtualPosition(Src);
|
SharedMem.AddVirtualPosition(Src);
|
||||||
|
|
||||||
Memory.Manager.MapPhys(Src, Size, (int)MemoryType.SharedMemory, (AMemoryPerm)Perm);
|
Memory.Manager.Map(Src, Size, (int)MemoryType.SharedMemory, (AMemoryPerm)Perm);
|
||||||
|
|
||||||
ThreadState.X0 = (int)SvcResult.Success;
|
ThreadState.X0 = (int)SvcResult.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,14 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
{
|
{
|
||||||
partial class SvcHandler
|
partial class SvcHandler
|
||||||
{
|
{
|
||||||
private void SvcExitProcess(AThreadState ThreadState) => Ns.Os.ExitProcess(ThreadState.ProcessId);
|
private const int AllowedCpuIdBitmask = 0b1111;
|
||||||
|
|
||||||
|
private const bool EnableProcessDebugging = false;
|
||||||
|
|
||||||
|
private void SvcExitProcess(AThreadState ThreadState)
|
||||||
|
{
|
||||||
|
Ns.Os.ExitProcess(ThreadState.ProcessId);
|
||||||
|
}
|
||||||
|
|
||||||
private void SvcCloseHandle(AThreadState ThreadState)
|
private void SvcCloseHandle(AThreadState ThreadState)
|
||||||
{
|
{
|
||||||
|
@ -162,79 +169,62 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
|
|
||||||
switch (InfoType)
|
switch (InfoType)
|
||||||
{
|
{
|
||||||
case 0: ThreadState.X1 = AllowedCpuIdBitmask(); break;
|
case 0:
|
||||||
case 2: ThreadState.X1 = GetMapRegionBaseAddr(); break;
|
ThreadState.X1 = AllowedCpuIdBitmask;
|
||||||
case 3: ThreadState.X1 = GetMapRegionSize(); break;
|
break;
|
||||||
case 4: ThreadState.X1 = GetHeapRegionBaseAddr(); break;
|
|
||||||
case 5: ThreadState.X1 = GetHeapRegionSize(); break;
|
case 2:
|
||||||
case 6: ThreadState.X1 = GetTotalMem(); break;
|
ThreadState.X1 = MemoryRegions.MapRegionAddress;
|
||||||
case 7: ThreadState.X1 = GetUsedMem(); break;
|
break;
|
||||||
case 8: ThreadState.X1 = IsCurrentProcessBeingDebugged(); break;
|
|
||||||
case 11: ThreadState.X1 = GetRnd64(); break;
|
case 3:
|
||||||
case 12: ThreadState.X1 = GetAddrSpaceBaseAddr(); break;
|
ThreadState.X1 = MemoryRegions.MapRegionSize;
|
||||||
case 13: ThreadState.X1 = GetAddrSpaceSize(); break;
|
break;
|
||||||
case 14: ThreadState.X1 = GetMapRegionBaseAddr(); break;
|
|
||||||
case 15: ThreadState.X1 = GetMapRegionSize(); break;
|
case 4:
|
||||||
|
ThreadState.X1 = MemoryRegions.HeapRegionAddress;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
ThreadState.X1 = CurrentHeapSize;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
ThreadState.X1 = MemoryRegions.TotalMemoryAvailable;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
ThreadState.X1 = MemoryRegions.TotalMemoryUsed + CurrentHeapSize;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
ThreadState.X1 = EnableProcessDebugging ? 1 : 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11:
|
||||||
|
ThreadState.X1 = (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 12:
|
||||||
|
ThreadState.X1 = MemoryRegions.AddrSpaceStart;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 13:
|
||||||
|
ThreadState.X1 = MemoryRegions.AddrSpaceSize;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 14:
|
||||||
|
ThreadState.X1 = MemoryRegions.MapRegionAddress;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 15:
|
||||||
|
ThreadState.X1 = MemoryRegions.MapRegionSize;
|
||||||
|
break;
|
||||||
|
|
||||||
default: throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle} {InfoId}");
|
default: throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle} {InfoId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadState.X0 = (int)SvcResult.Success;
|
ThreadState.X0 = (int)SvcResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ulong AllowedCpuIdBitmask()
|
|
||||||
{
|
|
||||||
return 0xF; //Mephisto value.
|
|
||||||
}
|
|
||||||
|
|
||||||
private ulong GetMapRegionBaseAddr()
|
|
||||||
{
|
|
||||||
return MemoryRegions.MapRegionAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ulong GetMapRegionSize()
|
|
||||||
{
|
|
||||||
return MemoryRegions.MapRegionSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ulong GetHeapRegionBaseAddr()
|
|
||||||
{
|
|
||||||
return MemoryRegions.HeapRegionAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ulong GetHeapRegionSize()
|
|
||||||
{
|
|
||||||
return MemoryRegions.HeapRegionSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ulong GetTotalMem()
|
|
||||||
{
|
|
||||||
return (ulong)Memory.Manager.GetTotalMemorySize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ulong GetUsedMem()
|
|
||||||
{
|
|
||||||
return (ulong)Memory.Manager.GetUsedMemorySize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ulong IsCurrentProcessBeingDebugged()
|
|
||||||
{
|
|
||||||
return (ulong)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ulong GetRnd64()
|
|
||||||
{
|
|
||||||
return (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ulong GetAddrSpaceBaseAddr()
|
|
||||||
{
|
|
||||||
return 0x08000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ulong GetAddrSpaceSize()
|
|
||||||
{
|
|
||||||
return AMemoryMgr.AddrSize - GetAddrSpaceBaseAddr();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
8
Ryujinx.Core/Settings/ColorSet.cs
Normal file
8
Ryujinx.Core/Settings/ColorSet.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ryujinx.Core.Settings
|
||||||
|
{
|
||||||
|
public enum ColorSet
|
||||||
|
{
|
||||||
|
BasicWhite = 0,
|
||||||
|
BasicBlack = 1
|
||||||
|
}
|
||||||
|
}
|
7
Ryujinx.Core/Settings/SetSys.cs
Normal file
7
Ryujinx.Core/Settings/SetSys.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Ryujinx.Core.Settings
|
||||||
|
{
|
||||||
|
public class SetSys
|
||||||
|
{
|
||||||
|
public ColorSet ThemeColor;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
|
using Ryujinx.Core.Input;
|
||||||
using Ryujinx.Core.OsHle;
|
using Ryujinx.Core.OsHle;
|
||||||
|
using Ryujinx.Core.Settings;
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
using System;
|
using System;
|
||||||
|
@ -14,7 +16,9 @@ namespace Ryujinx.Core
|
||||||
internal NsGpu Gpu { get; private set; }
|
internal NsGpu Gpu { get; private set; }
|
||||||
internal Horizon Os { get; private set; }
|
internal Horizon Os { get; private set; }
|
||||||
internal VirtualFs VFs { get; private set; }
|
internal VirtualFs VFs { get; private set; }
|
||||||
internal Hid Hid { get; private set; }
|
|
||||||
|
public Hid Hid { get; private set; }
|
||||||
|
public SetSys Settings { get; private set; }
|
||||||
|
|
||||||
public event EventHandler Finish;
|
public event EventHandler Finish;
|
||||||
|
|
||||||
|
@ -23,9 +27,11 @@ namespace Ryujinx.Core
|
||||||
Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize);
|
Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize);
|
||||||
|
|
||||||
Gpu = new NsGpu(Renderer);
|
Gpu = new NsGpu(Renderer);
|
||||||
Os = new Horizon(this);
|
|
||||||
VFs = new VirtualFs();
|
VFs = new VirtualFs();
|
||||||
Hid = new Hid(this);
|
|
||||||
|
Hid = new Hid(this);
|
||||||
|
Os = new Horizon(this);
|
||||||
|
Settings = new SetSys();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FinalizeAllProcesses()
|
public void FinalizeAllProcesses()
|
||||||
|
@ -43,20 +49,6 @@ namespace Ryujinx.Core
|
||||||
Os.LoadProgram(FileName);
|
Os.LoadProgram(FileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendControllerButtons(HidControllerID ControllerId,
|
|
||||||
HidControllerLayouts Layout,
|
|
||||||
HidControllerKeys Buttons,
|
|
||||||
JoystickPosition LeftJoystick,
|
|
||||||
JoystickPosition RightJoystick)
|
|
||||||
{
|
|
||||||
Hid.SendControllerButtons(ControllerId, Layout, Buttons, LeftJoystick, RightJoystick);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendTouchScreenEntry(HidTouchScreenEntryTouch TouchPoint)
|
|
||||||
{
|
|
||||||
Hid.SendTouchPoint(TouchPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal virtual void OnFinish(EventArgs e)
|
internal virtual void OnFinish(EventArgs e)
|
||||||
{
|
{
|
||||||
Finish?.Invoke(this, e);
|
Finish?.Invoke(this, e);
|
||||||
|
|
|
@ -5,9 +5,9 @@ namespace Ryujinx.Core
|
||||||
{
|
{
|
||||||
class VirtualFs : IDisposable
|
class VirtualFs : IDisposable
|
||||||
{
|
{
|
||||||
private const string BasePath = "Fs";
|
private const string BasePath = "RyuFs";
|
||||||
private const string SavesPath = "Saves";
|
private const string NandPath = "nand";
|
||||||
private const string SdCardPath = "SdCard";
|
private const string SdCardPath = "sdmc";
|
||||||
|
|
||||||
public Stream RomFs { get; private set; }
|
public Stream RomFs { get; private set; }
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ namespace Ryujinx.Core
|
||||||
|
|
||||||
public string GetSdCardPath() => MakeDirAndGetFullPath(SdCardPath);
|
public string GetSdCardPath() => MakeDirAndGetFullPath(SdCardPath);
|
||||||
|
|
||||||
public string GetGameSavesPath() => MakeDirAndGetFullPath(SavesPath);
|
public string GetGameSavesPath() => MakeDirAndGetFullPath(NandPath);
|
||||||
|
|
||||||
private string MakeDirAndGetFullPath(string Dir)
|
private string MakeDirAndGetFullPath(string Dir)
|
||||||
{
|
{
|
||||||
|
@ -56,7 +56,9 @@ namespace Ryujinx.Core
|
||||||
|
|
||||||
public string GetBasePath()
|
public string GetBasePath()
|
||||||
{
|
{
|
||||||
return Path.Combine(Directory.GetCurrentDirectory(), BasePath);
|
string AppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||||
|
|
||||||
|
return Path.Combine(AppDataPath, BasePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
@ -10,9 +10,20 @@ namespace Ryujinx.Graphics.Gal
|
||||||
void InitializeFrameBuffer();
|
void InitializeFrameBuffer();
|
||||||
void Render();
|
void Render();
|
||||||
void SetWindowSize(int Width, int Height);
|
void SetWindowSize(int Width, int Height);
|
||||||
void SetFrameBuffer(byte* Fb, int Width, int Height, float SX, float SY, float R);
|
void SetFrameBuffer(
|
||||||
|
byte* Fb,
|
||||||
|
int Width,
|
||||||
|
int Height,
|
||||||
|
float ScaleX,
|
||||||
|
float ScaleY,
|
||||||
|
float OffsX,
|
||||||
|
float OffsY,
|
||||||
|
float Rotate);
|
||||||
|
|
||||||
void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs);
|
void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs);
|
||||||
|
|
||||||
void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height);
|
void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height);
|
||||||
|
|
||||||
void BindTexture(int Index);
|
void BindTexture(int Index);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
uniform vec2 window_size;
|
|
||||||
uniform mat2 transform;
|
uniform mat2 transform;
|
||||||
|
uniform vec2 window_size;
|
||||||
|
uniform vec2 offset;
|
||||||
|
|
||||||
layout(location = 0) in vec2 in_position;
|
layout(location = 0) in vec2 in_position;
|
||||||
layout(location = 1) in vec2 in_tex_coord;
|
layout(location = 1) in vec2 in_tex_coord;
|
||||||
|
@ -22,5 +23,6 @@ vec2 get_scale_ratio(void) {
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
tex_coord = in_tex_coord;
|
tex_coord = in_tex_coord;
|
||||||
gl_Position = vec4((transform * in_position) * get_scale_ratio(), 0, 1);
|
vec2 t_pos = (transform * in_position) + offset;
|
||||||
|
gl_Position = vec4(t_pos * get_scale_ratio(), 0, 1);
|
||||||
}
|
}
|
|
@ -135,7 +135,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.BindVertexArray(0);
|
GL.BindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void Set(byte* Fb, int Width, int Height, Matrix2 Transform)
|
public unsafe void Set(byte* Fb, int Width, int Height, Matrix2 Transform, Vector2 Offs)
|
||||||
{
|
{
|
||||||
if (Fb == null)
|
if (Fb == null)
|
||||||
{
|
{
|
||||||
|
@ -172,6 +172,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
int WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size");
|
int WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size");
|
||||||
|
|
||||||
GL.Uniform2(WindowSizeUniformLocation, new Vector2(WindowWidth, WindowHeight));
|
GL.Uniform2(WindowSizeUniformLocation, new Vector2(WindowWidth, WindowHeight));
|
||||||
|
|
||||||
|
int OffsetUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "offset");
|
||||||
|
|
||||||
|
GL.Uniform2(OffsetUniformLocation, Offs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Render()
|
public void Render()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
@ -24,7 +25,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
private Texture[] Textures;
|
private Texture[] Textures;
|
||||||
|
|
||||||
private Queue<Action> ActionsQueue;
|
private ConcurrentQueue<Action> ActionsQueue;
|
||||||
|
|
||||||
private FrameBuffer FbRenderer;
|
private FrameBuffer FbRenderer;
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
Textures = new Texture[8];
|
Textures = new Texture[8];
|
||||||
|
|
||||||
ActionsQueue = new Queue<Action>();
|
ActionsQueue = new ConcurrentQueue<Action>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitializeFrameBuffer()
|
public void InitializeFrameBuffer()
|
||||||
|
@ -51,9 +52,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
int Count = ActionsQueue.Count;
|
int Count = ActionsQueue.Count;
|
||||||
|
|
||||||
while (Count-- > 0)
|
while (Count-- > 0 && ActionsQueue.TryDequeue(out Action RenderAction))
|
||||||
{
|
{
|
||||||
ActionsQueue.Dequeue()();
|
RenderAction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +87,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
int Height,
|
int Height,
|
||||||
float ScaleX,
|
float ScaleX,
|
||||||
float ScaleY,
|
float ScaleY,
|
||||||
|
float OffsX,
|
||||||
|
float OffsY,
|
||||||
float Rotate)
|
float Rotate)
|
||||||
{
|
{
|
||||||
Matrix2 Transform;
|
Matrix2 Transform;
|
||||||
|
@ -93,7 +96,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Transform = Matrix2.CreateScale(ScaleX, ScaleY);
|
Transform = Matrix2.CreateScale(ScaleX, ScaleY);
|
||||||
Transform *= Matrix2.CreateRotation(Rotate);
|
Transform *= Matrix2.CreateRotation(Rotate);
|
||||||
|
|
||||||
FbRenderer.Set(Fb, Width, Height, Transform);
|
Vector2 Offs = new Vector2(OffsX, OffsY);
|
||||||
|
|
||||||
|
FbRenderer.Set(Fb, Width, Height, Transform, Offs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs)
|
public void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs)
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
private const int PTLvl1Mask = PTLvl1Size - 1;
|
private const int PTLvl1Mask = PTLvl1Size - 1;
|
||||||
private const int PageMask = PageSize - 1;
|
private const int PageMask = PageSize - 1;
|
||||||
|
|
||||||
private const int PTLvl0Bit = PTPageBits + PTLvl0Bits;
|
private const int PTLvl0Bit = PTPageBits + PTLvl1Bits;
|
||||||
private const int PTLvl1Bit = PTPageBits;
|
private const int PTLvl1Bit = PTPageBits;
|
||||||
|
|
||||||
private const long PteUnmapped = -1;
|
private const long PteUnmapped = -1;
|
||||||
|
|
|
@ -17,7 +17,6 @@ namespace Ryujinx.Tests.Cpu
|
||||||
private long EntryPoint;
|
private long EntryPoint;
|
||||||
|
|
||||||
private IntPtr Ram;
|
private IntPtr Ram;
|
||||||
private AMemoryAlloc Allocator;
|
|
||||||
private AMemory Memory;
|
private AMemory Memory;
|
||||||
private AThread Thread;
|
private AThread Thread;
|
||||||
|
|
||||||
|
@ -31,9 +30,8 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize);
|
Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize);
|
||||||
ATranslator Translator = new ATranslator();
|
ATranslator Translator = new ATranslator();
|
||||||
Allocator = new AMemoryAlloc();
|
Memory = new AMemory(Ram);
|
||||||
Memory = new AMemory(Ram, Allocator);
|
Memory.Manager.Map(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute);
|
||||||
Memory.Manager.MapPhys(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute);
|
|
||||||
Thread = new AThread(Translator, Memory, ThreadPriority.Normal, EntryPoint);
|
Thread = new AThread(Translator, Memory, ThreadPriority.Normal, EntryPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +40,6 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Thread = null;
|
Thread = null;
|
||||||
Memory = null;
|
Memory = null;
|
||||||
Allocator = null;
|
|
||||||
Marshal.FreeHGlobal(Ram);
|
Marshal.FreeHGlobal(Ram);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using OpenTK.Input;
|
||||||
using Ryujinx.Core;
|
using Ryujinx.Core;
|
||||||
|
using Ryujinx.Core.Input;
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
@ -9,6 +11,12 @@ namespace Ryujinx
|
||||||
{
|
{
|
||||||
public class GLScreen : GameWindow
|
public class GLScreen : GameWindow
|
||||||
{
|
{
|
||||||
|
private const int TouchScreenWidth = 1280;
|
||||||
|
private const int TouchScreenHeight = 720;
|
||||||
|
|
||||||
|
private const float TouchScreenRatioX = (float)TouchScreenWidth / TouchScreenHeight;
|
||||||
|
private const float TouchScreenRatioY = (float)TouchScreenHeight / TouchScreenWidth;
|
||||||
|
|
||||||
private Switch Ns;
|
private Switch Ns;
|
||||||
|
|
||||||
private IGalRenderer Renderer;
|
private IGalRenderer Renderer;
|
||||||
|
@ -32,86 +40,124 @@ namespace Ryujinx
|
||||||
|
|
||||||
protected override void OnUpdateFrame(FrameEventArgs e)
|
protected override void OnUpdateFrame(FrameEventArgs e)
|
||||||
{
|
{
|
||||||
HidControllerKeys CurrentButton = 0;
|
HidControllerButtons CurrentButton = 0;
|
||||||
JoystickPosition LeftJoystick;
|
HidJoystickPosition LeftJoystick;
|
||||||
JoystickPosition RightJoystick;
|
HidJoystickPosition RightJoystick;
|
||||||
|
|
||||||
|
if (Keyboard[Key.Escape]) this.Exit();
|
||||||
|
|
||||||
if (Keyboard[OpenTK.Input.Key.Escape]) this.Exit();
|
|
||||||
|
|
||||||
//RightJoystick
|
|
||||||
int LeftJoystickDX = 0;
|
int LeftJoystickDX = 0;
|
||||||
int LeftJoystickDY = 0;
|
int LeftJoystickDY = 0;
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickUp]) LeftJoystickDY = short.MaxValue;
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickDown]) LeftJoystickDY = -short.MaxValue;
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickLeft]) LeftJoystickDX = -short.MaxValue;
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickRight]) LeftJoystickDX = short.MaxValue;
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickButton]) CurrentButton |= HidControllerKeys.KEY_LSTICK;
|
|
||||||
|
|
||||||
//LeftButtons
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadUp]) CurrentButton |= HidControllerKeys.KEY_DUP;
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadDown]) CurrentButton |= HidControllerKeys.KEY_DDOWN;
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadLeft]) CurrentButton |= HidControllerKeys.KEY_DLEFT;
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadRight]) CurrentButton |= HidControllerKeys.KEY_DRIGHT;
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.ButtonMinus]) CurrentButton |= HidControllerKeys.KEY_MINUS;
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.ButtonL]) CurrentButton |= HidControllerKeys.KEY_L;
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.ButtonZL]) CurrentButton |= HidControllerKeys.KEY_ZL;
|
|
||||||
|
|
||||||
//RightJoystick
|
|
||||||
int RightJoystickDX = 0;
|
int RightJoystickDX = 0;
|
||||||
int RightJoystickDY = 0;
|
int RightJoystickDY = 0;
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickUp]) RightJoystickDY = short.MaxValue;
|
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickDown]) RightJoystickDY = -short.MaxValue;
|
//RightJoystick
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickLeft]) RightJoystickDX = -short.MaxValue;
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.StickUp]) LeftJoystickDY = short.MaxValue;
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickRight]) RightJoystickDX = short.MaxValue;
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.StickDown]) LeftJoystickDY = -short.MaxValue;
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickButton]) CurrentButton |= HidControllerKeys.KEY_RSTICK;
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.StickLeft]) LeftJoystickDX = -short.MaxValue;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.StickRight]) LeftJoystickDX = short.MaxValue;
|
||||||
|
|
||||||
|
//LeftButtons
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.StickButton]) CurrentButton |= HidControllerButtons.KEY_LSTICK;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadUp]) CurrentButton |= HidControllerButtons.KEY_DUP;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadDown]) CurrentButton |= HidControllerButtons.KEY_DDOWN;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadLeft]) CurrentButton |= HidControllerButtons.KEY_DLEFT;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadRight]) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonMinus]) CurrentButton |= HidControllerButtons.KEY_MINUS;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonL]) CurrentButton |= HidControllerButtons.KEY_L;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonZL]) CurrentButton |= HidControllerButtons.KEY_ZL;
|
||||||
|
|
||||||
|
//RightJoystick
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickUp]) RightJoystickDY = short.MaxValue;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickDown]) RightJoystickDY = -short.MaxValue;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickLeft]) RightJoystickDX = -short.MaxValue;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickRight]) RightJoystickDX = short.MaxValue;
|
||||||
|
|
||||||
//RightButtons
|
//RightButtons
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonA]) CurrentButton |= HidControllerKeys.KEY_A;
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickButton]) CurrentButton |= HidControllerButtons.KEY_RSTICK;
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonB]) CurrentButton |= HidControllerKeys.KEY_B;
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonA]) CurrentButton |= HidControllerButtons.KEY_A;
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonX]) CurrentButton |= HidControllerKeys.KEY_X;
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonB]) CurrentButton |= HidControllerButtons.KEY_B;
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonY]) CurrentButton |= HidControllerKeys.KEY_Y;
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonX]) CurrentButton |= HidControllerButtons.KEY_X;
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonPlus]) CurrentButton |= HidControllerKeys.KEY_PLUS;
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonY]) CurrentButton |= HidControllerButtons.KEY_Y;
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonR]) CurrentButton |= HidControllerKeys.KEY_R;
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonPlus]) CurrentButton |= HidControllerButtons.KEY_PLUS;
|
||||||
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonZR]) CurrentButton |= HidControllerKeys.KEY_ZR;
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonR]) CurrentButton |= HidControllerButtons.KEY_R;
|
||||||
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonZR]) CurrentButton |= HidControllerButtons.KEY_ZR;
|
||||||
|
|
||||||
LeftJoystick = new JoystickPosition
|
LeftJoystick = new HidJoystickPosition
|
||||||
{
|
{
|
||||||
DX = LeftJoystickDX,
|
DX = LeftJoystickDX,
|
||||||
DY = LeftJoystickDY
|
DY = LeftJoystickDY
|
||||||
};
|
};
|
||||||
|
|
||||||
RightJoystick = new JoystickPosition
|
RightJoystick = new HidJoystickPosition
|
||||||
{
|
{
|
||||||
DX = RightJoystickDX,
|
DX = RightJoystickDX,
|
||||||
DY = RightJoystickDY
|
DY = RightJoystickDY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool HasTouch = false;
|
||||||
|
|
||||||
//Get screen touch position from left mouse click
|
//Get screen touch position from left mouse click
|
||||||
//Opentk always captures mouse events, even if out of focus, so check if window is focused.
|
//OpenTK always captures mouse events, even if out of focus, so check if window is focused.
|
||||||
if (Mouse != null && Focused)
|
if (Focused && Mouse?.GetState().LeftButton == ButtonState.Pressed)
|
||||||
if (Mouse.GetState().LeftButton == OpenTK.Input.ButtonState.Pressed)
|
{
|
||||||
|
int ScrnWidth = Width;
|
||||||
|
int ScrnHeight = Height;
|
||||||
|
|
||||||
|
if (Width > Height * TouchScreenRatioX)
|
||||||
{
|
{
|
||||||
HidTouchScreenEntryTouch CurrentPoint = new HidTouchScreenEntryTouch
|
ScrnWidth = (int)(Height * TouchScreenRatioX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScrnHeight = (int)(Width * TouchScreenRatioY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int StartX = (Width - ScrnWidth) >> 1;
|
||||||
|
int StartY = (Height - ScrnHeight) >> 1;
|
||||||
|
|
||||||
|
int EndX = StartX + ScrnWidth;
|
||||||
|
int EndY = StartY + ScrnHeight;
|
||||||
|
|
||||||
|
if (Mouse.X >= StartX &&
|
||||||
|
Mouse.Y >= StartY &&
|
||||||
|
Mouse.X < EndX &&
|
||||||
|
Mouse.Y < EndY)
|
||||||
|
{
|
||||||
|
int ScrnMouseX = Mouse.X - StartX;
|
||||||
|
int ScrnMouseY = Mouse.Y - StartY;
|
||||||
|
|
||||||
|
int MX = (int)(((float)ScrnMouseX / ScrnWidth) * TouchScreenWidth);
|
||||||
|
int MY = (int)(((float)ScrnMouseY / ScrnHeight) * TouchScreenHeight);
|
||||||
|
|
||||||
|
HidTouchPoint CurrentPoint = new HidTouchPoint
|
||||||
{
|
{
|
||||||
Timestamp = (uint)Environment.TickCount,
|
X = MX,
|
||||||
X = (uint)Mouse.X,
|
Y = MY,
|
||||||
Y = (uint)Mouse.Y,
|
|
||||||
|
|
||||||
//Placeholder values till more data is acquired
|
//Placeholder values till more data is acquired
|
||||||
DiameterX = 10,
|
DiameterX = 10,
|
||||||
DiameterY = 10,
|
DiameterY = 10,
|
||||||
Angle = 90,
|
Angle = 90
|
||||||
|
|
||||||
//Only support single touch
|
|
||||||
TouchIndex = 0,
|
|
||||||
};
|
};
|
||||||
if (Mouse.X > -1 && Mouse.Y > -1)
|
|
||||||
Ns.SendTouchScreenEntry(CurrentPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
//We just need one pair of JoyCon because it's emulate by the keyboard.
|
HasTouch = true;
|
||||||
Ns.SendControllerButtons(HidControllerID.CONTROLLER_HANDHELD, HidControllerLayouts.Main, CurrentButton, LeftJoystick, RightJoystick);
|
|
||||||
|
Ns.Hid.SetTouchPoints(CurrentPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HasTouch)
|
||||||
|
{
|
||||||
|
Ns.Hid.SetTouchPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ns.Hid.SetJoyconButton(
|
||||||
|
HidControllerId.CONTROLLER_HANDHELD,
|
||||||
|
HidControllerLayouts.Main,
|
||||||
|
CurrentButton,
|
||||||
|
LeftJoystick,
|
||||||
|
RightJoystick);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnRenderFrame(FrameEventArgs e)
|
protected override void OnRenderFrame(FrameEventArgs e)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue