Emit CIL directly for more SIMD instructions, add UCVTF (vector, scalar) and UZP2, fix XTN (?)
This commit is contained in:
parent
7c4346685c
commit
7c314eadcf
15 changed files with 674 additions and 1052 deletions
|
@ -168,7 +168,7 @@ namespace ChocolArm64
|
||||||
Set("00011110xx1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg));
|
Set("00011110xx1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg));
|
Set("00011110xx1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg));
|
||||||
Set("0x0011100x1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg));
|
Set("0x0011100x1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x0011111<<xxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Vs, typeof(AOpCodeSimdRegElem));
|
Set("0x0011111<<xxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Ve, typeof(AOpCodeSimdRegElem));
|
||||||
Set("00011110xx100000010000xxxxxxxxxx", AInstEmit.Fmov_S, typeof(AOpCodeSimd));
|
Set("00011110xx100000010000xxxxxxxxxx", AInstEmit.Fmov_S, typeof(AOpCodeSimd));
|
||||||
Set("00011110xx1xxxxxxxx100xxxxxxxxxx", AInstEmit.Fmov_Si, typeof(AOpCodeSimdFmov));
|
Set("00011110xx1xxxxxxxx100xxxxxxxxxx", AInstEmit.Fmov_Si, typeof(AOpCodeSimdFmov));
|
||||||
Set("0xx0111100000xxx111101xxxxxxxxxx", AInstEmit.Fmov_V, typeof(AOpCodeSimdImm));
|
Set("0xx0111100000xxx111101xxxxxxxxxx", AInstEmit.Fmov_V, typeof(AOpCodeSimdImm));
|
||||||
|
@ -179,7 +179,7 @@ namespace ChocolArm64
|
||||||
Set("00011111xx0xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fmsub_S, typeof(AOpCodeSimdReg));
|
Set("00011111xx0xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fmsub_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx1xxxxx000010xxxxxxxxxx", AInstEmit.Fmul_S, typeof(AOpCodeSimdReg));
|
Set("00011110xx1xxxxx000010xxxxxxxxxx", AInstEmit.Fmul_S, typeof(AOpCodeSimdReg));
|
||||||
Set("0x1011100x1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg));
|
Set("0x1011100x1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x0011111<<xxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Vs, typeof(AOpCodeSimdRegElem));
|
Set("0x0011111<<xxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Ve, typeof(AOpCodeSimdRegElem));
|
||||||
Set("00011110xx100001010000xxxxxxxxxx", AInstEmit.Fneg_S, typeof(AOpCodeSimdReg));
|
Set("00011110xx100001010000xxxxxxxxxx", AInstEmit.Fneg_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx1xxxxx100010xxxxxxxxxx", AInstEmit.Fnmul_S, typeof(AOpCodeSimdReg));
|
Set("00011110xx1xxxxx100010xxxxxxxxxx", AInstEmit.Fnmul_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx100110010000xxxxxxxxxx", AInstEmit.Frinta_S, typeof(AOpCodeSimd));
|
Set("00011110xx100110010000xxxxxxxxxx", AInstEmit.Frinta_S, typeof(AOpCodeSimd));
|
||||||
|
@ -243,13 +243,15 @@ namespace ChocolArm64
|
||||||
Set("01101110<<110000001110xxxxxxxxxx", AInstEmit.Uaddlv_V, typeof(AOpCodeSimd));
|
Set("01101110<<110000001110xxxxxxxxxx", AInstEmit.Uaddlv_V, typeof(AOpCodeSimd));
|
||||||
Set("0x101110<<1xxxxx000100xxxxxxxxxx", AInstEmit.Uaddw_V, typeof(AOpCodeSimdReg));
|
Set("0x101110<<1xxxxx000100xxxxxxxxxx", AInstEmit.Uaddw_V, typeof(AOpCodeSimdReg));
|
||||||
Set("x0011110xx100011000000xxxxxxxxxx", AInstEmit.Ucvtf_Gp, typeof(AOpCodeSimdCvt));
|
Set("x0011110xx100011000000xxxxxxxxxx", AInstEmit.Ucvtf_Gp, typeof(AOpCodeSimdCvt));
|
||||||
Set("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimdReg));
|
Set("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_S, typeof(AOpCodeSimd));
|
||||||
|
Set("0x1011100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimd));
|
||||||
Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns));
|
Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns));
|
||||||
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("0x1011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_V, typeof(AOpCodeSimdShImm));
|
Set("0x1011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_V, typeof(AOpCodeSimdShImm));
|
||||||
Set("0x1011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm));
|
Set("0x1011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm));
|
||||||
Set("0x001110xx0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg));
|
Set("0x001110xx0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg));
|
||||||
|
Set("0x001110xx0xxxxx010110xxxxxxxxxx", AInstEmit.Uzp2_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x001110<<100001001010xxxxxxxxxx", AInstEmit.Xtn_V, typeof(AOpCodeSimd));
|
Set("0x001110<<100001001010xxxxxxxxxx", AInstEmit.Xtn_V, typeof(AOpCodeSimd));
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -317,7 +319,7 @@ namespace ChocolArm64
|
||||||
}
|
}
|
||||||
else if (ZCount != 0 && OCount != 0)
|
else if (ZCount != 0 && OCount != 0)
|
||||||
{
|
{
|
||||||
//When both the > and the <, then a value is blacklisted,
|
//When both the > and the < are used, then a value is blacklisted,
|
||||||
//with > indicating 0, and < indicating 1. So, for example, ><<
|
//with > indicating 0, and < indicating 1. So, for example, ><<
|
||||||
//blacklists the pattern 011, but 000, 001, 010, 100, 101,
|
//blacklists the pattern 011, but 000, 001, 010, 100, 101,
|
||||||
//110 and 111 are valid.
|
//110 and 111 are valid.
|
||||||
|
|
|
@ -4,10 +4,10 @@ namespace ChocolArm64.Decoder
|
||||||
{
|
{
|
||||||
class AOpCodeMem : AOpCode
|
class AOpCodeMem : AOpCode
|
||||||
{
|
{
|
||||||
public int Rt { get; protected set; }
|
public int Rt { get; protected set; }
|
||||||
public int Rn { get; protected set; }
|
public int Rn { get; protected set; }
|
||||||
public int Size { get; protected set; }
|
public int Size { get; protected set; }
|
||||||
public bool Extend64 { get; protected set; }
|
public bool Extend64 { get; protected set; }
|
||||||
|
|
||||||
public AOpCodeMem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
public AOpCodeMem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,12 +3,8 @@ using ChocolArm64.State;
|
||||||
|
|
||||||
namespace ChocolArm64.Decoder
|
namespace ChocolArm64.Decoder
|
||||||
{
|
{
|
||||||
class AOpCodeSimdMemMs : AOpCode, IAOpCodeSimd
|
class AOpCodeSimdMemMs : AOpCodeMemReg, IAOpCodeSimd
|
||||||
{
|
{
|
||||||
public int Rt { get; private set; }
|
|
||||||
public int Rn { get; private set; }
|
|
||||||
public int Size { get; private set; }
|
|
||||||
public int Rm { get; private set; }
|
|
||||||
public int Reps { get; private set; }
|
public int Reps { get; private set; }
|
||||||
public int SElems { get; private set; }
|
public int SElems { get; private set; }
|
||||||
public int Elems { get; private set; }
|
public int Elems { get; private set; }
|
||||||
|
@ -29,10 +25,7 @@ namespace ChocolArm64.Decoder
|
||||||
default: Inst = AInst.Undefined; return;
|
default: Inst = AInst.Undefined; return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rt = (OpCode >> 0) & 0x1f;
|
|
||||||
Rn = (OpCode >> 5) & 0x1f;
|
|
||||||
Size = (OpCode >> 10) & 0x3;
|
Size = (OpCode >> 10) & 0x3;
|
||||||
Rm = (OpCode >> 16) & 0x1f;
|
|
||||||
WBack = ((OpCode >> 23) & 0x1) != 0;
|
WBack = ((OpCode >> 23) & 0x1) != 0;
|
||||||
|
|
||||||
bool Q = ((OpCode >> 30) & 1) != 0;
|
bool Q = ((OpCode >> 30) & 1) != 0;
|
||||||
|
|
|
@ -3,12 +3,8 @@ using ChocolArm64.State;
|
||||||
|
|
||||||
namespace ChocolArm64.Decoder
|
namespace ChocolArm64.Decoder
|
||||||
{
|
{
|
||||||
class AOpCodeSimdMemSs : AOpCode, IAOpCodeSimd
|
class AOpCodeSimdMemSs : AOpCodeMemReg, IAOpCodeSimd
|
||||||
{
|
{
|
||||||
public int Rt { get; private set; }
|
|
||||||
public int Rn { get; private set; }
|
|
||||||
public int Size { get; private set; }
|
|
||||||
public int Rm { get; private set; }
|
|
||||||
public int SElems { get; private set; }
|
public int SElems { get; private set; }
|
||||||
public int Index { get; private set; }
|
public int Index { get; private set; }
|
||||||
public bool Replicate { get; private set; }
|
public bool Replicate { get; private set; }
|
||||||
|
@ -91,9 +87,6 @@ namespace ChocolArm64.Decoder
|
||||||
this.SElems = SElems;
|
this.SElems = SElems;
|
||||||
this.Size = Scale;
|
this.Size = Scale;
|
||||||
|
|
||||||
Rt = (OpCode >> 0) & 0x1f;
|
|
||||||
Rn = (OpCode >> 5) & 0x1f;
|
|
||||||
Rm = (OpCode >> 16) & 0x1f;
|
|
||||||
WBack = ((OpCode >> 23) & 0x1) != 0;
|
WBack = ((OpCode >> 23) & 0x1) != 0;
|
||||||
|
|
||||||
RegisterSize = Q != 0
|
RegisterSize = Q != 0
|
||||||
|
|
|
@ -2,17 +2,13 @@ using ChocolArm64.Instruction;
|
||||||
|
|
||||||
namespace ChocolArm64.Decoder
|
namespace ChocolArm64.Decoder
|
||||||
{
|
{
|
||||||
class AOpCodeSimdRegElem : AOpCodeSimd
|
class AOpCodeSimdRegElem : AOpCodeSimdReg
|
||||||
{
|
{
|
||||||
public int Rm { get; private set; }
|
|
||||||
public int Index { get; private set; }
|
public int Index { get; private set; }
|
||||||
|
|
||||||
public AOpCodeSimdRegElem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
public AOpCodeSimdRegElem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||||
{
|
{
|
||||||
Rm = (OpCode >> 16) & 0x1f;
|
if ((Size & 1) != 0)
|
||||||
Size = (OpCode >> 22) & 0x1;
|
|
||||||
|
|
||||||
if (Size != 0)
|
|
||||||
{
|
{
|
||||||
Index = (OpCode >> 11) & 1;
|
Index = (OpCode >> 11) & 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,13 +21,22 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
public static void EmitAddsVCheck(AILEmitterCtx Context)
|
public static void EmitAddsVCheck(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
//V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0
|
//V = (Rd ^ Rn) & (Rd ^ Rm) & ~(Rn ^ Rm) < 0
|
||||||
Context.Emit(OpCodes.Dup);
|
Context.EmitSttmp();
|
||||||
|
Context.EmitLdtmp();
|
||||||
|
Context.EmitLdtmp();
|
||||||
|
|
||||||
EmitDataLoadRn(Context);
|
EmitDataLoadRn(Context);
|
||||||
|
|
||||||
Context.Emit(OpCodes.Xor);
|
Context.Emit(OpCodes.Xor);
|
||||||
|
|
||||||
|
Context.EmitLdtmp();
|
||||||
|
|
||||||
|
EmitDataLoadOper2(Context);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Xor);
|
||||||
|
Context.Emit(OpCodes.And);
|
||||||
|
|
||||||
EmitDataLoadOpers(Context);
|
EmitDataLoadOpers(Context);
|
||||||
|
|
||||||
Context.Emit(OpCodes.Xor);
|
Context.Emit(OpCodes.Xor);
|
||||||
|
@ -47,7 +56,10 @@ namespace ChocolArm64.Instruction
|
||||||
EmitDataLoadOpers(Context);
|
EmitDataLoadOpers(Context);
|
||||||
|
|
||||||
Context.Emit(OpCodes.Clt_Un);
|
Context.Emit(OpCodes.Clt_Un);
|
||||||
Context.Emit(OpCodes.Not);
|
|
||||||
|
Context.EmitLdc_I4(1);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Xor);
|
||||||
|
|
||||||
Context.EmitStflg((int)APState.CBit);
|
Context.EmitStflg((int)APState.CBit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -507,6 +507,32 @@ namespace ChocolArm64.Instruction
|
||||||
Context.EmitStvecsf(Op.Rd);
|
Context.EmitStvecsf(Op.Rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Ucvtf_S(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||||
|
|
||||||
|
Context.EmitLdvecsi(Op.Rn);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Conv_R_Un);
|
||||||
|
|
||||||
|
EmitFloatCast(Context, Op.Size);
|
||||||
|
|
||||||
|
Context.EmitStvecsf(Op.Rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Umov_S(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
|
||||||
|
|
||||||
|
Context.EmitLdvec(Op.Rn);
|
||||||
|
Context.EmitLdc_I4(Op.DstIndex);
|
||||||
|
Context.EmitLdc_I4(Op.Size);
|
||||||
|
|
||||||
|
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec));
|
||||||
|
|
||||||
|
Context.EmitStintzr(Op.Rd);
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitScalarOp(AILEmitterCtx Context, OpCode ILOp)
|
private static void EmitScalarOp(AILEmitterCtx Context, OpCode ILOp)
|
||||||
{
|
{
|
||||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -279,106 +279,7 @@ namespace ChocolArm64.Instruction
|
||||||
return InsertVec(new AVec(), 0, Size, Low + High);
|
return InsertVec(new AVec(), 0, Size, Low + High);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AVec Addp64(AVec LHS, AVec RHS, int Size)
|
public static int CountSetBits8(byte Value)
|
||||||
{
|
|
||||||
return Addp(LHS, RHS, Size, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Addp128(AVec LHS, AVec RHS, int Size)
|
|
||||||
{
|
|
||||||
return Addp(LHS, RHS, Size, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Addp(AVec LHS, AVec RHS, int Size, int Bytes)
|
|
||||||
{
|
|
||||||
AVec Res = new AVec();
|
|
||||||
|
|
||||||
int Elems = Bytes >> Size;
|
|
||||||
int Half = Elems >> 1;
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
int Elem = (Index & (Half - 1)) << 1;
|
|
||||||
|
|
||||||
ulong L = Index < Half
|
|
||||||
? ExtractVec(LHS, Elem + 0, Size)
|
|
||||||
: ExtractVec(RHS, Elem + 0, Size);
|
|
||||||
|
|
||||||
ulong R = Index < Half
|
|
||||||
? ExtractVec(LHS, Elem + 1, Size)
|
|
||||||
: ExtractVec(RHS, Elem + 1, Size);
|
|
||||||
|
|
||||||
Res = InsertVec(Res, Index, Size, L + R);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Bic_Vi64(AVec Res, ulong Imm, int Size)
|
|
||||||
{
|
|
||||||
return Bic_Vi(Res, Imm, Size, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Bic_Vi128(AVec Res, ulong Imm, int Size)
|
|
||||||
{
|
|
||||||
return Bic_Vi(Res, Imm, Size, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Bic_Vi(AVec Res, ulong Imm, int Size, int Bytes)
|
|
||||||
{
|
|
||||||
int Elems = Bytes >> Size;
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
ulong Value = ExtractVec(Res, Index, Size);
|
|
||||||
|
|
||||||
Res = InsertVec(Res, Index, Size, Value & ~Imm);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Cnt64(AVec Vector)
|
|
||||||
{
|
|
||||||
AVec Res = new AVec();
|
|
||||||
|
|
||||||
Res.B0 = (byte)CountSetBits8(Vector.B0);
|
|
||||||
Res.B1 = (byte)CountSetBits8(Vector.B1);
|
|
||||||
Res.B2 = (byte)CountSetBits8(Vector.B2);
|
|
||||||
Res.B3 = (byte)CountSetBits8(Vector.B3);
|
|
||||||
Res.B4 = (byte)CountSetBits8(Vector.B4);
|
|
||||||
Res.B5 = (byte)CountSetBits8(Vector.B5);
|
|
||||||
Res.B6 = (byte)CountSetBits8(Vector.B6);
|
|
||||||
Res.B7 = (byte)CountSetBits8(Vector.B7);
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Cnt128(AVec Vector)
|
|
||||||
{
|
|
||||||
AVec Res = new AVec();
|
|
||||||
|
|
||||||
Res.B0 = (byte)CountSetBits8(Vector.B0);
|
|
||||||
Res.B1 = (byte)CountSetBits8(Vector.B1);
|
|
||||||
Res.B2 = (byte)CountSetBits8(Vector.B2);
|
|
||||||
Res.B3 = (byte)CountSetBits8(Vector.B3);
|
|
||||||
Res.B4 = (byte)CountSetBits8(Vector.B4);
|
|
||||||
Res.B5 = (byte)CountSetBits8(Vector.B5);
|
|
||||||
Res.B6 = (byte)CountSetBits8(Vector.B6);
|
|
||||||
Res.B7 = (byte)CountSetBits8(Vector.B7);
|
|
||||||
Res.B8 = (byte)CountSetBits8(Vector.B8);
|
|
||||||
Res.B9 = (byte)CountSetBits8(Vector.B9);
|
|
||||||
Res.B10 = (byte)CountSetBits8(Vector.B10);
|
|
||||||
Res.B11 = (byte)CountSetBits8(Vector.B11);
|
|
||||||
Res.B12 = (byte)CountSetBits8(Vector.B12);
|
|
||||||
Res.B13 = (byte)CountSetBits8(Vector.B13);
|
|
||||||
Res.B14 = (byte)CountSetBits8(Vector.B14);
|
|
||||||
Res.B15 = (byte)CountSetBits8(Vector.B15);
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int CountSetBits8(byte Value)
|
|
||||||
{
|
{
|
||||||
return (Value >> 0) & 1 + (Value >> 1) & 1 +
|
return (Value >> 0) & 1 + (Value >> 1) & 1 +
|
||||||
(Value >> 2) & 1 + (Value >> 3) & 1 +
|
(Value >> 2) & 1 + (Value >> 3) & 1 +
|
||||||
|
@ -413,248 +314,11 @@ namespace ChocolArm64.Instruction
|
||||||
return InsertVec(new AVec(), 0, Size, ExtractVec(Vector, Elem, Size));
|
return InsertVec(new AVec(), 0, Size, ExtractVec(Vector, Elem, Size));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AVec Dup_V64(AVec Vector, int Elem, int Size)
|
|
||||||
{
|
|
||||||
return Dup_V(Vector, Elem, Size, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Dup_V128(AVec Vector, int Elem, int Size)
|
|
||||||
{
|
|
||||||
return Dup_V(Vector, Elem, Size, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Dup_V(AVec Vector, int Elem, int Size, int Bytes)
|
|
||||||
{
|
|
||||||
AVec Res = new AVec();
|
|
||||||
|
|
||||||
ulong Value = ExtractVec(Vector, Elem, Size);
|
|
||||||
|
|
||||||
for (Elem = 0; Elem < (Bytes >> Size); Elem++)
|
|
||||||
{
|
|
||||||
Res = InsertVec(Res, Elem, Size, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Fmla64(AVec Res, AVec LHS, AVec RHS, int Size)
|
|
||||||
{
|
|
||||||
return Fmla(Res, LHS, RHS, Size, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Fmla128(AVec Res, AVec LHS, AVec RHS, int Size)
|
|
||||||
{
|
|
||||||
return Fmla(Res, LHS, RHS, Size, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Fmla(AVec Res, AVec LHS, AVec RHS, int Size, int Bytes)
|
|
||||||
{
|
|
||||||
int Elems = Bytes >> Size;
|
|
||||||
|
|
||||||
if (Size == 0)
|
|
||||||
{
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
float L = LHS.ExtractSingle(Index);
|
|
||||||
float R = RHS.ExtractSingle(Index);
|
|
||||||
float Addend = Res.ExtractSingle(Index);
|
|
||||||
|
|
||||||
Res = AVec.InsertSingle(Res, Index, Addend + L * R);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
double L = LHS.ExtractDouble(Index);
|
|
||||||
double R = RHS.ExtractDouble(Index);
|
|
||||||
double Addend = Res.ExtractDouble(Index);
|
|
||||||
|
|
||||||
Res = AVec.InsertDouble(Res, Index, Addend + L * R);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Fmla_Ve64(AVec Res, AVec LHS, AVec RHS, int SIdx, int Size)
|
|
||||||
{
|
|
||||||
return Fmla_Ve(Res, LHS, RHS, SIdx, Size, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Fmla_Ve128(AVec Res, AVec LHS, AVec RHS, int SIdx, int Size)
|
|
||||||
{
|
|
||||||
return Fmla_Ve(Res, LHS, RHS, SIdx, Size, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Fmla_Ve(AVec Res, AVec LHS, AVec RHS, int SIdx, int Size, int Bytes)
|
|
||||||
{
|
|
||||||
int Elems = Bytes >> Size;
|
|
||||||
|
|
||||||
if (Size == 0)
|
|
||||||
{
|
|
||||||
float R = RHS.ExtractSingle(SIdx);
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
float L = LHS.ExtractSingle(Index);
|
|
||||||
float Addend = Res.ExtractSingle(Index);
|
|
||||||
|
|
||||||
Res = AVec.InsertSingle(Res, Index, Addend + L * R);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
double R = RHS.ExtractDouble(SIdx);
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
double L = LHS.ExtractDouble(Index);
|
|
||||||
double Addend = Res.ExtractDouble(Index);
|
|
||||||
|
|
||||||
Res = AVec.InsertDouble(Res, Index, Addend + L * R);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Fmov_S(ulong Value, int Elem, int Size)
|
public static AVec Fmov_S(ulong Value, int Elem, int Size)
|
||||||
{
|
{
|
||||||
return InsertVec(new AVec(), Elem, Size, Value);
|
return InsertVec(new AVec(), Elem, Size, Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AVec Fmul_Ve64(AVec LHS, AVec RHS, int SIdx, int Size)
|
|
||||||
{
|
|
||||||
return Fmul_Ve(LHS, RHS, SIdx, Size, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Fmul_Ve128(AVec LHS, AVec RHS, int SIdx, int Size)
|
|
||||||
{
|
|
||||||
return Fmul_Ve(LHS, RHS, SIdx, Size, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Fmul_Ve(AVec LHS, AVec RHS, int SIdx, int Size, int Bytes)
|
|
||||||
{
|
|
||||||
AVec Res = new AVec();
|
|
||||||
|
|
||||||
int Elems = Bytes >> Size;
|
|
||||||
|
|
||||||
if (Size == 0)
|
|
||||||
{
|
|
||||||
float R = RHS.ExtractSingle(SIdx);
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
float L = LHS.ExtractSingle(Index);
|
|
||||||
|
|
||||||
Res = AVec.InsertSingle(Res, Index, L * R);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
double R = RHS.ExtractDouble(SIdx);
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
double L = LHS.ExtractDouble(Index);
|
|
||||||
|
|
||||||
Res = AVec.InsertDouble(Res, Index, L * R);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Ins_Gp(AVec Res, ulong Value, int Elem, int Size)
|
|
||||||
{
|
|
||||||
return InsertVec(Res, Elem, Size, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Ins_V(AVec Res, AVec Value, int Src, int Dst, int Size)
|
|
||||||
{
|
|
||||||
return InsertVec(Res, Dst, Size, ExtractVec(Value, Src, Size));;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Orr_Vi64(AVec Res, ulong Imm, int Size)
|
|
||||||
{
|
|
||||||
return Orr_Vi(Res, Imm, Size, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Orr_Vi128(AVec Res, ulong Imm, int Size)
|
|
||||||
{
|
|
||||||
return Orr_Vi(Res, Imm, Size, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Orr_Vi(AVec Res, ulong Imm, int Size, int Bytes)
|
|
||||||
{
|
|
||||||
int Elems = Bytes >> Size;
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
ulong Value = ExtractVec(Res, Index, Size);
|
|
||||||
|
|
||||||
Res = InsertVec(Res, Index, Size, Value | Imm);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Saddw(AVec LHS, AVec RHS, int Size)
|
|
||||||
{
|
|
||||||
return Saddw_(LHS, RHS, Size, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Saddw2(AVec LHS, AVec RHS, int Size)
|
|
||||||
{
|
|
||||||
return Saddw_(LHS, RHS, Size, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Saddw_(AVec LHS, AVec RHS, int Size, bool High)
|
|
||||||
{
|
|
||||||
AVec Res = new AVec();
|
|
||||||
|
|
||||||
int Elems = 8 >> Size;
|
|
||||||
int Part = High ? Elems : 0;
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
long L = ExtractSVec(LHS, Index, Size + 1);
|
|
||||||
long R = ExtractSVec(RHS, Index + Part, Size);
|
|
||||||
|
|
||||||
Res = InsertSVec(Res, Index, Size + 1, L + R);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Sshll(AVec Vector, int Shift, int Size)
|
|
||||||
{
|
|
||||||
return Sshll_(Vector, Shift, Size, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Sshll2(AVec Vector, int Shift, int Size)
|
|
||||||
{
|
|
||||||
return Sshll_(Vector, Shift, Size, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Sshll_(AVec Vector, int Shift, int Size, bool High)
|
|
||||||
{
|
|
||||||
AVec Res = new AVec();
|
|
||||||
|
|
||||||
int Elems = 8 >> Size;
|
|
||||||
int Part = High ? Elems : 0;
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
long Value = ExtractSVec(Vector, Index + Part, Size);
|
|
||||||
|
|
||||||
Res = InsertSVec(Res, Index, Size + 1, Value << Shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Tbl1_V64(AVec Vector, AVec Tb0)
|
public static AVec Tbl1_V64(AVec Vector, AVec Tb0)
|
||||||
{
|
{
|
||||||
return Tbl(Vector, 8, Tb0);
|
return Tbl(Vector, 8, Tb0);
|
||||||
|
@ -720,173 +384,6 @@ namespace ChocolArm64.Instruction
|
||||||
return Res;
|
return Res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AVec Uaddlv64(AVec Vector, int Size)
|
|
||||||
{
|
|
||||||
return Uaddlv(Vector, Size, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Uaddlv128(AVec Vector, int Size)
|
|
||||||
{
|
|
||||||
return Uaddlv(Vector, Size, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Uaddlv(AVec Vector, int Size, int Bytes)
|
|
||||||
{
|
|
||||||
int Elems = Bytes >> Size;
|
|
||||||
|
|
||||||
ulong Sum = 0;
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
Sum += ExtractVec(Vector, Index, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return InsertVec(new AVec(), 0, 3, Sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Uaddw(AVec LHS, AVec RHS, int Size)
|
|
||||||
{
|
|
||||||
return Uaddw_(LHS, RHS, Size, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Uaddw2(AVec LHS, AVec RHS, int Size)
|
|
||||||
{
|
|
||||||
return Uaddw_(LHS, RHS, Size, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Uaddw_(AVec LHS, AVec RHS, int Size, bool High)
|
|
||||||
{
|
|
||||||
AVec Res = new AVec();
|
|
||||||
|
|
||||||
int Elems = 8 >> Size;
|
|
||||||
int Part = High ? Elems : 0;
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
ulong L = ExtractVec(LHS, Index, Size + 1);
|
|
||||||
ulong R = ExtractVec(RHS, Index + Part, Size);
|
|
||||||
|
|
||||||
Res = InsertVec(Res, Index, Size + 1, L + R);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Ucvtf_V_F(AVec Vector)
|
|
||||||
{
|
|
||||||
return new AVec()
|
|
||||||
{
|
|
||||||
S0 = (uint)Vector.W0,
|
|
||||||
S1 = (uint)Vector.W1,
|
|
||||||
S2 = (uint)Vector.W2,
|
|
||||||
S3 = (uint)Vector.W3
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Ucvtf_V_D(AVec Vector)
|
|
||||||
{
|
|
||||||
return new AVec()
|
|
||||||
{
|
|
||||||
D0 = (ulong)Vector.X0,
|
|
||||||
D1 = (ulong)Vector.X1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Ushll(AVec Vector, int Shift, int Size)
|
|
||||||
{
|
|
||||||
return Ushll_(Vector, Shift, Size, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Ushll2(AVec Vector, int Shift, int Size)
|
|
||||||
{
|
|
||||||
return Ushll_(Vector, Shift, Size, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Ushll_(AVec Vector, int Shift, int Size, bool High)
|
|
||||||
{
|
|
||||||
AVec Res = new AVec();
|
|
||||||
|
|
||||||
int Elems = 8 >> Size;
|
|
||||||
int Part = High ? Elems : 0;
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
ulong Value = ExtractVec(Vector, Index + Part, Size);
|
|
||||||
|
|
||||||
Res = InsertVec(Res, Index, Size + 1, Value << Shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Uzp1_V64(AVec LHS, AVec RHS, int Size)
|
|
||||||
{
|
|
||||||
return Uzp(LHS, RHS, Size, 0, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Uzp1_V128(AVec LHS, AVec RHS, int Size)
|
|
||||||
{
|
|
||||||
return Uzp(LHS, RHS, Size, 0, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Uzp2_V64(AVec LHS, AVec RHS, int Size)
|
|
||||||
{
|
|
||||||
return Uzp(LHS, RHS, Size, 1, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Uzp2_V128(AVec LHS, AVec RHS, int Size)
|
|
||||||
{
|
|
||||||
return Uzp(LHS, RHS, Size, 1, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Uzp(AVec LHS, AVec RHS, int Size, int Part, int Bytes)
|
|
||||||
{
|
|
||||||
AVec Res = new AVec();
|
|
||||||
|
|
||||||
int Elems = Bytes >> Size;
|
|
||||||
int Half = Elems >> 1;
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
int Elem = (Index & (Half - 1)) << 1;
|
|
||||||
|
|
||||||
ulong Value = Index < Half
|
|
||||||
? ExtractVec(LHS, Elem + Part, Size)
|
|
||||||
: ExtractVec(RHS, Elem + Part, Size);
|
|
||||||
|
|
||||||
Res = InsertVec(Res, Index, Size, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Xtn(AVec Vector, int Size)
|
|
||||||
{
|
|
||||||
return Xtn_(Vector, Size, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AVec Xtn2(AVec Vector, int Size)
|
|
||||||
{
|
|
||||||
return Xtn_(Vector, Size, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AVec Xtn_(AVec Vector, int Size, bool High)
|
|
||||||
{
|
|
||||||
AVec Res = new AVec();
|
|
||||||
|
|
||||||
int Elems = 8 >> Size;
|
|
||||||
int Part = High ? Elems : 0;
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Elems; Index++)
|
|
||||||
{
|
|
||||||
ulong Value = ExtractVec(Vector, Index, Size + 1);
|
|
||||||
|
|
||||||
Res = InsertVec(Res, Index + Part, Size, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ulong ExtractVec(AVec Vector, int Index, int Size)
|
public static ulong ExtractVec(AVec Vector, int Index, int Size)
|
||||||
{
|
{
|
||||||
switch (Size)
|
switch (Size)
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace ChocolArm64.Translation
|
||||||
private const int Tmp2Index = -2;
|
private const int Tmp2Index = -2;
|
||||||
private const int Tmp3Index = -3;
|
private const int Tmp3Index = -3;
|
||||||
private const int Tmp4Index = -4;
|
private const int Tmp4Index = -4;
|
||||||
|
private const int Tmp5Index = -5;
|
||||||
|
|
||||||
public AILEmitterCtx(ATranslator Translator, ABlock[] Graph, ABlock Root)
|
public AILEmitterCtx(ATranslator Translator, ABlock[] Graph, ABlock Root)
|
||||||
{
|
{
|
||||||
|
@ -91,7 +92,7 @@ namespace ChocolArm64.Translation
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryOptEmitSubroutineCall()
|
public bool TryOptEmitSubroutineCall()
|
||||||
{
|
{
|
||||||
if (!Translator.TryGetCachedSub(CurrOp, out ATranslatedSub Sub))
|
if (!Translator.TryGetCachedSub(CurrOp, out ATranslatedSub Sub))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -343,6 +344,9 @@ namespace ChocolArm64.Translation
|
||||||
public void EmitLdtmp() => EmitLdint(Tmp1Index);
|
public void EmitLdtmp() => EmitLdint(Tmp1Index);
|
||||||
public void EmitSttmp() => EmitStint(Tmp1Index);
|
public void EmitSttmp() => EmitStint(Tmp1Index);
|
||||||
|
|
||||||
|
public void EmitLdvectmp() => EmitLdvec(Tmp5Index);
|
||||||
|
public void EmitStvectmp() => EmitStvec(Tmp5Index);
|
||||||
|
|
||||||
public void EmitLdint(int Index) => Ldloc(Index, AIoType.Int);
|
public void EmitLdint(int Index) => Ldloc(Index, AIoType.Int);
|
||||||
public void EmitStint(int Index) => Stloc(Index, AIoType.Int);
|
public void EmitStint(int Index) => Stloc(Index, AIoType.Int);
|
||||||
|
|
||||||
|
@ -427,7 +431,8 @@ namespace ChocolArm64.Translation
|
||||||
Size |= 2;
|
Size |= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Op is AOpCodeMem || Op is IAOpCodeLit)
|
if ((Op is AOpCodeMem || Op is IAOpCodeLit) &&
|
||||||
|
!(Op is AOpCodeSimdMemMs || Op is AOpCodeSimdMemSs))
|
||||||
{
|
{
|
||||||
return Size < 4 ? typeof(ulong) : typeof(AVec);
|
return Size < 4 ? typeof(ulong) : typeof(AVec);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.OsHle.Handles;
|
using Ryujinx.OsHle.Handles;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.OsHle
|
namespace Ryujinx.OsHle
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace Ryujinx.OsHle.Objects.Time
|
||||||
{
|
{
|
||||||
DateTime CurrentTime = DateTime.Now;
|
DateTime CurrentTime = DateTime.Now;
|
||||||
|
|
||||||
if (ClockType == SystemClockType.Standard ||
|
if (ClockType == SystemClockType.User ||
|
||||||
ClockType == SystemClockType.Network)
|
ClockType == SystemClockType.Network)
|
||||||
{
|
{
|
||||||
CurrentTime = CurrentTime.ToUniversalTime();
|
CurrentTime = CurrentTime.ToUniversalTime();
|
||||||
|
|
|
@ -2,7 +2,7 @@ namespace Ryujinx.OsHle.Objects.Time
|
||||||
{
|
{
|
||||||
enum SystemClockType
|
enum SystemClockType
|
||||||
{
|
{
|
||||||
Standard,
|
User,
|
||||||
Network,
|
Network,
|
||||||
Local
|
Local
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.OsHle.Services
|
||||||
{
|
{
|
||||||
public static long TimeGetStandardUserSystemClock(ServiceCtx Context)
|
public static long TimeGetStandardUserSystemClock(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
MakeObject(Context, new ISystemClock(SystemClockType.Standard));
|
MakeObject(Context, new ISystemClock(SystemClockType.User));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using ChocolArm64;
|
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using Ryujinx.OsHle.Handles;
|
using Ryujinx.OsHle.Handles;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue